Merge pull request #1216 from davecivicrm/CRM-13062
[civicrm-core.git] / tests / phpunit / api / v3 / SyntaxConformanceTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 require_once 'CiviTest/CiviUnitTestCase.php';
29
30
31 /**
32 * Test APIv3 civicrm_sytanc conformance* functions
33 *
34 * @package CiviCRM_APIv3
35 * @subpackage API_Core
36 */
37
38 class api_v3_SyntaxConformanceTest extends CiviUnitTestCase {
39 protected $_apiversion = 3;
40
41 /**
42 * @var array e.g. $this->deletes['CRM_Contact_DAO_Contact'][] = $contactID;
43 */
44 protected $deletableTestObjects;
45
46 /** This test case doesn't require DB reset */
47 public $DBResetRequired = FALSE;
48 public $_eNoticeCompliant = FALSE;
49 /* they are two types of missing APIs:
50 - Those that are to be implemented
51 (in some future version when someone steps in -hint hint-). List the entities in toBeImplemented[ {$action} ]
52 Those that don't exist
53 and that will never exist (eg an obsoleted Entity
54 they need to be returned by the function toBeSkipped_{$action} (because it has to be a static method and therefore couldn't access a this->toBeSkipped)
55 */
56 function setUp() {
57 parent::setUp();
58
59 $this->toBeImplemented['get'] = array('Profile', 'CustomValue', 'Constant', 'CustomSearch', 'Extension', 'ReportTemplate', 'System', 'Setting');
60 $this->toBeImplemented['create'] = array('SurveyRespondant', 'OptionGroup', 'MailingRecipients', 'UFMatch', 'LocationType', 'CustomSearch', 'Extension', 'ReportTemplate', 'System');
61 $this->toBeImplemented['delete'] = array('MembershipPayment', 'OptionGroup', 'SurveyRespondant', 'UFJoin', 'UFMatch', 'Extension', 'LocationType', 'System');
62 $this->onlyIDNonZeroCount['get'] = array('ActivityType', 'Entity', 'Domain','Setting');
63 $this->deprecatedAPI = array('Location', 'ActivityType', 'SurveyRespondant');
64 $this->deletableTestObjects = array();
65 }
66
67 function tearDown() {
68 foreach ($this->deletableTestObjects as $entityName => $entities) {
69 foreach ($entities as $entityID) {
70 CRM_Core_DAO::deleteTestObjects($entityName, array('id' => $entityID));
71 }
72 }
73 }
74
75
76 public static function entities($skip = NULL) {
77 // uncomment to make a quicker run when adding a test
78 //return array(array ('Tag'), array ('Activity') );
79 $tmp = civicrm_api('Entity', 'Get', array('version' => 3));
80 if (!is_array($skip)) {
81 $skip = array();
82 }
83 $tmp = array_diff($tmp['values'], $skip);
84 $entities = array();
85 foreach ($tmp as $e) {
86 $entities[] = array($e);
87 }
88 return $entities;
89 }
90
91 public static function entities_get() {
92 // all the entities, beside the ones flagged
93 return api_v3_SyntaxConformanceTest::entities(api_v3_SyntaxConformanceTest::toBeSkipped_get(TRUE));
94 }
95
96 public static function entities_create() {
97 return api_v3_SyntaxConformanceTest::entities(api_v3_SyntaxConformanceTest::toBeSkipped_create(TRUE));
98 }
99
100 public static function entities_updatesingle() {
101 return api_v3_SyntaxConformanceTest::entities(api_v3_SyntaxConformanceTest::toBeSkipped_updatesingle(TRUE));
102 }
103
104 public static function entities_delete() {
105 return api_v3_SyntaxConformanceTest::entities(api_v3_SyntaxConformanceTest::toBeSkipped_delete(TRUE));
106 }
107
108 public static function toBeSkipped_get($sequential = FALSE) {
109 $entitiesWithoutGet = array('MailingEventSubscribe', 'MailingEventConfirm', 'MailingEventResubscribe', 'MailingEventUnsubscribe', 'MailingGroup', 'Location');
110 if ($sequential === TRUE) {
111 return $entitiesWithoutGet;
112 }
113 $entities = array();
114 foreach ($entitiesWithoutGet as $e) {
115 $entities[] = array($e);
116 }
117 return $entities;
118 }
119 /**
120 * Mailing Contact Just doesn't support id. We have always insisted on finding a way to
121 * support id in API but in this case the underlying tables are crying out for a restructue
122 * & it just doesn't make sense
123 * @param unknown_type $sequential
124 * @return multitype:string |multitype:multitype:string
125 */
126 public static function toBeSkipped_getByID($sequential = FALSE) {
127 return array('MailingContact');
128 }
129
130 public static function toBeSkipped_create($sequential = FALSE) {
131 $entitiesWithoutCreate = array('MailingGroup', 'Constant', 'Entity', 'Location', 'Profile', 'MailingRecipients');
132 if ($sequential === TRUE) {
133 return $entitiesWithoutCreate;
134 }
135 $entities = array();
136 foreach ($entitiesWithoutCreate as $e) {
137 $entities[] = array($e);
138 }
139 return $entities;
140 }
141
142 public static function toBeSkipped_delete($sequential = FALSE) {
143 $entitiesWithout = array('MailingGroup', 'Constant', 'Entity', 'Location', 'Domain', 'Profile', 'CustomValue');
144 if ($sequential === TRUE) {
145 return $entitiesWithout;
146 }
147 $entities = array();
148 foreach ($entitiesWithout as $e) {
149 $entities[] = array($e);
150 }
151 return $entities;
152 }
153 /**
154 * Generate list of entities to test for get by id functions
155 * @param boolean $sequential
156 * @return multitype:string |multitype:multitype:string
157 */
158 public static function toBeSkipped_automock($sequential = FALSE) {
159 $entitiesWithoutGet = array('MailingContact', 'EntityTag', 'Participant', 'ParticipantPayment', 'Setting', 'SurveyRespondant', 'MailingRecipients', 'CustomSearch', 'Extension', 'ReportTemplate', 'System');
160 if ($sequential === TRUE) {
161 return $entitiesWithoutGet;
162 }
163 $entities = array();
164 foreach ($entitiesWithoutGet as $e) {
165 $entities[] = array($e);
166 }
167 return $entities;
168 }
169
170
171 /*
172 * At this stage exclude the ones that don't pass & add them as we can troubleshoot them
173 */
174
175 public static function toBeSkipped_updatesingle($sequential = FALSE) {
176 $entitiesWithout = array(
177 'Mailing',
178 'MailingGroup',
179 'MailingJob',
180 'Address',
181 'MailingEventUnsubscribe',
182 'MailingEventSubscribe',
183 'Constant',
184 'Entity',
185 'Location',
186 'Domain',
187 'Profile',
188 'CustomValue',
189 'SurveyRespondant',
190 'Tag',
191 'UFMatch',
192 'UFJoin',
193 'UFField',
194 'OptionValue',
195 'Relationship',
196 'RelationshipType',
197 'ParticipantStatusType',
198 'Note',
199 'OptionGroup',
200 'Membership',
201 'MembershipType',
202 'MembershipStatus',
203 'Group',
204 'GroupOrganization',
205 'GroupNesting',
206 'Job',
207 'File',
208 'EntityTag',
209 'CustomField',
210 'CustomGroup',
211 'Contribution',
212 'ContributionRecur',
213 'ActivityType',
214 'MailingEventConfirm',
215 'Case',
216 'Contact',
217 'ContactType',
218 'MailingEventResubscribe',
219 'UFGroup',
220 'Activity',
221 'Email',
222 'Event',
223 'GroupContact',
224 'MembershipPayment',
225 'Participant',
226 'ParticipantPayment',
227 'LineItem',
228 'PriceSet',
229 'PriceField',
230 'PriceFieldValue',
231 'PledgePayment',
232 'ContributionPage',
233 'Phone',
234 'PaymentProcessor',
235 'MailSettings',
236 'Setting',
237 'MailingContact',
238 );
239 if ($sequential === TRUE) {
240 return $entitiesWithout;
241 }
242 $entities = array();
243 foreach ($entitiesWithout as $e) {
244 $entities[] = array(
245 $e,
246 );
247 }
248 return array('pledge');
249 return $entities;
250 }
251
252 public function getKnownUnworkablesUpdateSingle($entity, $key){
253 // can't update values are values for which updates don't result in the value being changed
254 $knownFailures = array(
255 'Address' => array(
256 'cant_update' => array(
257 'state_province_id', //issues with country id - need to ensure same country
258 'master_id',//creates relationship
259 ),
260 'cant_return' => array(
261 )
262 ),
263 'Pledge' => array(
264 'cant_update' => array(
265 'pledge_original_installment_amount',
266 'installments',
267 'original_installment_amount',
268 'next_pay_date',
269 'amount' // can't be changed through API
270 ),
271 'break_return' => array(// if these are passed in they are retrieved from the wrong table
272 'honor_contact_id',
273 'cancel_date',
274 'contribution_page_id',
275 'financial_account_id',
276 'financial_type_id',
277 'currency'
278 ),
279 'cant_return' => array(// can't be retrieved from api
280 'honor_type_id', //due to uniquename missing
281 'end_date',
282 'modified_date',
283 'acknowledge_date',
284 'start_date',
285 'frequency_day',
286 'currency',
287 'max_reminders',
288 'initial_reminder_day',
289 'additional_reminder_day',
290 'frequency_unit',
291 'pledge_contribution_page_id',
292 'pledge_status_id',
293 'pledge_campaign_id',
294 )
295 ),
296 'PaymentProcessorType' => array(
297 'cant_update' => array(
298 'billing_mode',
299 ),
300 'break_return' => array(
301 ),
302 'cant_return' => array(
303 ),
304 ),
305 );
306 if(empty($knownFailures[$entity]) || empty($knownFailures[$entity][$key])){
307 return array();
308 }
309 return $knownFailures[$entity][$key];
310 }
311
312 /** testing the _get **/
313
314 /**
315 * @dataProvider toBeSkipped_get
316 entities that don't need a get action
317 */
318 public function testNotImplemented_get($Entity) {
319 $result = civicrm_api($Entity, 'Get', array('version' => 3));
320 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
321 $this->assertContains("API ($Entity,Get) does not exist", $result['error_message']);
322 }
323
324 /**
325 * @dataProvider entities
326 * @expectedException PHPUnit_Framework_Error
327 */
328 public function testWithoutParam_get($Entity) {
329 // should get php complaining that a param is missing
330 $result = civicrm_api($Entity, 'Get');
331 }
332
333 /**
334 * @dataProvider entities
335 */
336 public function testGetFields($Entity) {
337 if (in_array($Entity, $this->deprecatedAPI) || $Entity == 'Entity' || $Entity == 'CustomValue' || $Entity == 'MailingGroup') {
338 return;
339 }
340
341 $result = civicrm_api($Entity, 'getfields', array('version' => 3));
342 $this->assertTrue(is_array($result['values']), "$Entity ::get fields doesn't return values array in line " . __LINE__);
343 foreach ($result['values'] as $key => $value) {
344 $this->assertTrue(is_array($value), $Entity . "::" . $key . " is not an array in line " . __LINE__);
345 }
346 }
347
348 /**
349 * @dataProvider entities_get
350 */
351 public function testEmptyParam_get($Entity) {
352
353 if (in_array($Entity, $this->toBeImplemented['get'])) {
354 // $this->markTestIncomplete("civicrm_api3_{$Entity}_get to be implemented");
355 return;
356 }
357 $result = civicrm_api($Entity, 'Get', array());
358 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
359 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
360 }
361 /**
362 * @dataProvider entities_get
363 */
364 public function testEmptyParam_getString($Entity) {
365
366 if (in_array($Entity, $this->toBeImplemented['get'])) {
367 // $this->markTestIncomplete("civicrm_api3_{$Entity}_get to be implemented");
368 return;
369 }
370 $result = $this->callAPIFailure($Entity, 'Get', 'string');
371 $this->assertEquals(2000, $result['error_code']);
372 $this->assertEquals('Input variable `params` is not an array', $result['error_message']);
373 }
374 /**
375 * @dataProvider entities_get
376 * @Xdepends testEmptyParam_get // no need to test the simple if the empty doesn't work/is skipped. doesn't seem to work
377 */
378 public function testSimple_get($Entity) {
379 // $this->markTestSkipped("test gives core error on test server (but not on our locals). Skip until we can get server to pass");
380 if (in_array($Entity, $this->toBeImplemented['get'])) {
381 return;
382 }
383 $result = civicrm_api($Entity, 'Get', array('version' => 3));
384 // @TODO: list the get that have mandatory params
385 if ($result['is_error']) {
386 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
387 // either id or contact_id or entity_id is one of the field missing
388 $this->assertContains("id", $result['error_message']);
389 }
390 else {
391 $this->assertEquals(3, $result['version']);
392 $this->assertArrayHasKey('count', $result);
393 $this->assertArrayHasKey('values', $result);
394 }
395 }
396
397 /**
398 * @dataProvider entities_get
399 */
400 public function testAcceptsOnlyID_get($Entity) {
401 // big random number. fun fact: if you multiply it by pi^e, the result is another random number, but bigger ;)
402 $nonExistantID = 30867307034;
403 if (in_array($Entity, $this->toBeImplemented['get'])
404 || in_array($Entity, $this->toBeSkipped_getByID())
405 ) {
406 return;
407 }
408
409 // FIXME
410 // the below function returns different values and hence an early return
411 // we'll fix this once beta1 is released
412 // return;
413
414 $result = civicrm_api($Entity, 'Get', array('version' => 3, 'id' => $nonExistantID));
415
416 if ($result['is_error']) {
417 // just to get a clearer message in the log
418 $this->assertEquals("only id should be enough", $result['error_message']);
419 }
420 if (!in_array($Entity, $this->onlyIDNonZeroCount['get'])) {
421 $this->assertEquals(0, $result['count']);
422 }
423 }
424
425 /**
426 * Create two entities and make sure we can fetch them individually by ID
427 *
428 * @dataProvider entities_get
429 *
430 * limitations include the problem with avoiding loops when creating test objects -
431 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
432 * Currency - only seems to support US
433 */
434 public function testByID_get($entityName) {
435 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
436 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
437 return;
438 }
439
440 $baos = $this->getMockableBAOObjects($entityName);
441 list($baoObj1, $baoObj2) = $baos;
442
443 // fetch first by ID
444 $result = civicrm_api($entityName, 'get', array(
445 'version' => 3,
446 'id' => $baoObj1->id,
447 ));
448 $this->assertAPISuccess($result);
449 $this->assertTrue(!empty($result['values'][$baoObj1->id]), 'Should find first object by id');
450 $this->assertEquals($baoObj1->id, $result['values'][$baoObj1->id]['id'], 'Should find id on first object');
451 $this->assertEquals(1, count($result['values']));
452
453 // fetch second by ID
454 $result = civicrm_api($entityName, 'get', array(
455 'version' => 3,
456 'id' => $baoObj2->id,
457 ));
458 $this->assertAPISuccess($result);
459 $this->assertTrue(!empty($result['values'][$baoObj2->id]), 'Should find second object by id');
460 $this->assertEquals($baoObj2->id, $result['values'][$baoObj2->id]['id'], 'Should find id on second object');
461 $this->assertEquals(1, count($result['values']));
462 }
463
464 /**
465 * Create two entities and make sure we can fetch them individually by ID (e.g. using "contact_id=>2"
466 * or "group_id=>4")
467 *
468 * @dataProvider entities_get
469 *
470 * limitations include the problem with avoiding loops when creating test objects -
471 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
472 * Currency - only seems to support US
473 */
474 public function testByIDAlias_get($entityName) {
475 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
476 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
477 return;
478 }
479
480 $baoString = _civicrm_api3_get_DAO($entityName);
481 if (empty($baoString)) {
482 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
483 return;
484 }
485
486 $idFieldName = _civicrm_api_get_entity_name_from_camel($entityName) . '_id';
487
488 // create entities
489 $baoObj1 = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
490 $this->assertTrue(is_integer($baoObj1->id), 'check first id');
491 $this->deletableTestObjects[$baoString][] = $baoObj1->id;
492 $baoObj2 = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
493 $this->assertTrue(is_integer($baoObj2->id), 'check second id');
494 $this->deletableTestObjects[$baoString][] = $baoObj2->id;
495
496 // fetch first by ID
497 $result = civicrm_api($entityName, 'get', array(
498 'version' => 3,
499 $idFieldName => $baoObj1->id,
500 ));
501 $this->assertAPISuccess($result);
502 $this->assertTrue(!empty($result['values'][$baoObj1->id]), 'Should find first object by id');
503 $this->assertEquals($baoObj1->id, $result['values'][$baoObj1->id]['id'], 'Should find id on first object');
504 $this->assertEquals(1, count($result['values']));
505
506 // fetch second by ID
507 $result = civicrm_api($entityName, 'get', array(
508 'version' => 3,
509 $idFieldName => $baoObj2->id,
510 ));
511 $this->assertAPISuccess($result);
512 $this->assertTrue(!empty($result['values'][$baoObj2->id]), 'Should find second object by id');
513 $this->assertEquals($baoObj2->id, $result['values'][$baoObj2->id]['id'], 'Should find id on second object');
514 $this->assertEquals(1, count($result['values']));
515 }
516
517 /**
518 * @dataProvider entities_get
519 */
520 public function testNonExistantID_get($Entity) {
521 // cf testAcceptsOnlyID_get
522 $nonExistantID = 30867307034;
523 if (in_array($Entity, $this->toBeImplemented['get'])) {
524 return;
525 }
526
527 $result = civicrm_api($Entity, 'Get', array('version' => 3, 'id' => $nonExistantID));
528
529 // redundant with testAcceptsOnlyID_get
530 if ($result['is_error']) {
531 return;
532 }
533
534
535 $this->assertArrayHasKey('version', $result);
536 $this->assertEquals(3, $result['version']);
537 if (!in_array($Entity, $this->onlyIDNonZeroCount['get'])) {
538 $this->assertEquals(0, $result['count']);
539 }
540 }
541
542 /** testing the _create **/
543
544 /**
545 * @dataProvider toBeSkipped_create
546 entities that don't need a create action
547 */
548 public function testNotImplemented_create($Entity) {
549 $result = civicrm_api($Entity, 'Create', array('version' => 3));
550 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
551 $this->assertContains("API ($Entity,Create) does not exist", $result['error_message']);
552 }
553
554 /**
555 * @dataProvider entities
556 * @expectedException PHPUnit_Framework_Error
557 */
558 public function testWithoutParam_create($Entity) {
559 // should create php complaining that a param is missing
560 $result = civicrm_api($Entity, 'Create');
561 }
562
563 /**
564 * @dataProvider entities_create
565 */
566 public function testEmptyParam_create($Entity) {
567 $this->markTestIncomplete("fixing this test to test the api functions fails on numberous tests
568 which will either create a completely blank entity (batch, participant status) or
569 have a damn good crack at it (e.g mailing job). Marking this as incomplete beats false success");
570 //
571 return;
572 if (in_array($Entity, $this->toBeImplemented['create'])) {
573 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
574 return;
575 }
576 $result = $this->callAPIFailure($Entity, 'Create', array());
577 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
578 }
579
580 /**
581 * @dataProvider entities_create
582 *
583 * Check that create doesn't work with an invalid
584 */
585 public function testInvalidID_create($Entity) {
586 // turn test off for noew
587 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
588 return;
589 if (in_array($Entity, $this->toBeImplemented['create'])) {
590 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
591 return;
592 }
593 $result = $this->callAPIFailure($Entity, 'Create', array('id' => 999));
594 }
595
596 /**
597 * @dataProvider entities
598 */
599 public function testCreateWrongTypeParamTag_create() {
600 $result = civicrm_api("Tag", 'Create', 'this is not a string');
601 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
602 $this->assertEquals("Input variable `params` is not an array", $result['error_message']);
603 }
604
605 /**
606 * @dataProvider entities_updatesingle
607 *
608 * limitations include the problem with avoiding loops when creating test objects -
609 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
610 * Currency - only seems to support US
611 */
612 public function testCreateSingleValueAlter($entityName) {
613 if (in_array($entityName, $this->toBeImplemented['create'])) {
614 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
615 return;
616 }
617
618 $baoString = _civicrm_api3_get_DAO($entityName);
619 $this->assertNotEmpty($baoString, $entityName);
620 $this->assertNotEmpty($entityName, $entityName);
621 $fieldsget = $fields = civicrm_api($entityName, 'getfields', array(
622 'version' => 3, 'action' => 'get'
623 )
624 );
625 if($entityName != 'Pledge'){
626 $fields = civicrm_api($entityName, 'getfields', array(
627 'version' => 3, 'action' => 'create'
628 )
629 );
630 }
631 $fields = $fields['values'];
632 $return = array_keys($fieldsget['values']);
633 $valuesNotToReturn = $this->getKnownUnworkablesUpdateSingle($entityName, 'break_return');
634 // these can't be requested as return values
635 $entityValuesThatDontWork = array_merge(
636 $this->getKnownUnworkablesUpdateSingle($entityName, 'cant_update'),
637 $this->getKnownUnworkablesUpdateSingle($entityName, 'cant_return'),
638 $valuesNotToReturn
639 );
640
641 $return = array_diff($return,$valuesNotToReturn);
642 $baoObj = new CRM_Core_DAO();
643 $baoObj->createTestObject($baoString, array('currency' => 'USD'), 2, 0);
644 $getentities = civicrm_api($entityName, 'get', array(
645 'version' => 3,
646 'sequential' => 1,
647 'return' => $return,
648 'options' => array(
649 'sort' => 'id DESC',
650 'limit' => 2,
651 ),
652 ));
653 // lets use first rather than assume only one exists
654 $entity = $getentities['values'][0];
655 $entity2 = $getentities['values'][1];
656 foreach ($fields as $field => $specs) {
657 $fieldName = $field;
658 if (!empty($specs['uniquename'])) {
659 $fieldName = $specs['uniquename'];
660 }
661 if ($field == 'currency' || $field == 'id' || $field == strtolower($entityName) . '_id'
662 || in_array($field,$entityValuesThatDontWork)) {
663 //@todo id & entity_id are correct but we should fix currency & frequency_day
664 continue;
665 }
666 switch ($specs['type']) {
667 case CRM_Utils_Type::T_DATE:
668 case CRM_Utils_Type::T_TIMESTAMP:
669 $entity[$fieldName] = '2012-05-20';
670 break;
671 //case CRM_Utils_Type::T_DATETIME:
672
673 case 12:
674 $entity[$fieldName] = '2012-05-20 03:05:20';
675 break;
676
677 case CRM_Utils_Type::T_STRING:
678 case CRM_Utils_Type::T_BLOB:
679 case CRM_Utils_Type::T_MEDIUMBLOB:
680 case CRM_Utils_Type::T_TEXT:
681 case CRM_Utils_Type::T_LONGTEXT:
682 case CRM_Utils_Type::T_EMAIL:
683 $entity[$fieldName] = substr('New String',0, CRM_Utils_Array::Value('maxlength',$specs,100));
684 break;
685
686 case CRM_Utils_Type::T_INT:
687 // probably created with a 1
688 $entity[$fieldName] = '6';
689 if (CRM_Utils_Array::value('FKClassName', $specs)) {
690 if($specs['FKClassName'] == $baoString){
691 $entity[$fieldName] = (string) $entity2['id'];
692 }
693 else{
694 $entity[$fieldName] = (string) empty($entity2[$field]) ? CRM_Utils_Array::value($specs['uniqueName'], $entity2) : $entity2[$field];
695 //todo - there isn't always something set here - & our checking on unset values is limited
696 if (empty($entity[$field])) {
697 unset($entity[$field]);
698 }
699 }
700 }
701 break;
702
703 case CRM_Utils_Type::T_BOOL:
704 case CRM_Utils_Type::T_BOOLEAN:
705 // probably created with a 1
706 $entity[$fieldName] = '0';
707 break;
708
709 case CRM_Utils_Type::T_FLOAT:
710 case CRM_Utils_Type::T_MONEY:
711 $entity[$field] = '222';
712 break;
713
714 case CRM_Utils_Type::T_URL:
715 $entity[$field] = 'warm.beer.com';
716 }
717 if (!empty($specs['pseudoconstant']) || !empty($specs['enumValues'])) {
718 $options = civicrm_api($entityName, 'getoptions', array('context' => 'create', 'field' => $field, 'version' => 3));
719 if (empty($options['values'])) {
720 print_r($options);
721 }
722 $entity[$field] = array_rand($options['values']);
723 }
724 $updateParams = array(
725 'version' => 3,
726 'id' => $entity['id'],
727 $field => $entity[$field],
728 );
729
730 $update = civicrm_api($entityName, 'create', $updateParams);
731 if(!empty($update['is_error'])){
732 print_r($update);
733 }
734 $this->assertAPISuccess($update, print_r($updateParams, TRUE) . 'in line ' . __LINE__);
735 $checkParams = array(
736 'id' => $entity['id'],
737 'version' => 3,
738 'sequential' => 1,
739 'return' => $return,
740 'options' => array(
741 'sort' => 'id DESC',
742 'limit' => 2,
743 ),
744 );
745
746 $checkEntity = civicrm_api($entityName, 'getsingle', $checkParams);
747 $this->assertEquals($entity, $checkEntity, "changing field $fieldName\n" .
748 print_r($entity, TRUE)
749 //print_r(array('update-params' => $updateParams, 'update-result' => $update, 'getsingle-params' => $checkParams, 'getsingle-result' => $checkEntity, 'expected entity' => $entity), TRUE)
750 );
751
752 }
753 $baoObj->deleteTestObjects($baoString);
754 $baoObj->free();
755 }
756
757 /** testing the _getFields **/
758
759 /** testing the _delete **/
760
761 /**
762 * @dataProvider toBeSkipped_delete
763 entities that don't need a delete action
764 */
765 public function testNotImplemented_delete($Entity) {
766 $nonExistantID = 151416349;
767 $result = civicrm_api($Entity, 'Delete', array('version' => 3, 'id' => $nonExistantID));
768 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
769 $this->assertContains("API ($Entity,Delete) does not exist", $result['error_message']);
770 }
771
772 /**
773 * @dataProvider entities
774 * @expectedException PHPUnit_Framework_Error
775 */
776 public function testWithoutParam_delete($Entity) {
777 // should delete php complaining that a param is missing
778 $result = civicrm_api($Entity, 'Delete');
779 }
780
781 /**
782 * @dataProvider entities_delete
783 */
784 public function testEmptyParam_delete($Entity) {
785 if (in_array($Entity, $this->toBeImplemented['delete'])) {
786 // $this->markTestIncomplete("civicrm_api3_{$Entity}_delete to be implemented");
787 return;
788 }
789 $result = civicrm_api($Entity, 'Delete', array());
790 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
791 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
792 }
793 /**
794 * @dataProvider entities_delete
795 */
796 public function testInvalidID_delete($Entity) {
797 // turn test off for noew
798 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
799 return;
800 if (in_array($Entity, $this->toBeImplemented['delete'])) {
801 // $this->markTestIncomplete("civicrm_api3_{$Entity}_delete to be implemented");
802 return;
803 }
804 $result = $this->callAPIFailure($Entity, 'Delete', array('id' => 999));
805 }
806 /**
807 * @dataProvider entities
808 */
809 public function testDeleteWrongTypeParamTag_delete() {
810 $result = civicrm_api("Tag", 'Delete', 'this is not a string');
811 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
812 $this->assertEquals("Input variable `params` is not an array", $result['error_message']);
813 }
814
815 /**
816 * Create two entities and make sure delete action only deletes one!
817 *
818 * @dataProvider entities_delete
819 *
820 * limitations include the problem with avoiding loops when creating test objects -
821 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
822 * Currency - only seems to support US
823 */
824 public function testByID_delete($entityName) {
825 // turn test off for noew
826 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
827 return;
828
829 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
830 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
831 return;
832 }
833 $startCount = $this->callAPISuccess($entityName, 'getcount', array());
834 $createcount = 2;
835 $baos = $this->getMockableBAOObjects($entityName, $createcount);
836 list($baoObj1, $baoObj2) = $baos;
837
838 // make sure exactly 2 exist
839 $result = $this->callAPISuccess($entityName, 'getcount', array(),
840 $createcount + $startCount
841 );
842
843 $this->callAPISuccess($entityName, 'delete', array('id' => $baoObj2->id));
844 //make sure 1 less exists now
845 $result = $this->callAPISuccess($entityName, 'getcount', array(),
846 ($createcount + $startCount) -1
847 );
848
849 //make sure id #1 exists
850 $result = $this->callAPISuccess($entityName, 'getcount', array('id' => $baoObj1->id),
851 1
852 );
853 //make sure id #2 desn't exist
854 $result = $this->callAPISuccess($entityName, 'getcount', array('id' => $baoObj2->id),
855 0
856 );
857 }
858
859 /**
860 * @param entityName
861 */private function getMockableBAOObjects($entityName, $count = 2) {
862 $baoString = _civicrm_api3_get_DAO($entityName);
863 if (empty($baoString)) {
864 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
865 return;
866 }
867 $baos = array();
868 while($i < $count) {
869 // create entities
870 $baoObj = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
871 $this->assertTrue(is_integer($baoObj->id), 'check first id');
872 $this->deletableTestObjects[$baoString][] = $baoObj->id;
873 $baos[] = $baoObj;
874 $i ++;
875 }
876 return $baos;
877 }
878
879
880 /**
881 * Verify that HTML metacharacters provided as inputs appear consistently
882 * as outputs.
883 *
884 * At time of writing, the encoding scheme requires (for example) that an
885 * event title be partially-HTML-escaped before writing to DB. To provide
886 * consistency, the API must perform extra encoding and decoding on some
887 * fields.
888 *
889 * In this example, the event 'title' is subject to encoding, but the
890 * event 'description' is not.
891 */
892 public function testEncodeDecodeConsistency() {
893 // Create example
894 $createResult = civicrm_api('Event', 'Create', array(
895 'version' => 3,
896 'title' => 'CiviCRM <> TheRest',
897 'description' => 'TheRest <> CiviCRM',
898 'event_type_id' => 1,
899 'is_public' => 1,
900 'start_date' => 20081021,
901 ));
902 $this->assertAPISuccess($createResult);
903 $eventId = $createResult['id'];
904 $this->assertEquals('CiviCRM <> TheRest', $createResult['values'][$eventId]['title']);
905 $this->assertEquals('TheRest <> CiviCRM', $createResult['values'][$eventId]['description']);
906
907 // Verify "get" handles decoding in result value
908 $getByIdResult = civicrm_api('Event', 'Get', array(
909 'version' => 3,
910 'id' => $eventId,
911 ));
912 $this->assertAPISuccess($getByIdResult);
913 $this->assertEquals('CiviCRM <> TheRest', $getByIdResult['values'][$eventId]['title']);
914 $this->assertEquals('TheRest <> CiviCRM', $getByIdResult['values'][$eventId]['description']);
915
916 // Verify "get" handles encoding in search value
917 $getByTitleResult = civicrm_api('Event', 'Get', array(
918 'version' => 3,
919 'title' => 'CiviCRM <> TheRest',
920 ));
921 $this->assertAPISuccess($getByTitleResult);
922 $this->assertEquals('CiviCRM <> TheRest', $getByTitleResult['values'][$eventId]['title']);
923 $this->assertEquals('TheRest <> CiviCRM', $getByTitleResult['values'][$eventId]['description']);
924
925 // Verify that "getSingle" handles decoding
926 $getSingleResult = civicrm_api('Event', 'GetSingle', array(
927 'version' => 3,
928 'id' => $eventId,
929 ));
930
931 $this->assertAPISuccess($getSingleResult);
932 $this->assertEquals('CiviCRM <> TheRest', $getSingleResult['title']);
933 $this->assertEquals('TheRest <> CiviCRM', $getSingleResult['description']);
934
935 // Verify that chaining handles decoding
936 $chainResult = civicrm_api('Event', 'Get', array(
937 'version' => 3,
938 'id' => $eventId,
939 'api.event.get' => array(
940 ),
941 ));
942 $this->assertEquals('CiviCRM <> TheRest', $chainResult['values'][$eventId]['title']);
943 $this->assertEquals('TheRest <> CiviCRM', $chainResult['values'][$eventId]['description']);
944 $this->assertEquals('CiviCRM <> TheRest', $chainResult['values'][$eventId]['api.event.get']['values'][0]['title']);
945 $this->assertEquals('TheRest <> CiviCRM', $chainResult['values'][$eventId]['api.event.get']['values'][0]['description']);
946
947 // Verify that "setvalue" handles encoding for updates
948 $setValueTitleResult = civicrm_api('Event', 'setvalue', array(
949 'version' => 3,
950 'id' => $eventId,
951 'field' => 'title',
952 'value' => 'setValueTitle: CiviCRM <> TheRest',
953 ));
954 $this->assertAPISuccess($setValueTitleResult);
955 $this->assertEquals('setValueTitle: CiviCRM <> TheRest', $setValueTitleResult['values']['title']);
956 $setValueDescriptionResult = civicrm_api('Event', 'setvalue', array(
957 'version' => 3,
958 'id' => $eventId,
959 'field' => 'description',
960 'value' => 'setValueDescription: TheRest <> CiviCRM',
961 ));
962 $this->assertTrue((bool)$setValueDescriptionResult['is_error']); // not supported by setValue
963 //$this->assertAPISuccess($setValueDescriptionResult);
964 //$this->assertEquals('setValueDescription: TheRest <> CiviCRM', $setValueDescriptionResult['values']['description']);
965 }
966
967 /**
968 * Verify that write operations (create/update) use partial HTML-encoding
969 *
970 * In this example, the event 'title' is subject to encoding, but the
971 * event 'description' is not.
972 */
973 public function testEncodeWrite() {
974 // Create example
975 $createResult = civicrm_api('Event', 'Create', array(
976 'version' => 3,
977 'title' => 'createNew: CiviCRM <> TheRest',
978 'description' => 'createNew: TheRest <> CiviCRM',
979 'event_type_id' => 1,
980 'is_public' => 1,
981 'start_date' => 20081021,
982 ));
983 $this->assertAPISuccess($createResult);
984 $eventId = $createResult['id'];
985 $this->assertDBQuery('createNew: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
986 1 => array($eventId, 'Integer')
987 ));
988 $this->assertDBQuery('createNew: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
989 1 => array($eventId, 'Integer')
990 ));
991
992 // Verify that "create" handles encoding for updates
993 $createWithIdResult = civicrm_api('Event', 'Create', array(
994 'version' => 3,
995 'id' => $eventId,
996 'title' => 'createWithId: CiviCRM <> TheRest',
997 'description' => 'createWithId: TheRest <> CiviCRM',
998 ));
999 $this->assertAPISuccess($createWithIdResult);
1000 $this->assertDBQuery('createWithId: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
1001 1 => array($eventId, 'Integer')
1002 ));
1003 $this->assertDBQuery('createWithId: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
1004 1 => array($eventId, 'Integer')
1005 ));
1006
1007 // Verify that "setvalue" handles encoding for updates
1008 $setValueTitleResult = civicrm_api('Event', 'setvalue', array(
1009 'version' => 3,
1010 'id' => $eventId,
1011 'field' => 'title',
1012 'value' => 'setValueTitle: CiviCRM <> TheRest',
1013 ));
1014 $this->assertAPISuccess($setValueTitleResult);
1015 $this->assertDBQuery('setValueTitle: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
1016 1 => array($eventId, 'Integer')
1017 ));
1018 $setValueDescriptionResult = civicrm_api('Event', 'setvalue', array(
1019 'version' => 3,
1020 'id' => $eventId,
1021 'field' => 'description',
1022 'value' => 'setValueDescription: TheRest <> CiviCRM',
1023 ));
1024 $this->assertTrue((bool)$setValueDescriptionResult['is_error']); // not supported by setValue
1025 //$this->assertAPISuccess($setValueDescriptionResult);
1026 //$this->assertDBQuery('setValueDescription: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
1027 // 1 => array($eventId, 'Integer')
1028 //));
1029 }
1030
1031 }