Merge pull request #14040 from eileenmcnaughton/import
[civicrm-core.git] / Civi / Test / Api3TestTrait.php
CommitLineData
30f5345c
TO
1<?php
2
3namespace Civi\Test;
4
5/**
6 * Class Api3TestTrait
7 * @package Civi\Test
8 *
9 * This trait defines a number of helper functions for testing APIv3. Commonly
10 * used helpers include `callAPISuccess()`, `callAPIFailure()`,
11 * `assertAPISuccess()`, and `assertAPIFailure()`.
12 *
13 * This trait is intended for use with PHPUnit-based test cases.
14 */
15trait Api3TestTrait {
16
17 /**
18 * Api version - easier to override than just a define
34f3bbd9 19 * @var int
30f5345c
TO
20 */
21 protected $_apiversion = 3;
22
23 /**
24 * Check that api returned 'is_error' => 1
25 * else provide full message
26 * @param array $result
27 * @param $expected
28 * @param array $valuesToExclude
29 * @param string $prefix
30 * Extra test to add to message.
31 */
c64f69d9
CW
32 public function assertAPIArrayComparison($result, $expected, $valuesToExclude = [], $prefix = '') {
33 $valuesToExclude = array_merge($valuesToExclude, ['debug', 'xdebug', 'sequential']);
30f5345c
TO
34 foreach ($valuesToExclude as $value) {
35 if (isset($result[$value])) {
36 unset($result[$value]);
37 }
38 if (isset($expected[$value])) {
39 unset($expected[$value]);
40 }
41 }
42 $this->assertEquals($result, $expected, "api result array comparison failed " . $prefix . print_r($result, TRUE) . ' was compared to ' . print_r($expected, TRUE));
43 }
44
45 /**
46 * Check that a deleted item has been deleted.
47 *
48 * @param $entity
49 * @param $id
50 */
51 public function assertAPIDeleted($entity, $id) {
c64f69d9 52 $this->callAPISuccess($entity, 'getcount', ['id' => $id], 0);
30f5345c
TO
53 }
54
55 /**
56 * Check that api returned 'is_error' => 1.
57 *
58 * @param array $apiResult
59 * Api result.
60 * @param string $prefix
61 * Extra test to add to message.
62 * @param null $expectedError
63 */
64 public function assertAPIFailure($apiResult, $prefix = '', $expectedError = NULL) {
65 if (!empty($prefix)) {
66 $prefix .= ': ';
67 }
68 if ($expectedError && !empty($apiResult['is_error'])) {
69 $this->assertEquals($expectedError, $apiResult['error_message'], 'api error message not as expected' . $prefix);
70 }
71 $this->assertEquals(1, $apiResult['is_error'], "api call should have failed but it succeeded " . $prefix . (print_r($apiResult, TRUE)));
72 $this->assertNotEmpty($apiResult['error_message']);
73 }
74
75 /**
76 * Check that api returned 'is_error' => 0.
77 *
78 * @param array $apiResult
79 * Api result.
80 * @param string $prefix
81 * Extra test to add to message.
82 */
83 public function assertAPISuccess($apiResult, $prefix = '') {
84 if (!empty($prefix)) {
85 $prefix .= ': ';
86 }
87 $errorMessage = empty($apiResult['error_message']) ? '' : " " . $apiResult['error_message'];
88
89 if (!empty($apiResult['debug_information'])) {
90 $errorMessage .= "\n " . print_r($apiResult['debug_information'], TRUE);
91 }
92 if (!empty($apiResult['trace'])) {
93 $errorMessage .= "\n" . print_r($apiResult['trace'], TRUE);
94 }
95 $this->assertEquals(0, $apiResult['is_error'], $prefix . $errorMessage);
96 }
97
98 /**
99 * This function exists to wrap api functions.
100 * so we can ensure they fail where expected & throw exceptions without litterering the test with checks
101 * @param string $entity
102 * @param string $action
103 * @param array $params
104 * @param string $expectedErrorMessage
105 * Error.
106 * @param null $extraOutput
107 * @return array|int
108 */
109 public function callAPIFailure($entity, $action, $params, $expectedErrorMessage = NULL, $extraOutput = NULL) {
110 if (is_array($params)) {
c64f69d9 111 $params += [
30f5345c 112 'version' => $this->_apiversion,
c64f69d9 113 ];
30f5345c
TO
114 }
115 $result = $this->civicrm_api($entity, $action, $params);
116 $this->assertAPIFailure($result, "We expected a failure for $entity $action but got a success", $expectedErrorMessage);
117 return $result;
118 }
119
120 /**
121 * wrap api functions.
122 * so we can ensure they succeed & throw exceptions without litterering the test with checks
123 *
124 * @param string $entity
125 * @param string $action
126 * @param array $params
127 * @param mixed $checkAgainst
128 * Optional value to check result against, implemented for getvalue,.
129 * getcount, getsingle. Note that for getvalue the type is checked rather than the value
130 * for getsingle the array is compared against an array passed in - the id is not compared (for
131 * better or worse )
132 *
133 * @return array|int
134 */
135 public function callAPISuccess($entity, $action, $params, $checkAgainst = NULL) {
c64f69d9 136 $params = array_merge([
30f5345c
TO
137 'version' => $this->_apiversion,
138 'debug' => 1,
c64f69d9 139 ],
30f5345c
TO
140 $params
141 );
142 switch (strtolower($action)) {
143 case 'getvalue':
144 return $this->callAPISuccessGetValue($entity, $params, $checkAgainst);
145
146 case 'getsingle':
147 return $this->callAPISuccessGetSingle($entity, $params, $checkAgainst);
148
149 case 'getcount':
150 return $this->callAPISuccessGetCount($entity, $params, $checkAgainst);
151 }
152 $result = $this->civicrm_api($entity, $action, $params);
153 $this->assertAPISuccess($result, "Failure in api call for $entity $action");
154 return $result;
155 }
156
157 /**
158 * This function exists to wrap api getValue function & check the result
159 * so we can ensure they succeed & throw exceptions without litterering the test with checks
160 * There is a type check in this
161 * @param string $entity
162 * @param array $params
163 * @param null $count
669fc25e 164 * @throws \Exception
30f5345c
TO
165 * @return array|int
166 */
167 public function callAPISuccessGetCount($entity, $params, $count = NULL) {
c64f69d9 168 $params += [
30f5345c
TO
169 'version' => $this->_apiversion,
170 'debug' => 1,
c64f69d9 171 ];
30f5345c
TO
172 $result = $this->civicrm_api($entity, 'getcount', $params);
173 if (!is_int($result) || !empty($result['is_error']) || isset($result['values'])) {
669fc25e 174 throw new \Exception('Invalid getcount result : ' . print_r($result, TRUE) . " type :" . gettype($result));
30f5345c
TO
175 }
176 if (is_int($count)) {
177 $this->assertEquals($count, $result, "incorrect count returned from $entity getcount");
178 }
179 return $result;
180 }
181
182 /**
183 * This function exists to wrap api getsingle function & check the result
184 * so we can ensure they succeed & throw exceptions without litterering the test with checks
185 *
186 * @param string $entity
187 * @param array $params
188 * @param array $checkAgainst
189 * Array to compare result against.
190 * - boolean
191 * - integer
192 * - double
193 * - string
194 * - array
195 * - object
196 *
669fc25e 197 * @throws \Exception
30f5345c
TO
198 * @return array|int
199 */
200 public function callAPISuccessGetSingle($entity, $params, $checkAgainst = NULL) {
c64f69d9 201 $params += [
30f5345c 202 'version' => $this->_apiversion,
c64f69d9 203 ];
30f5345c
TO
204 $result = $this->civicrm_api($entity, 'getsingle', $params);
205 if (!is_array($result) || !empty($result['is_error']) || isset($result['values'])) {
cb4e7d31 206 $unfilteredResult = $this->civicrm_api($entity, 'get', $params);
207 throw new \Exception(
208 'Invalid getsingle result' . print_r($result, TRUE)
209 . "\n entity: $entity . \n params \n " . print_r($params, TRUE)
34f3bbd9 210 . "\n entities retrieved with blank params \n" . print_r($unfilteredResult, TRUE)
cb4e7d31 211 );
30f5345c
TO
212 }
213 if ($checkAgainst) {
214 // @todo - have gone with the fn that unsets id? should we check id?
215 $this->checkArrayEquals($result, $checkAgainst);
216 }
217 return $result;
218 }
219
220 /**
221 * This function exists to wrap api getValue function & check the result
222 * so we can ensure they succeed & throw exceptions without litterering the test with checks
223 * There is a type check in this
224 *
225 * @param string $entity
226 * @param array $params
227 * @param string $type
228 * Per http://php.net/manual/en/function.gettype.php possible types.
229 * - boolean
230 * - integer
231 * - double
232 * - string
233 * - array
234 * - object
235 *
236 * @return array|int
237 */
238 public function callAPISuccessGetValue($entity, $params, $type = NULL) {
c64f69d9 239 $params += [
30f5345c
TO
240 'version' => $this->_apiversion,
241 'debug' => 1,
c64f69d9 242 ];
30f5345c 243 $result = $this->civicrm_api($entity, 'getvalue', $params);
1bf00882
PN
244 if (is_array($result) && (!empty($result['is_error']) || isset($result['values']))) {
245 throw new \Exception('Invalid getvalue result' . print_r($result, TRUE));
246 }
30f5345c
TO
247 if ($type) {
248 if ($type == 'integer') {
249 // api seems to return integers as strings
250 $this->assertTrue(is_numeric($result), "expected a numeric value but got " . print_r($result, 1));
251 }
252 else {
253 $this->assertType($type, $result, "returned result should have been of type $type but was ");
254 }
255 }
256 return $result;
257 }
258
259 /**
260 * A stub for the API interface. This can be overriden by subclasses to change how the API is called.
261 *
262 * @param $entity
263 * @param $action
264 * @param array $params
265 * @return array|int
266 */
267 public function civicrm_api($entity, $action, $params) {
268 return civicrm_api($entity, $action, $params);
269 }
270
271}