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