-
-
Notifications
You must be signed in to change notification settings - Fork 825
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CiviUnitTestCase - Extract Civi\Test\Api3DocTrait
This makes `CiviUnitTestCase` more readable, and it allows other tests to benefit from these helpers (even if they don't use everything from `CiviUnitTestCase`).
- Loading branch information
Showing
2 changed files
with
210 additions
and
186 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
<?php | ||
|
||
namespace Civi\Test; | ||
|
||
/** | ||
* Class Api3DocTrait | ||
* @package Civi\Test | ||
* | ||
* This trait defines helper functions for testing and documenting APIv3. In | ||
* particular, it supports a workflow that links a unit-test file to an | ||
* example data file: | ||
* | ||
* - When defining a new API, write a unit test for it. | ||
* - As part of the unit test, use `callAPIAndDocument($entity, $action, ...)`. | ||
* - When the test executes, the inputs and outputs are logged to an example file. | ||
* - You can commit this file to git. | ||
* - Whenever the inputs/output change, they'll be visible in SCM/git because | ||
* the example file also changes. | ||
* | ||
* This trait is intended for use with PHPUnit-based test cases. | ||
*/ | ||
trait Api3DocTrait { | ||
use Api3TestTrait; | ||
|
||
/** | ||
* This function exists to wrap api functions. | ||
* so we can ensure they succeed, generate and example & throw exceptions without litterering the test with checks | ||
* | ||
* @param string $entity | ||
* @param string $action | ||
* @param array $params | ||
* @param string $function | ||
* Pass this in to create a generated example. | ||
* @param string $file | ||
* Pass this in to create a generated example. | ||
* @param string $description | ||
* @param string|null $exampleName | ||
* | ||
* @return array|int | ||
*/ | ||
public function callAPIAndDocument($entity, $action, $params, $function, $file, $description = "", $exampleName = NULL) { | ||
$params['version'] = $this->_apiversion; | ||
$result = $this->callAPISuccess($entity, $action, $params); | ||
$this->documentMe($entity, $action, $params, $result, $function, $file, $description, $exampleName); | ||
return $result; | ||
} | ||
|
||
/** | ||
* Create test generated example in api/v3/examples. | ||
* | ||
* To turn this off (e.g. on the server) set | ||
* define(DONT_DOCUMENT_TEST_CONFIG ,1); | ||
* in your settings file | ||
* | ||
* @param string $entity | ||
* @param string $action | ||
* @param array $params | ||
* Array as passed to civicrm_api function. | ||
* @param array $result | ||
* Array as received from the civicrm_api function. | ||
* @param string $testFunction | ||
* Calling function - generally __FUNCTION__. | ||
* @param string $testFile | ||
* Called from file - generally __FILE__. | ||
* @param string $description | ||
* Descriptive text for the example file. | ||
* @param string $exampleName | ||
* Name for this example file (CamelCase) - if omitted the action name will be substituted. | ||
*/ | ||
private function documentMe($entity, $action, $params, $result, $testFunction, $testFile, $description = "", $exampleName = NULL) { | ||
if (defined('DONT_DOCUMENT_TEST_CONFIG') && DONT_DOCUMENT_TEST_CONFIG) { | ||
return; | ||
} | ||
$entity = _civicrm_api_get_camel_name($entity); | ||
$action = strtolower($action); | ||
|
||
if (empty($exampleName)) { | ||
// Attempt to convert lowercase action name to CamelCase. | ||
// This is clunky/imperfect due to the convention of all lowercase actions. | ||
$exampleName = CRM_Utils_String::convertStringToCamel($action); | ||
$knownPrefixes = array( | ||
'Get', | ||
'Set', | ||
'Create', | ||
'Update', | ||
'Send', | ||
); | ||
foreach ($knownPrefixes as $prefix) { | ||
if (strpos($exampleName, $prefix) === 0 && $prefix != $exampleName) { | ||
$exampleName[strlen($prefix)] = strtoupper($exampleName[strlen($prefix)]); | ||
} | ||
} | ||
} | ||
|
||
$this->tidyExampleResult($result); | ||
if (isset($params['version'])) { | ||
unset($params['version']); | ||
} | ||
// Format multiline description as array | ||
$desc = array(); | ||
if (is_string($description) && strlen($description)) { | ||
foreach (explode("\n", $description) as $line) { | ||
$desc[] = trim($line); | ||
} | ||
} | ||
$smarty = CRM_Core_Smarty::singleton(); | ||
$smarty->assign('testFunction', $testFunction); | ||
$smarty->assign('function', _civicrm_api_get_entity_name_from_camel($entity) . "_$action"); | ||
foreach ($params as $index => $param) { | ||
if (is_string($param)) { | ||
$params[$index] = addslashes($param); | ||
} | ||
} | ||
$smarty->assign('params', $params); | ||
$smarty->assign('entity', $entity); | ||
$smarty->assign('testFile', basename($testFile)); | ||
$smarty->assign('description', $desc); | ||
$smarty->assign('result', $result); | ||
$smarty->assign('action', $action); | ||
|
||
global $civicrm_root; | ||
if (file_exists($civicrm_root . '/tests/templates/documentFunction.tpl')) { | ||
if (!is_dir($civicrm_root . "/api/v3/examples/$entity")) { | ||
mkdir($civicrm_root . "/api/v3/examples/$entity"); | ||
} | ||
$f = fopen($civicrm_root . "/api/v3/examples/$entity/$exampleName.php", "w+b"); | ||
fwrite($f, $smarty->fetch($civicrm_root . '/tests/templates/documentFunction.tpl')); | ||
fclose($f); | ||
} | ||
} | ||
|
||
/** | ||
* Tidy up examples array so that fields that change often ..don't | ||
* and debug related fields are unset | ||
* | ||
* @param array $result | ||
*/ | ||
public function tidyExampleResult(&$result) { | ||
if (!is_array($result)) { | ||
return; | ||
} | ||
$fieldsToChange = array( | ||
'hash' => '67eac7789eaee00', | ||
'modified_date' => '2012-11-14 16:02:35', | ||
'created_date' => '2013-07-28 08:49:19', | ||
'create_date' => '20120130621222105', | ||
'application_received_date' => '20130728084957', | ||
'in_date' => '2013-07-28 08:50:19', | ||
'scheduled_date' => '20130728085413', | ||
'approval_date' => '20130728085413', | ||
'pledge_start_date_high' => '20130726090416', | ||
'start_date' => '2013-07-29 00:00:00', | ||
'event_start_date' => '2013-07-29 00:00:00', | ||
'end_date' => '2013-08-04 00:00:00', | ||
'event_end_date' => '2013-08-04 00:00:00', | ||
'decision_date' => '20130805000000', | ||
); | ||
|
||
$keysToUnset = array('xdebug', 'undefined_fields'); | ||
foreach ($keysToUnset as $unwantedKey) { | ||
if (isset($result[$unwantedKey])) { | ||
unset($result[$unwantedKey]); | ||
} | ||
} | ||
if (isset($result['values'])) { | ||
if (!is_array($result['values'])) { | ||
return; | ||
} | ||
$resultArray = &$result['values']; | ||
} | ||
elseif (is_array($result)) { | ||
$resultArray = &$result; | ||
} | ||
else { | ||
return; | ||
} | ||
|
||
foreach ($resultArray as $index => &$values) { | ||
if (!is_array($values)) { | ||
continue; | ||
} | ||
foreach ($values as $key => &$value) { | ||
if (substr($key, 0, 3) == 'api' && is_array($value)) { | ||
if (isset($value['is_error'])) { | ||
// we have a std nested result format | ||
$this->tidyExampleResult($value); | ||
} | ||
else { | ||
foreach ($value as &$nestedResult) { | ||
// this is an alternative syntax for nested results a keyed array of results | ||
$this->tidyExampleResult($nestedResult); | ||
} | ||
} | ||
} | ||
if (in_array($key, $keysToUnset)) { | ||
unset($values[$key]); | ||
break; | ||
} | ||
if (array_key_exists($key, $fieldsToChange) && !empty($value)) { | ||
$value = $fieldsToChange[$key]; | ||
} | ||
if (is_string($value)) { | ||
$value = addslashes($value); | ||
} | ||
} | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.