Merge pull request #1474 from yashodha/CRM-13233
[civicrm-core.git] / tests / phpunit / api / v3 / SyntaxConformanceTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
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(static::toBeSkipped_get(TRUE));
94 }
95
96 public static function entities_create() {
97 return api_v3_SyntaxConformanceTest::entities(static::toBeSkipped_create(TRUE));
98 }
99
100 public static function entities_updatesingle() {
101 return api_v3_SyntaxConformanceTest::entities(static::toBeSkipped_updatesingle(TRUE));
102 }
103
104 public static function entities_delete() {
105 return api_v3_SyntaxConformanceTest::entities(static::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_BOOLEAN:
704 // probably created with a 1
705 $entity[$fieldName] = '0';
706 break;
707
708 case CRM_Utils_Type::T_FLOAT:
709 case CRM_Utils_Type::T_MONEY:
710 $entity[$field] = '222';
711 break;
712
713 case CRM_Utils_Type::T_URL:
714 $entity[$field] = 'warm.beer.com';
715 }
716 if (!empty($specs['pseudoconstant']) || !empty($specs['enumValues'])) {
717 $options = civicrm_api($entityName, 'getoptions', array('context' => 'create', 'field' => $field, 'version' => 3));
718 if (empty($options['values'])) {
719 }
720 $entity[$field] = array_rand($options['values']);
721 }
722 $updateParams = array(
723 'version' => 3,
724 'id' => $entity['id'],
725 $field => $entity[$field],
726 );
727
728 $update = $this->callAPISuccess($entityName, 'create', $updateParams);
729 $checkParams = array(
730 'id' => $entity['id'],
731 'version' => 3,
732 'sequential' => 1,
733 'return' => $return,
734 'options' => array(
735 'sort' => 'id DESC',
736 'limit' => 2,
737 ),
738 );
739
740 $checkEntity = $this->callAPISuccess($entityName, 'getsingle', $checkParams);
741 $this->assertAPIArrayComparison($entity, $checkEntity, array(), "changing field $fieldName\n");
742 //print_r(array('update-params' => $updateParams, 'update-result' => $update, 'getsingle-params' => $checkParams, 'getsingle-result' => $checkEntity, 'expected entity' => $entity), TRUE)
743
744 }
745 $baoObj->deleteTestObjects($baoString);
746 $baoObj->free();
747 }
748
749 /** testing the _getFields **/
750
751 /** testing the _delete **/
752
753 /**
754 * @dataProvider toBeSkipped_delete
755 entities that don't need a delete action
756 */
757 public function testNotImplemented_delete($Entity) {
758 $nonExistantID = 151416349;
759 $result = civicrm_api($Entity, 'Delete', array('version' => 3, 'id' => $nonExistantID));
760 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
761 $this->assertContains("API ($Entity,Delete) does not exist", $result['error_message']);
762 }
763
764 /**
765 * @dataProvider entities
766 * @expectedException PHPUnit_Framework_Error
767 */
768 public function testWithoutParam_delete($Entity) {
769 // should delete php complaining that a param is missing
770 $result = civicrm_api($Entity, 'Delete');
771 }
772
773 /**
774 * @dataProvider entities_delete
775 */
776 public function testEmptyParam_delete($Entity) {
777 if (in_array($Entity, $this->toBeImplemented['delete'])) {
778 // $this->markTestIncomplete("civicrm_api3_{$Entity}_delete to be implemented");
779 return;
780 }
781 $result = civicrm_api($Entity, 'Delete', array());
782 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
783 $this->assertContains("Mandatory key(s) missing from params array", $result['error_message']);
784 }
785 /**
786 * @dataProvider entities_delete
787 */
788 public function testInvalidID_delete($Entity) {
789 // turn test off for noew
790 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
791 return;
792 if (in_array($Entity, $this->toBeImplemented['delete'])) {
793 // $this->markTestIncomplete("civicrm_api3_{$Entity}_delete to be implemented");
794 return;
795 }
796 $result = $this->callAPIFailure($Entity, 'Delete', array('id' => 999));
797 }
798 /**
799 * @dataProvider entities
800 */
801 public function testDeleteWrongTypeParamTag_delete() {
802 $result = civicrm_api("Tag", 'Delete', 'this is not a string');
803 $this->assertEquals(1, $result['is_error'], 'In line ' . __LINE__);
804 $this->assertEquals("Input variable `params` is not an array", $result['error_message']);
805 }
806
807 /**
808 * Create two entities and make sure delete action only deletes one!
809 *
810 * @dataProvider entities_delete
811 *
812 * limitations include the problem with avoiding loops when creating test objects -
813 * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
814 * Currency - only seems to support US
815 */
816 public function testByID_delete($entityName) {
817 // turn test off for noew
818 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
819 return;
820
821 if (in_array($entityName, self::toBeSkipped_automock(TRUE))) {
822 // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
823 return;
824 }
825 $startCount = $this->callAPISuccess($entityName, 'getcount', array());
826 $createcount = 2;
827 $baos = $this->getMockableBAOObjects($entityName, $createcount);
828 list($baoObj1, $baoObj2) = $baos;
829
830 // make sure exactly 2 exist
831 $result = $this->callAPISuccess($entityName, 'getcount', array(),
832 $createcount + $startCount
833 );
834
835 $this->callAPISuccess($entityName, 'delete', array('id' => $baoObj2->id));
836 //make sure 1 less exists now
837 $result = $this->callAPISuccess($entityName, 'getcount', array(),
838 ($createcount + $startCount) -1
839 );
840
841 //make sure id #1 exists
842 $result = $this->callAPISuccess($entityName, 'getcount', array('id' => $baoObj1->id),
843 1
844 );
845 //make sure id #2 desn't exist
846 $result = $this->callAPISuccess($entityName, 'getcount', array('id' => $baoObj2->id),
847 0
848 );
849 }
850
851 /**
852 * @param entityName
853 */private function getMockableBAOObjects($entityName, $count = 2) {
854 $baoString = _civicrm_api3_get_DAO($entityName);
855 if (empty($baoString)) {
856 $this->markTestIncomplete("Entity [$entityName] cannot be mocked - no known DAO");
857 return;
858 }
859 $baos = array();
860 while($i < $count) {
861 // create entities
862 $baoObj = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD'));
863 $this->assertTrue(is_integer($baoObj->id), 'check first id');
864 $this->deletableTestObjects[$baoString][] = $baoObj->id;
865 $baos[] = $baoObj;
866 $i ++;
867 }
868 return $baos;
869 }
870
871
872 /**
873 * Verify that HTML metacharacters provided as inputs appear consistently
874 * as outputs.
875 *
876 * At time of writing, the encoding scheme requires (for example) that an
877 * event title be partially-HTML-escaped before writing to DB. To provide
878 * consistency, the API must perform extra encoding and decoding on some
879 * fields.
880 *
881 * In this example, the event 'title' is subject to encoding, but the
882 * event 'description' is not.
883 */
884 public function testEncodeDecodeConsistency() {
885 // Create example
886 $createResult = civicrm_api('Event', 'Create', array(
887 'version' => 3,
888 'title' => 'CiviCRM <> TheRest',
889 'description' => 'TheRest <> CiviCRM',
890 'event_type_id' => 1,
891 'is_public' => 1,
892 'start_date' => 20081021,
893 ));
894 $this->assertAPISuccess($createResult);
895 $eventId = $createResult['id'];
896 $this->assertEquals('CiviCRM <> TheRest', $createResult['values'][$eventId]['title']);
897 $this->assertEquals('TheRest <> CiviCRM', $createResult['values'][$eventId]['description']);
898
899 // Verify "get" handles decoding in result value
900 $getByIdResult = civicrm_api('Event', 'Get', array(
901 'version' => 3,
902 'id' => $eventId,
903 ));
904 $this->assertAPISuccess($getByIdResult);
905 $this->assertEquals('CiviCRM <> TheRest', $getByIdResult['values'][$eventId]['title']);
906 $this->assertEquals('TheRest <> CiviCRM', $getByIdResult['values'][$eventId]['description']);
907
908 // Verify "get" handles encoding in search value
909 $getByTitleResult = civicrm_api('Event', 'Get', array(
910 'version' => 3,
911 'title' => 'CiviCRM <> TheRest',
912 ));
913 $this->assertAPISuccess($getByTitleResult);
914 $this->assertEquals('CiviCRM <> TheRest', $getByTitleResult['values'][$eventId]['title']);
915 $this->assertEquals('TheRest <> CiviCRM', $getByTitleResult['values'][$eventId]['description']);
916
917 // Verify that "getSingle" handles decoding
918 $getSingleResult = civicrm_api('Event', 'GetSingle', array(
919 'version' => 3,
920 'id' => $eventId,
921 ));
922
923 $this->assertAPISuccess($getSingleResult);
924 $this->assertEquals('CiviCRM <> TheRest', $getSingleResult['title']);
925 $this->assertEquals('TheRest <> CiviCRM', $getSingleResult['description']);
926
927 // Verify that chaining handles decoding
928 $chainResult = civicrm_api('Event', 'Get', array(
929 'version' => 3,
930 'id' => $eventId,
931 'api.event.get' => array(
932 ),
933 ));
934 $this->assertEquals('CiviCRM <> TheRest', $chainResult['values'][$eventId]['title']);
935 $this->assertEquals('TheRest <> CiviCRM', $chainResult['values'][$eventId]['description']);
936 $this->assertEquals('CiviCRM <> TheRest', $chainResult['values'][$eventId]['api.event.get']['values'][0]['title']);
937 $this->assertEquals('TheRest <> CiviCRM', $chainResult['values'][$eventId]['api.event.get']['values'][0]['description']);
938
939 // Verify that "setvalue" handles encoding for updates
940 $setValueTitleResult = civicrm_api('Event', 'setvalue', array(
941 'version' => 3,
942 'id' => $eventId,
943 'field' => 'title',
944 'value' => 'setValueTitle: CiviCRM <> TheRest',
945 ));
946 $this->assertAPISuccess($setValueTitleResult);
947 $this->assertEquals('setValueTitle: CiviCRM <> TheRest', $setValueTitleResult['values']['title']);
948 $setValueDescriptionResult = civicrm_api('Event', 'setvalue', array(
949 'version' => 3,
950 'id' => $eventId,
951 'field' => 'description',
952 'value' => 'setValueDescription: TheRest <> CiviCRM',
953 ));
954 $this->assertTrue((bool)$setValueDescriptionResult['is_error']); // not supported by setValue
955 //$this->assertAPISuccess($setValueDescriptionResult);
956 //$this->assertEquals('setValueDescription: TheRest <> CiviCRM', $setValueDescriptionResult['values']['description']);
957 }
958
959 /**
960 * Verify that write operations (create/update) use partial HTML-encoding
961 *
962 * In this example, the event 'title' is subject to encoding, but the
963 * event 'description' is not.
964 */
965 public function testEncodeWrite() {
966 // Create example
967 $createResult = civicrm_api('Event', 'Create', array(
968 'version' => 3,
969 'title' => 'createNew: CiviCRM <> TheRest',
970 'description' => 'createNew: TheRest <> CiviCRM',
971 'event_type_id' => 1,
972 'is_public' => 1,
973 'start_date' => 20081021,
974 ));
975 $this->assertAPISuccess($createResult);
976 $eventId = $createResult['id'];
977 $this->assertDBQuery('createNew: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
978 1 => array($eventId, 'Integer')
979 ));
980 $this->assertDBQuery('createNew: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
981 1 => array($eventId, 'Integer')
982 ));
983
984 // Verify that "create" handles encoding for updates
985 $createWithIdResult = civicrm_api('Event', 'Create', array(
986 'version' => 3,
987 'id' => $eventId,
988 'title' => 'createWithId: CiviCRM <> TheRest',
989 'description' => 'createWithId: TheRest <> CiviCRM',
990 ));
991 $this->assertAPISuccess($createWithIdResult);
992 $this->assertDBQuery('createWithId: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
993 1 => array($eventId, 'Integer')
994 ));
995 $this->assertDBQuery('createWithId: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
996 1 => array($eventId, 'Integer')
997 ));
998
999 // Verify that "setvalue" handles encoding for updates
1000 $setValueTitleResult = civicrm_api('Event', 'setvalue', array(
1001 'version' => 3,
1002 'id' => $eventId,
1003 'field' => 'title',
1004 'value' => 'setValueTitle: CiviCRM <> TheRest',
1005 ));
1006 $this->assertAPISuccess($setValueTitleResult);
1007 $this->assertDBQuery('setValueTitle: CiviCRM &lt;&gt; TheRest', 'SELECT title FROM civicrm_event WHERE id = %1', array(
1008 1 => array($eventId, 'Integer')
1009 ));
1010 $setValueDescriptionResult = civicrm_api('Event', 'setvalue', array(
1011 'version' => 3,
1012 'id' => $eventId,
1013 'field' => 'description',
1014 'value' => 'setValueDescription: TheRest <> CiviCRM',
1015 ));
1016 $this->assertTrue((bool)$setValueDescriptionResult['is_error']); // not supported by setValue
1017 //$this->assertAPISuccess($setValueDescriptionResult);
1018 //$this->assertDBQuery('setValueDescription: TheRest <> CiviCRM', 'SELECT description FROM civicrm_event WHERE id = %1', array(
1019 // 1 => array($eventId, 'Integer')
1020 //));
1021 }
1022
1023 }