abdd21b36eb514ccdc38ac3a6e81f69e6e7da60e
[tine20] / tests / tine20 / Crm / JsonTest.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Crm
6  * @license     http://www.gnu.org/licenses/agpl.html
7  * @copyright   Copyright (c) 2008-2014 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Philipp Schüle <p.schuele@metaways.de>
9  * 
10  */
11
12 /**
13  * Test helper
14  */
15 require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
16
17 /**
18  * Test class for Crm_Json
19  */
20 class Crm_JsonTest extends Crm_AbstractTest
21 {
22     /**
23      * @var array test objects
24      */
25     protected $_objects = array();
26     
27     /**
28      * Backend
29      *
30      * @var Crm_Frontend_Json
31      */
32     protected $_instance;
33     
34     /**
35      * fs controller
36      *
37      * @var Tinebase_FileSystem
38      */
39     protected $_fsController;
40
41    /**
42      * Sets up the fixture.
43      * This method is called before a test is executed.
44      *
45      * @access protected
46      */
47     protected function setUp()
48     {
49         parent::setUp();
50         
51         $this->_instance = new Crm_Frontend_Json();
52         $this->_fsController = Tinebase_FileSystem::getInstance();
53     }
54
55     /**
56      * Tears down the fixture
57      * This method is called after a test is executed.
58      *
59      * @access protected
60      */
61     protected function tearDown()
62     {
63         if (isset($this->_objects['paths'])) {
64             foreach ($this->_objects['paths'] as $path) {
65                 try {
66                     $this->_fsController->rmdir($path, TRUE);
67                 } catch (Tinebase_Exception_NotFound $tenf) {
68                     // already deleted
69                 }
70             }
71         }
72         
73         parent::tearDown();
74     }
75      
76     /**
77      * test get crm registry
78      * 
79      * @return void
80      */
81     public function testGetRegistryData()
82     {
83         $registry = $this->_instance->getRegistryData();
84         
85         $types = array('leadtypes', 'leadstates', 'leadsources');
86         
87         // check data
88         foreach ($types as $type) {
89             $this->assertGreaterThan(0, $registry[$type]['totalcount']);
90             $this->assertGreaterThan(0, count($registry[$type]['results']));
91         }
92         
93         // check defaults
94         $this->assertEquals(array(
95             'leadstate_id'  => 1,
96             'leadtype_id'   => 1,
97             'leadsource_id' => 1,
98         ), array(
99             'leadstate_id' => $registry['defaults']['leadstate_id'],
100             'leadtype_id' => $registry['defaults']['leadtype_id'],
101             'leadsource_id' => $registry['defaults']['leadsource_id'],
102         ));
103         $this->assertEquals(
104             Tinebase_Container::getInstance()->getDefaultContainer('Crm')->getId(),
105             $registry['defaults']['container_id']['id']
106         );
107         //print_r($registry);
108     }
109     
110     /**
111      * test get settings/config
112      * 
113      * @return void
114      */
115     public function testGetSettings()
116     {
117         $result = $this->_instance->getSettings();
118         
119         $this->assertArrayHasKey('leadstates',  $result);
120         $this->assertArrayHasKey('leadtypes',   $result);
121         $this->assertArrayHasKey('leadsources', $result);
122         $this->assertArrayHasKey('defaults',    $result);
123         $this->assertEquals(6, count($result[Crm_Model_Config::LEADSTATES]));
124         $this->assertEquals(3, count($result[Crm_Model_Config::LEADTYPES]));
125         $this->assertEquals(4, count($result[Crm_Model_Config::LEADSOURCES]));
126     }
127     
128     /**
129      * test get settings/config
130      * 
131      * @return void
132      */
133     public function testSaveSettings()
134     {
135         $oldSettings = $this->_instance->getSettings();
136         
137         // change some settings
138         $newSettings = $oldSettings;
139         $newSettings['defaults']['leadstate_id'] = 2;
140         $newSettings['leadsources'][] = array(
141             'id' => 5,
142             'leadsource' => 'Another Leadsource'
143         );
144         $anotherResult = $this->_instance->saveSettings($newSettings);
145         $this->assertEquals($newSettings, $anotherResult, 'new settings have not been saved');
146         
147         // reset original settings
148         $result = $this->_instance->saveSettings($oldSettings);
149         $this->assertEquals($result, $oldSettings, 'old settings have not been reset');
150         
151         // test Crm_Model_Config::getOptionById
152         $settings = Crm_Controller::getInstance()->getConfigSettings();
153         $this->assertEquals(array(), $settings->getOptionById(5, 'leadsources'), 'Crm_Model_Config::getOptionById failed');
154     }
155     
156     /**
157      * try to add/search/delete a lead with linked contact, task and product
158      * 
159      * @see 0007214: if lead with linked task is saved, alarm is discarded
160      */
161     public function testAddGetSearchDeleteLead()
162     {
163         $savedLead = $this->_saveLead();
164         $getLead = $this->_instance->getLead($savedLead['id']);
165         $searchLeads = $this->_instance->searchLeads($this->_getLeadFilter(), '');
166         
167         // assertions
168         $this->assertEquals($getLead, $savedLead);
169         $this->assertEquals($getLead['notes'][0]['note'], 'phpunit test note');
170         $this->assertTrue($searchLeads['totalcount'] > 0);
171         $this->assertTrue(isset($searchLeads['totalleadstates']) && count($searchLeads['totalleadstates']) > 0);
172         $this->assertEquals($getLead['description'], $searchLeads['results'][0]['description']);
173         $this->assertEquals(200, $searchLeads['results'][0]['turnover'], 'turnover has not been calculated using product prices');
174         $this->assertEquals($searchLeads['results'][0]['turnover']*$getLead['probability']/100, $searchLeads['results'][0]['probableTurnover']);
175         $this->assertTrue(count($searchLeads['results'][0]['relations']) == 3, 'did not get all relations');
176
177         // get related records and check relations
178         foreach ($searchLeads['results'][0]['relations'] as $relation) {
179             switch ($relation['type']) {
180                 case 'PRODUCT':
181                     //print_r($relation);
182                     $this->assertEquals(200, $relation['remark']['price'], 'product price (remark) does not match');
183                     $relatedProduct = $relation['related_record'];
184                     break;
185                 case 'TASK':
186                     $relatedTask = $relation['related_record'];
187                     break;
188                 case 'PARTNER':
189                     $relatedContact = $relation['related_record'];
190                     break;
191             }
192         }
193         $this->assertTrue(isset($relatedContact), 'contact not found');
194         $this->assertEquals($this->_getContact()->n_fn, $relatedContact['n_fn'], 'contact name does not match');
195         
196         $this->assertTrue(isset($relatedTask), 'task not found');
197         $this->assertEquals($this->_getTask()->summary, $relatedTask['summary'], 'task summary does not match');
198         $defaultTaskContainerId = Tinebase_Core::getPreference('Tasks')->getValue(Tasks_Preference::DEFAULTTASKLIST);
199         $this->assertEquals($defaultTaskContainerId, $relatedTask['container_id']);
200         $this->assertTrue(isset($relatedTask['alarms']) && count($relatedTask['alarms']) === 1, 'alarm missing in related task: ' . print_r($relatedTask, TRUE));
201         
202         $this->assertTrue(isset($relatedProduct), 'product not found');
203         $this->assertEquals($this->_getProduct()->name, $relatedProduct['name'], 'product name does not match');
204         
205         // delete all
206         $this->_instance->deleteLeads($savedLead['id']);
207         Addressbook_Controller_Contact::getInstance()->delete($relatedContact['id']);
208         Sales_Controller_Product::getInstance()->delete($relatedProduct['id']);
209         
210         // check if delete worked
211         $result = $this->_instance->searchLeads($this->_getLeadFilter(), '');
212         $this->assertEquals(0, $result['totalcount']);
213         
214         // check if linked task got removed as well
215         $this->setExpectedException('Tinebase_Exception_NotFound');
216         Tasks_Controller_Task::getInstance()->get($relatedTask['id']);
217     }
218     
219     /**
220      * save lead with relations
221      * 
222      * @return array
223      */
224     protected function _saveLead()
225     {
226         $contact    = $this->_getContact();
227         $task       = $this->_getTask();
228         $lead       = $this->_getLead();
229         $product    = $this->_getProduct();
230         $price      = 200;
231         
232         $leadData = $lead->toArray();
233         $leadData['relations'] = array(
234             array('type'  => 'TASK',    'related_record' => $task->toArray()),
235             array('type'  => 'PARTNER', 'related_record' => $contact->toArray()),
236             array('type'  => 'PRODUCT', 'related_record' => $product->toArray(), 'remark' => array('price' => $price)),
237         );
238         // add note
239         $note = array(
240             'note_type_id'      => 1,
241             'note'              => 'phpunit test note',
242         );
243         $leadData['notes'] = array($note);
244         
245         $savedLead = $this->_instance->saveLead($leadData);
246         return $savedLead;
247     }
248     
249     /**
250      * test tag filter (adds a contact with the same id + tag)
251      * 
252      * see bug #4834 (http://forge.tine20.org/mantisbt/view.php?id=4834)
253      */
254     public function testTagFilter()
255     {
256         $lead       = $this->_getLead();
257         $savedLead = $this->_instance->saveLead($lead->toArray());
258         
259         $sharedTagName = Tinebase_Record_Abstract::generateUID();
260         $tag = new Tinebase_Model_Tag(array(
261             'type'  => Tinebase_Model_Tag::TYPE_SHARED,
262             'name'  => $sharedTagName,
263             'description' => 'testTagFilter',
264             'color' => '#009B31',
265         ));
266         $contact    = $this->_getContact();
267         $contact->setId($savedLead['id']);
268         
269         $contact->tags = array($tag);
270         $savedContact = Addressbook_Controller_Contact::getInstance()->create($contact, FALSE);
271         $tag = $savedContact->tags->getFirstRecord();
272         
273         $filter = array(
274             array('field' => 'tag',           'operator' => 'equals',       'value' => $tag->getId()),
275         );
276         
277         $result = $this->_instance->searchLeads($filter, array());
278         $this->assertEquals(0, $result['totalcount'], 'Should not find the lead!');
279     }    
280     
281     /**
282      * testSearchByBrokenFilter
283      * 
284      * @see 0005990: cardinality violation when searching for leads / http://forge.tine20.org/mantisbt/view.php?id=5990
285      */
286     public function testSearchByBrokenFilter()
287     {
288         $filter = Zend_Json::decode('[{"field":"query","operator":"contains","value":"test"},{"field":"container_id","operator":"equals","value":{"path":"/"}},{"field":"contact","operator":"AND","value":[{"field":":id","operator":"equals","value":{"n_fn":"","n_fileas":"","org_name":"","container_id":"2576"}}]}]');
289         $result = $this->_instance->searchLeads($filter, array());
290         $this->assertEquals(0, $result['totalcount']);
291     }
292     
293     /**
294      * add relation, remove relation and add relation again
295      * 
296      * see bug #4840 (http://forge.tine20.org/mantisbt/view.php?id=4840)
297      */
298     public function testAddRelationAgain()
299     {
300         $contact    = $this->_getContact();
301         $savedContact = Addressbook_Controller_Contact::getInstance()->create($contact, FALSE);
302         $lead       = $this->_getLead();
303         
304         $leadData = $lead->toArray();
305         $leadData['relations'] = array(
306             array('type'  => 'PARTNER', 'related_record' => $savedContact->toArray()),
307         );
308         $savedLead = $this->_instance->saveLead($leadData);
309         
310         $savedLead['relations'] = array();
311         $savedLead = $this->_instance->saveLead($savedLead);
312         $this->assertEquals(0, count($savedLead['relations']));
313         
314         $savedLead['relations'] = array(
315             array('type'  => 'PARTNER', 'related_record' => $savedContact->toArray()),
316         );
317         $savedLead = $this->_instance->saveLead($savedLead);
318         
319         $this->assertEquals(1, count($savedLead['relations']), 'Relation has not been added');
320         $this->assertEquals($contact->n_fn, $savedLead['relations'][0]['related_record']['n_fn'], 'Contact name does not match');
321     }
322     
323     /**
324      * testRelationWithoutType
325      * 
326      * @see 0006206: relation type field can be empty
327      */
328     public function testRelationWithoutType()
329     {
330         $contact      = $this->_getContact();
331         $savedContact = Addressbook_Controller_Contact::getInstance()->create($contact, FALSE);
332         $lead         = $this->_getLead();
333         
334         $leadData = $lead->toArray();
335         $leadData['relations'] = array(
336             array('type'  => '', 'related_record' => $savedContact->toArray()),
337         );
338         $savedLead = $this->_instance->saveLead($leadData);
339         
340         $this->assertEquals(1, count($savedLead['relations']), 'Relation has not been added');
341         $this->assertEquals('CUSTOMER', $savedLead['relations'][0]['type'], 'default type should be CUSTOMER');
342     }
343     
344     /**
345      * testConcurrentRelationSetting
346      * 
347      * @see 0007108: inspect and solve concurrency conflicts when setting lead relations
348      * @see 0000554: modlog: records can't be updated in less than 1 second intervals
349      */
350     public function testConcurrentRelationSetting()
351     {
352         $leadData = $this->_instance->saveLead($this->_getLead()->toArray());
353         $task = $this->_getTask();
354         
355         $taskJson = new Tasks_Frontend_Json();
356         $taskData = $this->_getTask()->toArray();
357         $taskData['relations'] = array(
358             array(
359                 'type'  => 'TASK',
360                 'own_model' => 'Tasks_Model_Task',
361                 'own_backend' => 'Sql',
362                 'own_degree' => 'sibling',
363                 'related_model' => 'Crm_Model_Lead',
364                 'related_backend' => 'Sql',
365                 'related_id' => $leadData['id'],
366                 'related_record' => $leadData
367             ),
368         );
369         $taskData = $taskJson->saveTask($taskData);
370         $taskData['description'] = 1;
371         $taskData = $taskJson->saveTask($taskData);
372         
373         $savedLead = $this->_instance->getLead($leadData['id']);
374         $savedLead['relations'][0]['related_record']['description'] = '2';
375         $savedLead['relations'][0]['related_record']['due'] = '2012-10-18 12:54:33';
376         
377         // client may send wrong seq -> this should cause a concurrency conflict
378         $savedLead['relations'][0]['related_record']['seq'] = 0;
379         try {
380             $savedLead = $this->_instance->saveLead($savedLead);
381             $this->fail('expected concurrency exception');
382         } catch (Tinebase_Timemachine_Exception_ConcurrencyConflict $ttecc) {
383             $this->assertEquals('concurrency conflict!', $ttecc->getMessage());
384         }
385     }
386     
387     /**
388      * get contact
389      * 
390      * @return Addressbook_Model_Contact
391      */
392     protected function _getContact()
393     {
394         return new Addressbook_Model_Contact(array(
395             'adr_one_countryname'   => 'DE',
396             'adr_one_locality'      => 'Hamburg',
397             'adr_one_postalcode'    => '24xxx',
398             'adr_one_region'        => 'Hamburg',
399             'adr_one_street'        => 'Pickhuben 4',
400             'adr_one_street2'       => 'no second street',
401             'adr_two_countryname'   => 'DE',
402             'adr_two_locality'      => 'Hamburg',
403             'adr_two_postalcode'    => '24xxx',
404             'adr_two_region'        => 'Hamburg',
405             'adr_two_street'        => 'Pickhuben 4',
406             'adr_two_street2'       => 'no second street2',
407             'assistent'             => 'Cornelius Weiß',
408             'bday'                  => '1975-01-02 03:04:05', // new Tinebase_DateTime???
409             'email'                 => 'unittests@tine20.org',
410             'email_home'            => 'unittests@tine20.org',
411             'note'                  => 'Bla Bla Bla',
412             'role'                  => 'Role',
413             'title'                 => 'Title',
414             'url'                   => 'http://www.tine20.org',
415             'url_home'              => 'http://www.tine20.com',
416             'n_family'              => 'Kneschke',
417             'n_fileas'              => 'Kneschke, Lars',
418             'n_given'               => 'Lars',
419             'n_middle'              => 'no middle name',
420             'n_prefix'              => 'no prefix',
421             'n_suffix'              => 'no suffix',
422             'org_name'              => 'Metaways Infosystems GmbH',
423             'org_unit'              => 'Tine 2.0',
424             'tel_assistent'         => '+49TELASSISTENT',
425             'tel_car'               => '+49TELCAR',
426             'tel_cell'              => '+49TELCELL',
427             'tel_cell_private'      => '+49TELCELLPRIVATE',
428             'tel_fax'               => '+49TELFAX',
429             'tel_fax_home'          => '+49TELFAXHOME',
430             'tel_home'              => '+49TELHOME',
431             'tel_pager'             => '+49TELPAGER',
432             'tel_work'              => '+49TELWORK',
433         ));
434     }
435
436     /**
437      * get task
438      * 
439      * @return Tasks_Model_Task
440      */
441     protected function _getTask()
442     {
443         return new Tasks_Model_Task(array(
444             'created_by'           => Zend_Registry::get('currentAccount')->getId(),
445             'creation_time'        => Tinebase_DateTime::now(),
446             'percent'              => 70,
447             'due'                  => Tinebase_DateTime::now()->addMonth(1),
448             'summary'              => 'phpunit: crm test task',
449             'alarms'               => new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(array(
450                 'minutes_before'    => 0
451             )), TRUE),
452         ));
453     }
454     
455     /**
456      * get lead
457      * 
458      * @return Crm_Model_Lead
459      */
460     protected function _getLead()
461     {
462         $cfc = Tinebase_CustomFieldTest::getCustomField(array(
463             'application_id' => Tinebase_Application::getInstance()->getApplicationByName('Crm')->getId(),
464             'model'          => 'Crm_Model_Lead',
465             'name'           => 'crmcf',
466         ));
467         Tinebase_CustomField::getInstance()->addCustomField($cfc);
468         
469         return new Crm_Model_Lead(array(
470             'lead_name'     => 'PHPUnit',
471             'leadstate_id'  => 1,
472             'leadtype_id'   => 1,
473             'leadsource_id' => 1,
474             'container_id'  => Tinebase_Container::getInstance()->getDefaultContainer('Crm')->getId(),
475             'start'         => Tinebase_DateTime::now(),
476             'description'   => 'Description',
477             'end'           => NULL,
478             'turnover'      => 0,
479             'probability'   => 70,
480             'end_scheduled' => NULL,
481             'tags'          => array(
482                 array('name' => 'lead tag', 'type' => Tinebase_Model_Tag::TYPE_SHARED)
483             ),
484             'customfields'  => array(
485                 'crmcf' => '1234'
486             ),
487         ));
488     }
489     
490     /**
491      * get product
492      * 
493      * @return Sales_Model_Product
494      */
495     protected function _getProduct()
496     {
497         return new Sales_Model_Product(array(
498             'name'  => 'PHPUnit test product',
499             'price' => 10000,
500         ));
501     }
502     
503     /**
504      * get lead filter
505      * 
506      * @return array
507      */
508     protected function _getLeadFilter()
509     {
510         return array(
511             array('field' => 'query',           'operator' => 'contains',       'value' => 'PHPUnit'),
512         );
513     }
514
515     /**
516      * testRelatedModlog
517      * 
518      * @see 0000996: add changes in relations/linked objects to modlog/history
519      */
520     public function testRelatedModlog()
521     {
522         // create lead with tag, customfield and related contacts
523         $savedLead = $this->_saveLead();
524         
525         // change relations, customfields + tags
526         $savedLead['tags'][] = array('name' => 'another tag', 'type' => Tinebase_Model_Tag::TYPE_PERSONAL);
527         foreach ($savedLead['relations'] as $key => $value) {
528             if ($value['type'] == 'PARTNER') {
529                 $savedLead['relations'][$key]['type'] = 'CUSTOMER';
530             }
531             if ($value['type'] == 'TASK') {
532                 unset($savedLead['relations'][$key]);
533             }
534         }
535         $savedLead['customfields']['crmcf'] = '5678';
536         $updatedLead = $this->_instance->saveLead($savedLead);
537         
538         // check modlog + history
539         $modifications = Tinebase_Timemachine_ModificationLog::getInstance()->getModifications('Crm', $updatedLead['id']);
540         
541         //print_r($updatedLead);
542         $this->assertEquals(3, count($modifications), 'expected 3 modifications: ' . print_r($modifications->toArray(), TRUE));
543         foreach ($modifications as $modification) {
544             switch ($modification->modified_attribute) {
545                 case 'customfields':
546                     $this->assertEquals('{"crmcf":"5678"}', $modification->new_value);
547                     break;
548                 case 'relations':
549                     $diff = new Tinebase_Record_RecordSetDiff(Zend_Json::decode($modification->new_value));
550                     $this->assertEquals(0, count($diff->added));
551                     $this->assertEquals(1, count($diff->removed));
552                     $this->assertEquals(1, count($diff->modified), 'relations modified mismatch: ' . print_r($diff->toArray(), TRUE));
553                     $this->assertTrue(isset($diff->modified[0]['diff']['type']));
554                     $this->assertEquals('CUSTOMER', $diff->modified[0]['diff']['type'], 'type diff is not correct: ' . print_r($diff->toArray(), TRUE));
555                     break;
556                 case 'tags':
557                     $diff = new Tinebase_Record_RecordSetDiff(Zend_Json::decode($modification->new_value));
558                     $this->assertEquals(1, count($diff->added));
559                     $this->assertEquals(0, count($diff->removed));
560                     $this->assertEquals(0, count($diff->modified), 'tags modified mismatch: ' . print_r($diff->toArray(), TRUE));
561                     break;
562                 default:
563                     $this->fail('Invalid modification: ' . print_r($modification->toArray(), TRUE));
564             }
565         }
566     }
567     
568     /**
569      * testCreateLeadWithAttachment
570      * 
571      * @see 0005024: allow to attach external files to records
572      */
573     public function testCreateLeadWithAttachment()
574     {
575         $tempFileBackend = new Tinebase_TempFile();
576         $tempFile = $tempFileBackend->createTempFile(dirname(dirname(__FILE__)) . '/Filemanager/files/test.txt');
577         
578         $lead = $this->_getLead()->toArray();
579         $lead['attachments'] = array(array('tempFile' => array('id' => $tempFile->getId())));
580         
581         $savedLead = $this->_instance->saveLead($lead);
582         // add path to files to remove
583         $this->_objects['paths'][] = Tinebase_FileSystem_RecordAttachments::getInstance()->getRecordAttachmentPath(new Crm_Model_Lead($savedLead, TRUE)) . '/' . $tempFile->name;
584         
585         $this->assertTrue(isset($savedLead['attachments']), 'no attachments found');
586         $this->assertEquals(1, count($savedLead['attachments']));
587         $attachment = $savedLead['attachments'][0];
588         $this->assertEquals('text/plain', $attachment['contenttype'], print_r($attachment, TRUE));
589         $this->assertEquals(17, $attachment['size']);
590         $this->assertTrue(is_array($attachment['created_by']), 'user not resolved: ' . print_r($attachment['created_by'], TRUE));
591         $this->assertEquals(Tinebase_Core::getUser()->accountFullName, $attachment['created_by']['accountFullName'], 'user not resolved: ' . print_r($attachment['created_by'], TRUE));
592         
593         return $savedLead;
594     }
595     
596     /**
597      * testUpdateLeadWithAttachment
598      * 
599      * @see 0005024: allow to attach external files to records
600      */
601     public function testUpdateLeadWithAttachment()
602     {
603         $lead = $this->testCreateLeadWithAttachment();
604         $savedLead = $this->_instance->saveLead($lead);
605         $this->assertTrue(isset($savedLead['attachments']), 'no attachments found');
606         $this->assertEquals(1, count($savedLead['attachments']));
607     }
608     
609     /**
610      * testRemoveAttachmentFromLead
611      * 
612      * @see 0005024: allow to attach external files to records
613      */
614     public function testRemoveAttachmentFromLead()
615     {
616         $lead = $this->testCreateLeadWithAttachment();
617         $lead['attachments'] = array();
618     
619         $savedLead = $this->_instance->saveLead($lead);
620         $this->assertEquals(0, count($savedLead['attachments']));
621         $this->assertFalse($this->_fsController->fileExists($this->_objects['paths'][0]));
622     }
623     
624     /**
625      * testDeleteLeadWithAttachment
626      * 
627      * @see 0005024: allow to attach external files to records
628      */
629     public function testDeleteLeadWithAttachment()
630     {
631         $lead = $this->testCreateLeadWithAttachment();
632         $this->_instance->deleteLeads(array($lead['id']));
633         $this->assertFalse($this->_fsController->fileExists($this->_objects['paths'][0]));
634     }
635
636     /**
637      * test saving lead with empty start date
638      * 
639      * @see 0009602: CRM should cope with empty start of leads
640      */
641     public function testEmptyStart()
642     {
643         $leadArray = $this->_getLead()->toArray();
644         $leadArray['start'] = null;
645         $newLead = $this->_instance->saveLead($leadArray);
646         
647         $this->assertContains(Tinebase_DateTime::now()->format('Y-m-d'), $newLead['start'], 'start should be set to now if missing');
648     }
649 }