CRM-15168 fix test to cope with problems with getactions
[civicrm-core.git] / tests / phpunit / api / v3 / SyntaxConformanceTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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
49 protected $_entity;
50
51 /** Map custom group entities to civicrm components */
52 static $componentMap = array(
53 'Contact' => NULL,
54 'Individual' => NULL,
55 'Household' => NULL,
56 'Organization' => NULL,
57 'Contribution' => 'CiviContribute',
58 'Membership' => 'CiviMember',
59 'Participant' => 'CiviEvent',
60 'Group' => NULL,
61 'Relationship' => NULL,
62 'Event' => 'CiviEvent',
63 'Case' => 'CiviCase',
64 'Activity' => NULL,
65 'Pledge' => 'CiviPledge',
66 'Grant' => 'CiviGrant',
67 'Address' => NULL,
68 );
69
70 /* they are two types of missing APIs:
71 - Those that are to be implemented
72 (in some future version when someone steps in -hint hint-). List the entities in toBeImplemented[ {$action} ]
73 Those that don't exist
74 and that will never exist (eg an obsoleted Entity
75 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)
76 */
77 function setUp() {
78 parent::setUp();
79 $this->enableCiviCampaign();
80 $this->toBeImplemented['get'] = array('Profile', 'CustomValue', 'Constant', 'CustomSearch', 'Extension', 'ReportTemplate', 'System', 'Setting');
81 $this->toBeImplemented['create'] = array('SurveyRespondant', 'OptionGroup', 'MailingRecipients', 'UFMatch', 'LocationType', 'CustomSearch', 'Extension', 'ReportTemplate', 'System');
82 $this->toBeImplemented['delete'] = array('MembershipPayment', 'OptionGroup', 'SurveyRespondant', 'UFJoin', 'UFMatch', 'Extension', 'LocationType', 'System');
83 $this->onlyIDNonZeroCount['get'] = array('ActivityType', 'Entity', 'Domain','Setting');
84 $this->deprecatedAPI = array('Location', 'ActivityType', 'SurveyRespondant');
85 $this->deletableTestObjects = array();
86 }
87
88 function tearDown() {
89 foreach ($this->deletableTestObjects as $entityName => $entities) {
90 foreach ($entities as $entityID) {
91 CRM_Core_DAO::deleteTestObjects($entityName, array('id' => $entityID));
92 }
93 }
94 }
95
96 /**
97 * @param null $skip
98 *
99 * @return array
100 */
101 public static function entities($skip = NULL) {
102 // To only test specific entities, call phpunit with SYNTAX_CONFORMANCE_ENTITIES="TheEntityName"
103 // or uncomment this line:
104 //return array(array ('Tag'), array ('Activity') );
105
106 if (getenv('SYNTAX_CONFORMANCE_ENTITIES')) {
107 $result = array();
108 foreach (explode(' ', getenv('SYNTAX_CONFORMANCE_ENTITIES')) as $entity) {
109 $result[] = array($entity);
110 }
111 return $result;
112 }
113
114 $tmp = civicrm_api('Entity', 'Get', array('version' => 3));
115 if (!is_array($skip)) {
116 $skip = array();
117 }
118 $tmp = array_diff($tmp['values'], $skip);
119 $entities = array();
120 foreach ($tmp as $e) {
121 $entities[] = array($e);
122 }
123 return $entities;
124 }
125
126 /**
127 * @return array
128 */
129 public static function entities_get() {
130 // all the entities, beside the ones flagged
131 return static::entities(static::toBeSkipped_get(TRUE));
132 }
133
134 /**
135 * @return array
136 */
137 public static function entities_create() {
138 return static::entities(static::toBeSkipped_create(TRUE));
139 }
140
141 /**
142 * @return array
143 */
144 public static function entities_updatesingle() {
145 return static::entities(static::toBeSkipped_updatesingle(TRUE));
146 }
147
148 /**
149 * @return array
150 */
151 public static function entities_getlimit() {
152 return static::entities(static::toBeSkipped_getlimit());
153 }
154
155 /**
156 * @return array
157 */
158 public static function entities_delete() {
159 return static::entities(static::toBeSkipped_delete(TRUE));
160 }
161
162 /**
163 * @return array
164 */
165 public static function entities_getfields() {
166 return static::entities(static::toBeSkipped_getfields(TRUE));
167 }
168 /**
169 * @return array
170 */
171 public static function custom_data_entities_get() {
172 return static::custom_data_entities();
173 }
174
175 /**
176 * @return array
177 */
178 public static function custom_data_entities() {
179 $enableComponents = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components', NULL, array());
180 $entities = CRM_Core_BAO_CustomQuery::$extendsMap;
181 $components = self::$componentMap;
182 $customDataEntities = array();
183 $invalidEntities = array('Individual', 'Organization', 'Household');
184 $entitiesToFix = array('Case', 'Relationship');
185 foreach ($entities as $entityName => $entity ) {
186 if(!in_array($entityName, $invalidEntities)
187 && !in_array($entityName, $entitiesToFix)
188 && (!empty($components[$entityName]) && in_array($components[$entityName], $enableComponents) || $components[$entityName] == NULL)) {
189 $customDataEntities[] = array($entityName );
190 }
191 }
192 return $customDataEntities;
193 }
194
195 /**
196 * @param bool $sequential
197 *
198 * @return array
199 */
200 public static function toBeSkipped_get($sequential = FALSE) {
201 $entitiesWithoutGet = array('MailingEventSubscribe', 'MailingEventConfirm', 'MailingEventResubscribe', 'MailingEventUnsubscribe', 'MailingGroup', 'Location');
202 if ($sequential === TRUE) {
203 return $entitiesWithoutGet;
204 }
205 $entities = array();
206 foreach ($entitiesWithoutGet as $e) {
207 $entities[] = array($e);
208 }
209 return $entities;
210 }
211
212 /**
213 * Mailing Contact Just doesn't support id. We have always insisted on finding a way to
214 * support id in API but in this case the underlying tables are crying out for a restructue
215 * & it just doesn't make sense
216 *
217 * @param bool|\unknown_type $sequential
218 *
219 * @return multitype:string |multitype:multitype:string
220 */
221 public static function toBeSkipped_getByID($sequential = FALSE) {
222 return array('MailingContact');
223 }
224
225 /**
226 * @param bool $sequential
227 *
228 * @return array
229 */
230 public static function toBeSkipped_create($sequential = FALSE) {
231 $entitiesWithoutCreate = array('MailingGroup', 'Constant', 'Entity', 'Location', 'Profile', 'MailingRecipients');
232 if ($sequential === TRUE) {
233 return $entitiesWithoutCreate;
234 }
235 $entities = array();
236 foreach ($entitiesWithoutCreate as $e) {
237 $entities[] = array($e);
238 }
239 return $entities;
240 }
241
242 /**
243 * @param bool $sequential
244 *
245 * @return array
246 */
247 public static function toBeSkipped_delete($sequential = FALSE) {
248 $entitiesWithout = array('MailingContact', 'MailingEventConfirm', 'MailingEventResubscribe', 'MailingEventSubscribe', 'MailingEventUnsubscribe', 'MailingGroup', 'MailingRecipients', 'Constant', 'Entity', 'Location', 'Domain', 'Profile', 'CustomValue', 'Setting');
249 if ($sequential === TRUE) {
250 return $entitiesWithout;
251 }
252 $entities = array();
253 foreach ($entitiesWithout as $e) {
254 $entities[] = array($e);
255 }
256 return $entities;
257 }
258
259 /**
260 * @param bool $sequential
261 *
262 * @return array
263 * @todo add metadata for ALL these entities
264 */
265 public static function toBeSkipped_getfields($sequential = FALSE) {
266 $entitiesWithMetadataNotYetFixed = array('ReportTemplate', 'CustomSearch');
267 if ($sequential === TRUE) {
268 return $entitiesWithMetadataNotYetFixed ;
269 }
270 $entities = array();
271 foreach ($entitiesWithMetadataNotYetFixed as $e) {
272 $entities[] = array($e);
273 }
274 return $entities;
275 }
276 /**
277 * Generate list of entities to test for get by id functions
278 * @param boolean $sequential
279 * @return multitype:string |multitype:multitype:string
280 */
281 public static function toBeSkipped_automock($sequential = FALSE) {
282 $entitiesWithoutGet = array('MailingContact', 'EntityTag', 'Participant', 'ParticipantPayment', 'Setting', 'SurveyRespondant', 'MailingRecipients', 'CustomSearch', 'Extension', 'ReportTemplate', 'System');
283 if ($sequential === TRUE) {
284 return $entitiesWithoutGet;
285 }
286 $entities = array();
287 foreach ($entitiesWithoutGet as $e) {
288 $entities[] = array($e);
289 }
290 return $entities;
291 }
292
293
294 /**
295 * At this stage exclude the ones that don't pass & add them as we can troubleshoot them
296 */
297 public static function toBeSkipped_updatesingle($sequential = FALSE) {
298 $entitiesWithout = array(
299 'Mailing',
300 'MailingGroup',
301 'MailingJob',
302 'Address',
303 'MailingEventUnsubscribe',
304 'MailingEventSubscribe',
305 'Constant',
306 'Entity',
307 'Location',
308 'Domain',
309 'Profile',
310 'CustomValue',
311 'SurveyRespondant',
312 'Tag',
313 'UFMatch',
314 'UFJoin',
315 'UFField',
316 'OptionValue',
317 'Relationship',
318 'RelationshipType',
319 'ParticipantStatusType',
320 'Note',
321 'OptionGroup',
322 'Membership',
323 'MembershipType',
324 'MembershipStatus',
325 'Group',
326 'GroupOrganization',
327 'GroupNesting',
328 'Job',
329 'File',
330 'EntityTag',
331 'CustomField',
332 'CustomGroup',
333 'Contribution',
334 'ContributionRecur',
335 'ActivityType',
336 'MailingEventConfirm',
337 'Case',
338 'Contact',
339 'ContactType',
340 'MailingEventResubscribe',
341 'UFGroup',
342 'Activity',
343 'Email',
344 'Event',
345 'GroupContact',
346 'MembershipPayment',
347 'Participant',
348 'ParticipantPayment',
349 'LineItem',
350 'PriceSet',
351 'PriceField',
352 'PriceFieldValue',
353 'PledgePayment',
354 'ContributionPage',
355 'Phone',
356 'PaymentProcessor',
357 'MailSettings',
358 'Setting',
359 'MailingContact',
360 'SystemLog' //skip this because it doesn't make sense to update logs
361 );
362 if ($sequential === TRUE) {
363 return $entitiesWithout;
364 }
365 $entities = array();
366 foreach ($entitiesWithout as $e) {
367 $entities[] = array(
368 $e,
369 );
370 }
371 return array('pledge');
372 return $entities;
373 }
374
375 /**
376 * At this stage exclude the ones that don't pass & add them as we can troubleshoot them
377 */
378 public static function toBeSkipped_getlimit() {
379 $entitiesWithout = array(
380 'Case',//case api has non-std mandatory fields one of (case_id, contact_id, activity_id, contact_id)
381 'EntityTag', // non-standard api - has inappropriate mandatory fields & doesn't implement limit
382 'Event', // failed 'check that a 5 limit returns 5' - probably is_template field is wrong or something, or could be limit doesn't work right
383 'Extension', // can't handle creating 25
384 'MailingGroup', // no get call on MailingGroup
385 'Note', // fails on 5 limit - probably a set up problem
386 'Setting', //a bit of a pseudoapi - keys by domain
387 );
388 return $entitiesWithout;
389 }
390
391 /**
392 * @param $entity
393 * @param $key
394 *
395 * @return array
396 */
397 public function getKnownUnworkablesUpdateSingle($entity, $key){
398 // can't update values are values for which updates don't result in the value being changed
399 $knownFailures = array(
400 'ActionSchedule' => array(
401 'cant_update' => array(
402 'group_id',
403 ),
404 ),
405 'ActivityContact' => array(
406 'cant_update' => array(
407 'activity_id', //we have an FK on activity_id + contact_id + record id so if we don't leave this one distinct we get an FK constraint error
408 ),
409 ),
410 'Address' => array(
411 'cant_update' => array(
412 'state_province_id', //issues with country id - need to ensure same country
413 'master_id',//creates relationship
414 ),
415 'cant_return' => array(
416 )
417 ),
418 'Batch' => array(
419 'cant_update' => array(
420 'entity_table', // believe this field is defined in error
421 ),
422 'cant_return' => array(
423 'entity_table',
424 )
425 ),
426 'Pledge' => array(
427 'cant_update' => array(
428 'pledge_original_installment_amount',
429 'installments',
430 'original_installment_amount',
431 'next_pay_date',
432 'amount' // can't be changed through API
433 ),
434 'break_return' => array(// if these are passed in they are retrieved from the wrong table
435 'honor_contact_id',
436 'cancel_date',
437 'contribution_page_id',
438 'financial_account_id',
439 'financial_type_id',
440 'currency'
441 ),
442 'cant_return' => array(// can't be retrieved from api
443 'honor_type_id', //due to uniquename missing
444 'end_date',
445 'modified_date',
446 'acknowledge_date',
447 'start_date',
448 'frequency_day',
449 'currency',
450 'max_reminders',
451 'initial_reminder_day',
452 'additional_reminder_day',
453 'frequency_unit',
454 'pledge_contribution_page_id',
455 'pledge_status_id',
456 'pledge_campaign_id',
457 'pledge_financial_type_id',
458 )
459 ),
460 'PaymentProcessorType' => array(
461 'cant_update' => array(
462 'billing_mode',
463 ),
464 'break_return' => array(
465 ),
466 'cant_return' => array(
467 ),
468 ),
469 );
470 if(empty($knownFailures[$entity]) || empty($knownFailures[$entity][$key])){
471 return array();
472 }
473 return $knownFailures[$entity][$key];
474 }
475
476 /** testing the _get **/
477
478 /**
479 * @dataProvider toBeSkipped_get
480 entities that don't need a get action
481 */
482 public function testNotImplemented_get($Entity) {
483 $result = civicrm_api($Entity, 'Get', array('version' => 3));
484 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
485 // $this->assertContains("API ($Entity, Get) does not exist", $result['error_message']);
486 $this->assertRegExp('/API (.*) does not exist/', $result['error_message']);
487 }
488
489 /**
490 * @dataProvider entities
491 * @expectedException PHPUnit_Framework_Error
492 */
493 public function testWithoutParam_get($Entity) {
494 // should get php complaining that a param is missing
495 $result = civicrm_api($Entity, 'Get');
496 }
497
498 /**
499 * @dataProvider entities
500 */
501 public function testGetFields($Entity) {
502 if (in_array($Entity, $this->deprecatedAPI) || $Entity == 'Entity' || $Entity == 'CustomValue' || $Entity == 'MailingGroup') {
503 return;
504 }
505
506 $result = civicrm_api($Entity, 'getfields', array('version' => 3));
507 $this->assertTrue(is_array($result['values']), "$Entity ::get fields doesn't return values array in line " . __LINE__);
508 foreach ($result['values'] as $key => $value) {
509 $this->assertTrue(is_array($value), $Entity . "::" . $key . " is not an array in line " . __LINE__);
510 }
511 }
512
513 /**
514 * @dataProvider entities_get
515 */
516 public function testEmptyParam_get($Entity) {
517
518 if (in_array($Entity, $this->toBeImplemented['get'])) {
519 // $this->markTestIncomplete("civicrm_api3_{$Entity}_get to be implemented");
520 return;
521 }
522 $result = civicrm_api($Entity, 'Get', array());
523 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
524 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
525 }
526 /**
527 * @dataProvider entities_get
528 */
529 public function testEmptyParam_getString($Entity) {
530
531 if (in_array($Entity, $this->toBeImplemented['get'])) {
532 // $this->markTestIncomplete("civicrm_api3_{$Entity}_get to be implemented");
533 return;
534 }
535 $result = $this->callAPIFailure($Entity, 'Get', 'string');
536 $this->assertEquals(2000, $result['error_code']);
537 $this->assertEquals('Input variable `params` is not an array', $result['error_message']);
538 }
539 /**
540 * @dataProvider entities_get
541 * @Xdepends testEmptyParam_get // no need to test the simple if the empty doesn't work/is skipped. doesn't seem to work
542 */
543 public function testSimple_get($Entity) {
544 // $this->markTestSkipped("test gives core error on test server (but not on our locals). Skip until we can get server to pass");
545 if (in_array($Entity, $this->toBeImplemented['get'])) {
546 return;
547 }
548 $result = civicrm_api($Entity, 'Get', array('version' => 3));
549 // @TODO: list the get that have mandatory params
550 if ($result['is_error']) {
551 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
552 // either id or contact_id or entity_id is one of the field missing
553 $this->assertContains("id", $result['error_message']);
554 }
555 else {
556 $this->assertEquals(3, $result['version']);
557 $this->assertArrayHasKey('count', $result);
558 $this->assertArrayHasKey('values', $result);
559 }
560 }
561
562 /**
563 * @dataProvider custom_data_entities_get
564 */
565 public function testCustomDataGet($entityName) {
566 $this->createLoggedInUser();// so subsidiary activities are created
567 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, $entityName . 'Test.php');
568 $customFieldName = 'custom_' . $ids['custom_field_id'];
569 $objects = $this->getMockableBAOObjects($entityName, 1);
570 $params = array('id' => $objects[0]->id, 'custom_' . $ids['custom_field_id'] => "custom string");
571 $result = $this->callAPISuccess($entityName, 'create', $params);
572
573 $getParams = array('id' => $result['id'], 'return' => array($customFieldName));
574 $check = $this->callAPISuccess($entityName, 'get', $getParams);
575 $this->assertEquals("custom string", $check['values'][$check['id']][$customFieldName]);
576
577 $this->customFieldDelete($ids['custom_field_id']);
578 $this->customGroupDelete($ids['custom_group_id']);
579 $this->callAPISuccess($entityName, 'delete', array('id' => $result['id']));
580 }
581
582 /**
583 * @dataProvider entities_get
584 */
585 public function testAcceptsOnlyID_get($Entity) {
586 // big random number. fun fact: if you multiply it by pi^e, the result is another random number, but bigger ;)
587 $nonExistantID = 30867307034;
588 if (in_array($Entity, $this->toBeImplemented['get'])
589 || in_array($Entity, $this->toBeSkipped_getByID())
590 ) {
591 return;
592 }
593
594 // FIXME
595 // the below function returns different values and hence an early return
596 // we'll fix this once beta1 is released
597 // return;
598
599 $result = civicrm_api($Entity, 'Get', array('version' => 3, 'id' => $nonExistantID));
600
601 if ($result['is_error']) {
602 // just to get a clearer message in the log
603 $this->assertEquals("only id should be enough", $result['error_message']);
604 }
605 if (!in_array($Entity, $this->onlyIDNonZeroCount['get'])) {
606 $this->assertEquals(0, $result['count']);
607 }
608 }
609
610 /**
611 * Create two entities and make sure we can fetch them individually by ID
612 *
613 * @dataProvider entities_get
614 *
615 * limitations include the problem with avoiding loops when creating test objects -
616 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
617 * Currency - only seems to support US
618 */
619 public function testByID_get($entityName) {
620 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
621 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
622 return;
623 }
624
625 $baos = $this->getMockableBAOObjects($entityName);
626 list($baoObj1, $baoObj2) = $baos;
627
628 // fetch first by ID
629 $result = $this->callAPISuccess($entityName, 'get', array(
630 'id' => $baoObj1->id,
631 ));
632
633 $this->assertTrue(!empty($result['values'][$baoObj1->id]), 'Should find first object by id');
634 $this->assertEquals($baoObj1->id, $result['values'][$baoObj1->id]['id'], 'Should find id on first object');
635 $this->assertEquals(1, count($result['values']));
636
637 // fetch second by ID
638 $result = $this->callAPISuccess($entityName, 'get', array(
639 'id' => $baoObj2->id,
640 ));
641 $this->assertTrue(!empty($result['values'][$baoObj2->id]), 'Should find second object by id');
642 $this->assertEquals($baoObj2->id, $result['values'][$baoObj2->id]['id'], 'Should find id on second object');
643 $this->assertEquals(1, count($result['values']));
644 }
645
646 /**
647 * Ensure that the "get" operation accepts limiting the #result records.
648 *
649 * TODO Consider making a separate entity list ("entities_getlimit")
650 * For the moment, the "entities_updatesingle" list should give a good
651 * sense for which entities support createTestObject
652 *
653 * @dataProvider entities_getlimit
654 *
655 * @param $entityName
656 *
657 * @internal param string $entity
658 */
659 function testLimit($entityName) {
660 $cases = array(); // each case is array(0 => $inputtedApiOptions, 1 => $expectedResultCount)
661 $cases[] = array(
662 array('options' => array('limit' => NULL)),
663 30,
664 'check that a NULL limit returns unlimited',
665 );
666 $cases[] = array(
667 array('options' => array('limit' => FALSE)),
668 30,
669 'check that a FALSE limit returns unlimited',
670 );
671 $cases[] = array(
672 array('options' => array('limit' => 0)),
673 30,
674 'check that a 0 limit returns unlimited',
675 );
676 $cases[] = array(
677 array('options' => array('limit' => 5)),
678 5,
679 'check that a 5 limit returns 5',
680 );
681 $cases[] = array(
682 array(),
683 25,
684 'check that no limit returns 25',
685 );
686
687 $baoString = _civicrm_api3_get_DAO($entityName);
688 if (empty($baoString)) {
689 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
690 return;
691 }
692
693 // make 30 test items -- 30 > 25 (the default limit)
694 $ids = array();
695 for ($i = 0; $i < 30; $i++) {
696 $baoObj = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
697 $ids[] = $baoObj->id;
698 }
699
700 // each case is array(0 => $inputtedApiOptions, 1 => $expectedResultCount)
701 foreach ($cases as $case) {
702 $this->checkLimitAgainstExpected($entityName, $case[0], $case[1], $case[2]);
703
704 //non preferred / legacy syntax
705 if(isset($case[0]['options']['limit'])) {
706 $this->checkLimitAgainstExpected($entityName, array('rowCount' => $case[0]['options']['limit']), $case[1], $case[2]);
707 $this->checkLimitAgainstExpected($entityName, array('option_limit' => $case[0]['options']['limit']), $case[1], $case[2]);
708 $this->checkLimitAgainstExpected($entityName, array('option.limit' => $case[0]['options']['limit']), $case[1], $case[2]);
709 }
710 }
711 foreach ($ids as $id) {
712 CRM_Core_DAO::deleteTestObjects($baoString, array('id' => $id));
713 }
714 $baoObj->free();
715 }
716
717 /**
718 * Check that get fetches an appropriate number of results
719 *
720 * @param string $entityName Name of entity to test
721 * @param unknown $params
722 * @param unknown $limit
723 * @param unknown $message
724 */
725 function checkLimitAgainstExpected($entityName, $params, $limit, $message) {
726 $result = $this->callAPISuccess($entityName, 'get', $params);
727 if($limit == 30) {
728 $this->assertGreaterThanOrEqual($limit, $result['count'], $message);
729 $this->assertGreaterThanOrEqual($limit, $result['count'], $message);
730 }
731 else {
732 $this->assertEquals($limit, $result['count'], $message);
733 $this->assertEquals($limit, count($result['values']), $message);
734 }
735 }
736 /**
737 * Create two entities and make sure we can fetch them individually by ID (e.g. using "contact_id=>2"
738 * or "group_id=>4")
739 *
740 * @dataProvider entities_get
741 *
742 * limitations include the problem with avoiding loops when creating test objects -
743 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
744 * Currency - only seems to support US
745 */
746 public function testByIDAlias_get($entityName) {
747 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
748 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
749 return;
750 }
751
752 $baoString = _civicrm_api3_get_DAO($entityName);
753 if (empty($baoString)) {
754 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
755 return;
756 }
757
758 $idFieldName = _civicrm_api_get_entity_name_from_camel($entityName) . '_id';
759
760 // create entities
761 $baoObj1 = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
762 $this->assertTrue(is_integer($baoObj1->id), 'check first id');
763 $this->deletableTestObjects[$baoString][] = $baoObj1->id;
764 $baoObj2 = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
765 $this->assertTrue(is_integer($baoObj2->id), 'check second id');
766 $this->deletableTestObjects[$baoString][] = $baoObj2->id;
767
768 // fetch first by ID
769 $result = civicrm_api($entityName, 'get', array(
770 'version' => 3,
771 $idFieldName => $baoObj1->id,
772 ));
773 $this->assertAPISuccess($result);
774 $this->assertTrue(!empty($result['values'][$baoObj1->id]), 'Should find first object by id');
775 $this->assertEquals($baoObj1->id, $result['values'][$baoObj1->id]['id'], 'Should find id on first object');
776 $this->assertEquals(1, count($result['values']));
777
778 // fetch second by ID
779 $result = civicrm_api($entityName, 'get', array(
780 'version' => 3,
781 $idFieldName => $baoObj2->id,
782 ));
783 $this->assertAPISuccess($result);
784 $this->assertTrue(!empty($result['values'][$baoObj2->id]), 'Should find second object by id');
785 $this->assertEquals($baoObj2->id, $result['values'][$baoObj2->id]['id'], 'Should find id on second object');
786 $this->assertEquals(1, count($result['values']));
787 }
788
789 /**
790 * @dataProvider entities_get
791 */
792 public function testNonExistantID_get($Entity) {
793 // cf testAcceptsOnlyID_get
794 $nonExistantID = 30867307034;
795 if (in_array($Entity, $this->toBeImplemented['get'])) {
796 return;
797 }
798
799 $result = civicrm_api($Entity, 'Get', array('version' => 3, 'id' => $nonExistantID));
800
801 // redundant with testAcceptsOnlyID_get
802 if ($result['is_error']) {
803 return;
804 }
805
806
807 $this->assertArrayHasKey('version', $result);
808 $this->assertEquals(3, $result['version']);
809 if (!in_array($Entity, $this->onlyIDNonZeroCount['get'])) {
810 $this->assertEquals(0, $result['count']);
811 }
812 }
813
814 /** testing the _create **/
815
816 /**
817 * @dataProvider toBeSkipped_create
818 entities that don't need a create action
819 */
820 public function testNotImplemented_create($Entity) {
821 $result = civicrm_api($Entity, 'Create', array('version' => 3));
822 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
823 $this->assertContains(strtolower("API ($Entity, Create) does not exist"), strtolower($result['error_message']));
824 }
825
826 /**
827 * @dataProvider entities
828 * @expectedException PHPUnit_Framework_Error
829 */
830 public function testWithoutParam_create($Entity) {
831 // should create php complaining that a param is missing
832 $result = civicrm_api($Entity, 'Create');
833 }
834
835 /**
836 * @dataProvider entities_create
837 */
838 public function testEmptyParam_create($Entity) {
839 $this->markTestIncomplete("fixing this test to test the api functions fails on numberous tests
840 which will either create a completely blank entity (batch, participant status) or
841 have a damn good crack at it (e.g mailing job). Marking this as incomplete beats false success");
842 //
843 return;
844 if (in_array($Entity, $this->toBeImplemented['create'])) {
845 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
846 return;
847 }
848 $result = $this->callAPIFailure($Entity, 'Create', array());
849 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
850 }
851
852 /**
853 * @dataProvider entities_create
854 *
855 * Check that create doesn't work with an invalid
856 */
857 public function testInvalidID_create($Entity) {
858 // turn test off for noew
859 $this->markTestIncomplete("Entity [ $Entity ] cannot be mocked - no known DAO");
860 return;
861 if (in_array($Entity, $this->toBeImplemented['create'])) {
862 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
863 return;
864 }
865 $result = $this->callAPIFailure($Entity, 'Create', array('id' => 999));
866 }
867
868 /**
869 * @dataProvider entities
870 */
871 public function testCreateWrongTypeParamTag_create() {
872 $result = civicrm_api("Tag", 'Create', 'this is not a string');
873 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
874 $this->assertEquals("Input variable `params` is not an array", $result['error_message']);
875 }
876
877 /**
878 * @dataProvider entities_updatesingle
879 *
880 * limitations include the problem with avoiding loops when creating test objects -
881 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
882 * Currency - only seems to support US
883 */
884 public function testCreateSingleValueAlter($entityName) {
885 if (in_array($entityName, $this->toBeImplemented['create'])) {
886 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
887 return;
888 }
889
890 $baoString = _civicrm_api3_get_DAO($entityName);
891 $this->assertNotEmpty($baoString, $entityName);
892 $this->assertNotEmpty($entityName, $entityName);
893 $fieldsGet = $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'get'));
894 if($entityName != 'Pledge'){
895 $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'create'));
896 }
897 $fields = $fields['values'];
898 $return = array_keys($fieldsGet['values']);
899 $valuesNotToReturn = $this->getKnownUnworkablesUpdateSingle($entityName, 'break_return');
900 // these can't be requested as return values
901 $entityValuesThatDoNotWork = array_merge(
902 $this->getKnownUnworkablesUpdateSingle($entityName, 'cant_update'),
903 $this->getKnownUnworkablesUpdateSingle($entityName, 'cant_return'),
904 $valuesNotToReturn
905 );
906
907 $return = array_diff($return,$valuesNotToReturn);
908 $baoObj = new CRM_Core_DAO();
909 $baoObj->createTestObject($baoString, array('currency' => 'USD'), 2, 0);
910
911 $getEntities = $this->callAPISuccess($entityName, 'get', array(
912 'sequential' => 1,
913 'return' => $return,
914 'options' => array(
915 'sort' => 'id DESC',
916 'limit' => 2,
917 ),
918 ));
919 // lets use first rather than assume only one exists
920 $entity = $getEntities['values'][0];
921 $entity2 = $getEntities['values'][1];
922 $this->deletableTestObjects[$baoString][] = $entity['id'];
923 $this->deletableTestObjects[$baoString][] = $entity2['id'];
924 foreach ($fields as $field => $specs) {
925 $fieldName = $field;
926 if (!empty($specs['uniquename'])) {
927 $fieldName = $specs['uniquename'];
928 }
929 if ($field == 'currency' || $field == 'id' || $field == strtolower($entityName) . '_id'
930 || in_array($field,$entityValuesThatDoNotWork)) {
931 //@todo id & entity_id are correct but we should fix currency & frequency_day
932 continue;
933 }
934 $this->assertArrayHasKey('type', $specs, "the _spec function for $entityName field $field does not specify the type");
935 switch ($specs['type']) {
936 case CRM_Utils_Type::T_DATE:
937 case CRM_Utils_Type::T_TIMESTAMP:
938 $entity[$fieldName] = '2012-05-20';
939 break;
940 //case CRM_Utils_Type::T_DATETIME:
941
942 case 12:
943 $entity[$fieldName] = '2012-05-20 03:05:20';
944 break;
945
946 case CRM_Utils_Type::T_STRING:
947 case CRM_Utils_Type::T_BLOB:
948 case CRM_Utils_Type::T_MEDIUMBLOB:
949 case CRM_Utils_Type::T_TEXT:
950 case CRM_Utils_Type::T_LONGTEXT:
951 case CRM_Utils_Type::T_EMAIL:
952 $entity[$fieldName] = substr('New String',0, CRM_Utils_Array::Value('maxlength',$specs,100));
953 break;
954
955 case CRM_Utils_Type::T_INT:
956 // probably created with a 1
957 $entity[$fieldName] = '6';
958 if (!empty($specs['FKClassName'])) {
959 if($specs['FKClassName'] == $baoString){
960 $entity[$fieldName] = (string) $entity2['id'];
961 }
962 else{
963 $uniqueName = CRM_Utils_Array::value('uniqueName', $specs);
964 $entity[$fieldName] = (string) empty($entity2[$field]) ? CRM_Utils_Array::value($uniqueName, $entity2) : $entity2[$field];
965 //todo - there isn't always something set here - & our checking on unset values is limited
966 if (empty($entity[$field])) {
967 unset($entity[$field]);
968 }
969 }
970 }
971 break;
972
973 case CRM_Utils_Type::T_BOOLEAN:
974 // probably created with a 1
975 $entity[$fieldName] = '0';
976 break;
977
978 case CRM_Utils_Type::T_FLOAT:
979 case CRM_Utils_Type::T_MONEY:
980 $entity[$field] = '22.75';
981 break;
982
983 case CRM_Utils_Type::T_URL:
984 $entity[$field] = 'warm.beer.com';
985 }
986 if (!empty($specs['pseudoconstant'])) {
987 $options = $this->callAPISuccess($entityName, 'getoptions', array('context' => 'create', 'field' => $field));
988 if (empty($options['values'])) {
989 //eg. pdf_format id doesn't ship with any
990 if(isset($specs['pseudoconstant']['optionGroupName'])) {
991 $optionGroupID = $this->callAPISuccess('option_group', 'getvalue', array('name' => 'pdf_format', 'return' => 'id'));
992 $optionValue = $this->callAPISuccess('option_value', 'create', array('option_group_id' => $optionGroupID, 'label' => 'new option value'));
993 $options['values'][] = $optionValue['id'];
994 }
995 }
996 $entity[$field] = array_rand($options['values']);
997 }
998 $updateParams = array(
999 'id' => $entity['id'],
1000 $field => isset($entity[$field]) ? $entity[$field] : NULL,
1001 );
1002 if(isset($updateParams['financial_type_id']) && $entityName != 'Product') {
1003 //api has special handling on these 2 fields for backward compatibility reasons
1004 $entity['contribution_type_id'] = $updateParams['financial_type_id'];
1005 }
1006
1007 $update = $this->callAPISuccess($entityName, 'create', $updateParams);
1008 $checkParams = array(
1009 'id' => $entity['id'],
1010 'sequential' => 1,
1011 'return' => $return,
1012 'options' => array(
1013 'sort' => 'id DESC',
1014 'limit' => 2,
1015 ),
1016 );
1017
1018 $checkEntity = $this->callAPISuccess($entityName, 'getsingle', $checkParams);
1019 $this->assertAPIArrayComparison($entity, $checkEntity, array(), "checking if $fieldName was correctly updated\n" . print_r(array('update-params' => $updateParams, 'update-result' => $update, 'getsingle-params' => $checkParams, 'getsingle-result' => $checkEntity, 'expected entity' => $entity), TRUE));
1020 }
1021 $baoObj->free();
1022 }
1023
1024 /** testing the _getFields **/
1025
1026 /** testing the _delete **/
1027
1028 /**
1029 * @dataProvider toBeSkipped_delete
1030 entities that don't need a delete action
1031 */
1032 public function testNotImplemented_delete($Entity) {
1033 $nonExistantID = 151416349;
1034 $result = civicrm_api($Entity, 'Delete', array('version' => 3, 'id' => $nonExistantID));
1035 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
1036 $this->assertContains(strtolower("API ($Entity, Delete) does not exist"), strtolower($result['error_message']));
1037 }
1038
1039 /**
1040 * @dataProvider entities
1041 * @expectedException PHPUnit_Framework_Error
1042 */
1043 public function testWithoutParam_delete($Entity) {
1044 // should delete php complaining that a param is missing
1045 $result = civicrm_api($Entity, 'Delete');
1046 }
1047
1048 /**
1049 * @dataProvider entities_delete
1050 */
1051 public function testEmptyParam_delete($Entity) {
1052 if (in_array($Entity, $this->toBeImplemented['delete'])) {
1053 // $this->markTestIncomplete("civicrm_api3_{$Entity}_delete to be implemented");
1054 return;
1055 }
1056 $result = civicrm_api($Entity, 'Delete', array());
1057 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
1058 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
1059 }
1060 /**
1061 * @dataProvider entities_delete
1062 */
1063 public function testInvalidID_delete($Entity) {
1064 // turn test off for now
1065 $this->markTestIncomplete("Entity [ $Entity ] cannot be mocked - no known DAO");
1066 return;
1067 if (in_array($Entity, $this->toBeImplemented['delete'])) {
1068 // $this->markTestIncomplete("civicrm_api3_{$Entity}_delete to be implemented");
1069 return;
1070 }
1071 $result = $this->callAPIFailure($Entity, 'Delete', array('id' => 999));
1072 }
1073 /**
1074 * @dataProvider entities
1075 */
1076 public function testDeleteWrongTypeParamTag_delete() {
1077 $result = civicrm_api("Tag", 'Delete', 'this is not a string');
1078 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
1079 $this->assertEquals("Input variable `params` is not an array", $result['error_message']);
1080 }
1081
1082 /**
1083 * Create two entities and make sure delete action only deletes one!
1084 *
1085 * @dataProvider entities_delete
1086 *
1087 * limitations include the problem with avoiding loops when creating test objects -
1088 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
1089 * Currency - only seems to support US
1090 */
1091 public function testByID_delete($entityName) {
1092 // turn test off for noew
1093 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
1094 return;
1095
1096 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
1097 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
1098 return;
1099 }
1100 $startCount = $this->callAPISuccess($entityName, 'getcount', array());
1101 $createcount = 2;
1102 $baos = $this->getMockableBAOObjects($entityName, $createcount);
1103 list($baoObj1, $baoObj2) = $baos;
1104
1105 // make sure exactly 2 exist
1106 $result = $this->callAPISuccess($entityName, 'getcount', array(),
1107 $createcount + $startCount
1108 );
1109
1110 $this->callAPISuccess($entityName, 'delete', array('id' => $baoObj2->id));
1111 //make sure 1 less exists now
1112 $result = $this->callAPISuccess($entityName, 'getcount', array(),
1113 ($createcount + $startCount) -1
1114 );
1115
1116 //make sure id #1 exists
1117 $result = $this->callAPISuccess($entityName, 'getcount', array('id' => $baoObj1->id),
1118 1
1119 );
1120 //make sure id #2 desn't exist
1121 $result = $this->callAPISuccess($entityName, 'getcount', array('id' => $baoObj2->id),
1122 0
1123 );
1124 }
1125
1126 /**
1127 * Create two entities and make sure delete action only deletes one!
1128 *
1129 * @dataProvider entities_getfields
1130 *
1131 */
1132 public function testGetfieldsHasTitle($entity) {
1133 $entities = $this->getEntitiesSupportingCustomFields();
1134 if (in_array($entity, $entities)) {
1135 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, $entity . 'Test.php');
1136 }
1137 $actions = $this->callAPISuccess($entity, 'getactions', array());
1138 foreach ($actions['values'] as $action) {
1139 if (substr($action, -7) == '_create' || substr($action, -4) == '_get' || substr($action, -7) == '_delete') {
1140 //getactions can't distinguish between contribution_page.create & contribution_page.create
1141 continue;
1142 }
1143 $fields = $this->callAPISuccess($entity, 'getfields', array('action' => $action));
1144 if (!empty($ids) && in_array($action, array('create', 'get'))) {
1145 $this->assertArrayHasKey('custom_' . $ids['custom_field_id'], $fields['values']);
1146 }
1147
1148 foreach ($fields['values'] as $fieldName => $fieldSpec) {
1149 $this->assertArrayHasKey('title', $fieldSpec, "no title for $entity - $fieldName on action $action");
1150 $this->assertNotEmpty($fieldSpec['title'], "empty title for $entity - $fieldName");
1151 }
1152 }
1153 if (!empty($ids)) {
1154 $this->customFieldDelete($ids['custom_field_id']);
1155 $this->customGroupDelete($ids['custom_group_id']);
1156 }
1157 }
1158
1159 /**
1160 * @return array
1161 */
1162 public function getEntitiesSupportingCustomFields() {
1163 $entities = self::custom_data_entities_get();
1164 $returnEntities = array();
1165 foreach ($entities as $entityArray) {
1166 $returnEntities[] = $entityArray[0];
1167 }
1168 return $returnEntities;
1169 }
1170 /**
1171 * @param $entityName
1172 * @param int $count
1173 *
1174 * @internal param $entityName
1175 *
1176 * @return array
1177 */
1178 private function getMockableBAOObjects($entityName, $count = 2) {
1179 $baoString = _civicrm_api3_get_DAO($entityName);
1180 if (empty($baoString)) {
1181 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
1182 return;
1183 }
1184 $baos = array();
1185 $i = 0;
1186 while($i < $count) {
1187 // create entities
1188 $baoObj = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
1189 $this->assertTrue(is_integer($baoObj->id), 'check first id');
1190 $this->deletableTestObjects[$baoString][] = $baoObj->id;
1191 $baos[] = $baoObj;
1192 $i ++;
1193 }
1194 return $baos;
1195 }
1196
1197
1198 /**
1199 * Verify that HTML metacharacters provided as inputs appear consistently
1200 * as outputs.
1201 *
1202 * At time of writing, the encoding scheme requires (for example) that an
1203 * event title be partially-HTML-escaped before writing to DB. To provide
1204 * consistency, the API must perform extra encoding and decoding on some
1205 * fields.
1206 *
1207 * In this example, the event 'title' is subject to encoding, but the
1208 * event 'description' is not.
1209 */
1210 public function testEncodeDecodeConsistency() {
1211 // Create example
1212 $createResult = civicrm_api('Event', 'Create', array(
1213 'version' => 3,
1214 'title' => 'CiviCRM <> TheRest',
1215 'description' => 'TheRest <> CiviCRM',
1216 'event_type_id' => 1,
1217 'is_public' => 1,
1218 'start_date' => 20081021,
1219 ));
1220 $this->assertAPISuccess($createResult);
1221 $eventId = $createResult['id'];
1222 $this->assertEquals('CiviCRM <> TheRest', $createResult['values'][$eventId]['title']);
1223 $this->assertEquals('TheRest <> CiviCRM', $createResult['values'][$eventId]['description']);
1224
1225 // Verify "get" handles decoding in result value
1226 $getByIdResult = civicrm_api('Event', 'Get', array(
1227 'version' => 3,
1228 'id' => $eventId,
1229 ));
1230 $this->assertAPISuccess($getByIdResult);
1231 $this->assertEquals('CiviCRM <> TheRest', $getByIdResult['values'][$eventId]['title']);
1232 $this->assertEquals('TheRest <> CiviCRM', $getByIdResult['values'][$eventId]['description']);
1233
1234 // Verify "get" handles encoding in search value
1235 $getByTitleResult = civicrm_api('Event', 'Get', array(
1236 'version' => 3,
1237 'title' => 'CiviCRM <> TheRest',
1238 ));
1239 $this->assertAPISuccess($getByTitleResult);
1240 $this->assertEquals('CiviCRM <> TheRest', $getByTitleResult['values'][$eventId]['title']);
1241 $this->assertEquals('TheRest <> CiviCRM', $getByTitleResult['values'][$eventId]['description']);
1242
1243 // Verify that "getSingle" handles decoding
1244 $getSingleResult = $this->callAPISuccess('Event', 'GetSingle', array(
1245 'id' => $eventId,
1246 ));
1247
1248 $this->assertEquals('CiviCRM <> TheRest', $getSingleResult['title']);
1249 $this->assertEquals('TheRest <> CiviCRM', $getSingleResult['description']);
1250
1251 // Verify that chaining handles decoding
1252 $chainResult = $this->callAPISuccess('Event', 'Get', array(
1253 'id' => $eventId,
1254 'api.event.get' => array(
1255 ),
1256 ));
1257 $this->assertEquals('CiviCRM <> TheRest', $chainResult['values'][$eventId]['title']);
1258 $this->assertEquals('TheRest <> CiviCRM', $chainResult['values'][$eventId]['description']);
1259 $this->assertEquals('CiviCRM <> TheRest', $chainResult['values'][$eventId]['api.event.get']['values'][0]['title']);
1260 $this->assertEquals('TheRest <> CiviCRM', $chainResult['values'][$eventId]['api.event.get']['values'][0]['description']);
1261
1262 // Verify that "setvalue" handles encoding for updates
1263 $setValueTitleResult = civicrm_api('Event', 'setvalue', array(
1264 'version' => 3,
1265 'id' => $eventId,
1266 'field' => 'title',
1267 'value' => 'setValueTitle: CiviCRM <> TheRest',
1268 ));
1269 $this->assertAPISuccess($setValueTitleResult);
1270 $this->assertEquals('setValueTitle: CiviCRM <> TheRest', $setValueTitleResult['values']['title']);
1271 $setValueDescriptionResult = civicrm_api('Event', 'setvalue', array(
1272 'version' => 3,
1273 'id' => $eventId,
1274 'field' => 'description',
1275 'value' => 'setValueDescription: TheRest <> CiviCRM',
1276 ));
1277 //$this->assertTrue((bool)$setValueDescriptionResult['is_error']); // not supported by setValue
1278 $this->assertEquals('setValueDescription: TheRest <> CiviCRM', $setValueDescriptionResult['values']['description']);
1279 }
1280
1281 /**
1282 * Verify that write operations (create/update) use partial HTML-encoding
1283 *
1284 * In this example, the event 'title' is subject to encoding, but the
1285 * event 'description' is not.
1286 */
1287 public function testEncodeWrite() {
1288 // Create example
1289 $createResult = civicrm_api('Event', 'Create', array(
1290 'version' => 3,
1291 'title' => 'createNew: CiviCRM <> TheRest',
1292 'description' => 'createNew: TheRest <> CiviCRM',
1293 'event_type_id' => 1,
1294 'is_public' => 1,
1295 'start_date' => 20081021,
1296 ));
1297 $this->assertAPISuccess($createResult);
1298 $eventId = $createResult['id'];
1299 $this->assertDBQuery('createNew: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
1300 1 => array($eventId, 'Integer')
1301 ));
1302 $this->assertDBQuery('createNew: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
1303 1 => array($eventId, 'Integer')
1304 ));
1305
1306 // Verify that "create" handles encoding for updates
1307 $createWithIdResult = civicrm_api('Event', 'Create', array(
1308 'version' => 3,
1309 'id' => $eventId,
1310 'title' => 'createWithId: CiviCRM <> TheRest',
1311 'description' => 'createWithId: TheRest <> CiviCRM',
1312 ));
1313 $this->assertAPISuccess($createWithIdResult);
1314 $this->assertDBQuery('createWithId: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
1315 1 => array($eventId, 'Integer')
1316 ));
1317 $this->assertDBQuery('createWithId: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
1318 1 => array($eventId, 'Integer')
1319 ));
1320
1321 // Verify that "setvalue" handles encoding for updates
1322 $setValueTitleResult = civicrm_api('Event', 'setvalue', array(
1323 'version' => 3,
1324 'id' => $eventId,
1325 'field' => 'title',
1326 'value' => 'setValueTitle: CiviCRM <> TheRest',
1327 ));
1328 $this->assertAPISuccess($setValueTitleResult);
1329 $this->assertDBQuery('setValueTitle: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
1330 1 => array($eventId, 'Integer')
1331 ));
1332 $setValueDescriptionResult = civicrm_api('Event', 'setvalue', array(
1333 'version' => 3,
1334 'id' => $eventId,
1335 'field' => 'description',
1336 'value' => 'setValueDescription: TheRest <> CiviCRM',
1337 ));
1338 //$this->assertTrue((bool)$setValueDescriptionResult['is_error']); // not supported by setValue
1339 $this->assertAPISuccess($setValueDescriptionResult);
1340 $this->assertDBQuery('setValueDescription: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
1341 1 => array($eventId, 'Integer')
1342 ));
1343 }
1344 }