c23d07297d47d609fb23c69c7fb24a3a6bccfd17
[tine20] / tests / tine20 / Addressbook / Import / CsvTest.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Addressbook
6  * @license     http://www.gnu.org/licenses/agpl.html
7  * @copyright   Copyright (c) 2008-2013 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Philipp Schüle <p.schuele@metaways.de>
9  */
10
11 /**
12  * Test helper
13  */
14 require_once dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
15
16 /**
17  * Test class for Addressbook_Import_Csv
18  */
19 class Addressbook_Import_CsvTest extends PHPUnit_Framework_TestCase
20 {
21     /**
22      * @var Addressbook_Import_Csv instance
23      */
24     protected $_instance = NULL;
25     
26     /**
27      * @var string $_filename
28      */
29     protected $_filename = NULL;
30     
31     /**
32      * @var boolean
33      */
34     protected $_deleteImportFile = TRUE;
35     
36     protected $_deletePersonalContacts = FALSE;
37     
38     /**
39      * Runs the test methods of this class.
40      *
41      * @access public
42      * @static
43      */
44     public static function main()
45     {
46         $suite  = new PHPUnit_Framework_TestSuite('Tine 2.0 Addressbook Csv Import Tests');
47         PHPUnit_TextUI_TestRunner::run($suite);
48     }
49
50     /**
51      * Sets up the fixture.
52      * This method is called before a test is executed.
53      *
54      * @access protected
55      */
56     protected function setUp()
57     {
58         // always resolve customfields
59         Addressbook_Controller_Contact::getInstance()->resolveCustomfields(TRUE);
60     }
61
62     /**
63      * Tears down the fixture
64      * This method is called after a test is executed.
65      *
66      * @access protected
67      */
68     protected function tearDown()
69     {
70         // cleanup
71         if (file_exists($this->_filename) && $this->_deleteImportFile) {
72             unlink($this->_filename);
73         }
74         
75         if ($this->_deletePersonalContacts) {
76             Addressbook_Controller_Contact::getInstance()->deleteByFilter(new Addressbook_Model_ContactFilter(array(array(
77                 'field' => 'container_id', 'operator' => 'equals', 'value' => Addressbook_Controller_Contact::getInstance()->getDefaultAddressbook()->getId()
78             ))));
79         }
80     }
81     
82     /**
83      * test import duplicate data
84      * 
85      * @return array
86      */
87     public function testImportDuplicates()
88     {
89         $internalContainer = Tinebase_Container::getInstance()->getContainerByName('Addressbook', 'Internal Contacts', Tinebase_Model_Container::TYPE_SHARED);
90         $options = array(
91             'container_id'  => $internalContainer->getId(),
92         );
93         $result = $this->_doImport($options, 'adb_tine_import_csv', new Addressbook_Model_ContactFilter(array(
94             array('field' => 'container_id', 'operator' => 'equals', 'value' => $internalContainer->getId()),
95         )));
96         
97         $this->assertGreaterThan(0, $result['duplicatecount'], 'no duplicates.');
98         $this->assertTrue($result['exceptions'] instanceof Tinebase_Record_RecordSet);
99         
100         return $result;
101     }
102     
103     /**
104      * test import data
105      */
106     public function testImportSalutation()
107     {
108         $myContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
109         $salutation = Addressbook_Config::getInstance()->get(Addressbook_Config::CONTACT_SALUTATION)->records->getFirstRecord()->value;
110         $myContact->salutation = $salutation;
111         Addressbook_Controller_Contact::getInstance()->update($myContact);
112         
113         $result = $this->testImportDuplicates();
114         
115         $found = FALSE;
116         foreach ($result['exceptions'] as $exception) {
117             if ($exception['exception']['clientRecord']['n_fn'] === Tinebase_Core::getUser()->accountFullName) {
118                 $found = TRUE;
119                 $this->assertTrue(isset($exception['exception']['clientRecord']['salutation']), 'no salutation found: ' . print_r($exception['exception']['clientRecord'], TRUE));
120                 $this->assertEquals($salutation, $exception['exception']['clientRecord']['salutation']);
121                 break;
122             }
123         }
124         
125         $this->assertTrue($found);
126     }
127
128     /**
129      * test import umlaut
130      * 
131      * @see 0006936: detect import file encoding
132      */
133     public function testImportUmlaut()
134     {
135         $myContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
136         $myContact->org_name = 'Übel leckerer Äppler';
137         Addressbook_Controller_Contact::getInstance()->update($myContact);
138         
139         $result = $this->testImportDuplicates();
140         
141         $found = FALSE;
142         foreach ($result['exceptions'] as $exception) {
143             $record = $exception['exception']['clientRecord'];
144             if ($record['n_fn'] === Tinebase_Core::getUser()->accountFullName) {
145                 $found = TRUE;
146                 $this->assertEquals($myContact->org_name, $record['org_name']);
147             }
148         }
149         
150         $this->assertTrue($found);
151     }
152     
153     /**
154      * import google contacts
155      */
156     public function testImportGoogleContacts()
157     {
158         $this->_filename = dirname(__FILE__) . '/files/google_contacts.csv';
159         $this->_deleteImportFile = FALSE;
160         
161         $result = $this->_doImport(array('dryrun' => TRUE), 'adb_google_import_csv');
162         
163         $this->assertEquals(5, $result['totalcount']);
164         $this->assertEquals('Niedersachsen Ring 22', $result['results'][4]->adr_one_street);
165         $this->assertEquals('abc@here.de', $result['results'][3]->email);
166         $this->assertEquals('+49227913452', $result['results'][0]->tel_work);
167     }
168     
169     /**
170      * test import of a customfield
171      */
172     public function testImportCustomField()
173     {
174         $customField = $this->_createCustomField();
175         
176         // create/get new import/export definition with customfield
177         $filename = dirname(__FILE__) . '/files/adb_google_import_csv_test.xml';
178         $applicationId = Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId();
179         $definition = Tinebase_ImportExportDefinition::getInstance()->getFromFile($filename, $applicationId);
180         
181         $this->_filename = dirname(__FILE__) . '/files/google_contacts.csv';
182         $this->_deleteImportFile = FALSE;
183         
184         $result = $this->_doImport(array(), $definition);
185         $this->_deletePersonalContacts = TRUE;
186         $this->assertEquals(5, $result['totalcount']);
187         
188         $contacts = Addressbook_Controller_Contact::getInstance()->search(new Addressbook_Model_ContactFilter(array(
189             array('field' => 'container_id', 'operator' => 'equals', 'value' => Addressbook_Controller_Contact::getInstance()->getDefaultAddressbook()->getId()),
190             array('field' => 'n_given', 'operator' => 'equals', 'value' => 'Ando'),
191         )));
192         $this->assertEquals(1, count($contacts));
193         $ando = $contacts->getFirstRecord();
194         $this->assertEquals(array('Yomi Name' => 'yomi'), $ando->customfields);
195     }
196     
197     /**
198      * testExportAndImportWithCustomField
199      * 
200      * @see 0006230: add customfields to csv export
201      */
202     public function testExportAndImportWithCustomField()
203     {
204         $customField = $this->_createCustomField();
205         $ownContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
206         $cfValue = array($customField->name => 'testing');
207         $ownContact->customfields = $cfValue;
208         Addressbook_Controller_Contact::getInstance()->update($ownContact);
209         
210         $definition = Tinebase_ImportExportDefinition::getInstance()->getByName('adb_tine_import_csv');
211         $definition->plugin_options = preg_replace('/<\/mapping>/',
212             '<field>
213                 <source>Yomi Name</source>
214                 <destination>Yomi Name</destination>
215             </field></mapping>', $definition->plugin_options);
216         $result = $this->_doImport(array(), $definition, new Addressbook_Model_ContactFilter(array(
217             array('field' => 'id', 'operator' => 'equals', 'value' => $ownContact->getId()),
218         )));
219         $this->assertGreaterThan(0, $result['duplicatecount'], 'no duplicates.');
220         $this->assertTrue($result['exceptions'] instanceof Tinebase_Record_RecordSet);
221
222         $exceptionArray = $result['exceptions']->toArray();
223         $this->assertTrue(isset($exceptionArray[0]['exception']['clientRecord']['customfields']),
224             'could not find customfields in client record: ' . print_r($exceptionArray[0]['exception']['clientRecord'], TRUE));
225         $this->assertEquals('testing', $exceptionArray[0]['exception']['clientRecord']['customfields'][$customField->name],
226             'could not find cf value in client record: ' . print_r($exceptionArray[0]['exception']['clientRecord'], TRUE));
227     }
228     
229     /**
230      * testImportWithUmlautsWin1252
231      * 
232      * @see 0006534: import of contacts with umlaut as first char fails
233      */
234     public function testImportWithUmlautsWin1252()
235     {
236         $definition = $this->_getDefinitionFromFile('adb_import_csv_win1252.xml');
237         
238         $this->_filename = dirname(__FILE__) . '/files/importtest_win1252.csv';
239         $this->_deleteImportFile = FALSE;
240         
241         $result = $this->_doImport(array(), $definition);
242         $this->_deletePersonalContacts = TRUE;
243         
244         $this->assertEquals(4, $result['totalcount']);
245         $this->assertEquals('Üglü, ÖzdemirÖ', $result['results'][2]->n_fileas, 'Umlauts were not imported correctly: ' . print_r($result['results'][2]->toArray(), TRUE));
246     }
247     
248     /**
249      * returns import defintion from file
250      * 
251      * @param string $filename
252      * @return Tinebase_Model_ImportExportDefinition
253      */
254     protected function _getDefinitionFromFile($filename)
255     {
256         $filename = dirname(__FILE__) . '/files/' . $filename;
257         $applicationId = Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId();
258         $definition = Tinebase_ImportExportDefinition::getInstance()->getFromFile($filename, $applicationId);
259         
260         return $definition;
261     }
262     
263     /**
264      * import helper
265      * 
266      * @param array $_options
267      * @param string|Tinebase_Model_ImportExportDefinition $_definition
268      * @param Addressbook_Model_ContactFilter $_exportFilter
269      * @return array
270      */
271     protected function _doImport(array $_options, $_definition, Addressbook_Model_ContactFilter $_exportFilter = NULL)
272     {
273         $definition = ($_definition instanceof Tinebase_Model_ImportExportDefinition) ? $_definition : Tinebase_ImportExportDefinition::getInstance()->getByName($_definition);
274         $this->_instance = Addressbook_Import_Csv::createFromDefinition($definition, $_options);
275         
276         // export first
277         if ($_exportFilter !== NULL) {
278             $exporter = new Addressbook_Export_Csv($_exportFilter, Addressbook_Controller_Contact::getInstance());
279             $this->_filename = $exporter->generate();
280         }
281         
282         // then import
283         $result = $this->_instance->importFile($this->_filename);
284         
285         return $result;
286     }
287     
288     /**
289     * get custom field record
290     *
291     * @return Tinebase_Model_CustomField_Config
292     */
293     protected function _createCustomField()
294     {
295         $cfData = new Tinebase_Model_CustomField_Config(array(
296             'application_id'    => Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId(),
297             'name'              => 'Yomi Name',
298             'model'             => 'Addressbook_Model_Contact',
299             'definition'        => array(
300                 'label' => Tinebase_Record_Abstract::generateUID(),
301                 'type'  => 'string',
302                 'uiconfig' => array(
303                     'xtype'  => Tinebase_Record_Abstract::generateUID(),
304                     'length' => 10,
305                     'group'  => 'unittest',
306                     'order'  => 100,
307                 )
308             )
309         ));
310         
311         try {
312             $result = Tinebase_CustomField::getInstance()->addCustomField($cfData);
313         } catch (Zend_Db_Statement_Exception $zdse) {
314             // customfield already exists
315             $cfs = Tinebase_CustomField::getInstance()->getCustomFieldsForApplication('Addressbook');
316             $result = $cfs->filter('name', 'Yomi Name')->getFirstRecord();
317         }
318         
319         return $result;
320     }
321
322     /**
323      * testImportDuplicateResolve
324      * 
325      * @see 0009316: add duplicate resolving to cli import
326      */
327     public function testImportDuplicateResolve()
328     {
329         $definition = $this->_getDefinitionFromFile('adb_import_csv_duplicate.xml');
330         
331         $this->_filename = dirname(__FILE__) . '/files/import_duplicate_1.csv';
332         $this->_deleteImportFile = FALSE;
333         
334         $result = $this->_doImport(array(), $definition);
335         $this->_deletePersonalContacts = TRUE;
336
337         $this->_filename = dirname(__FILE__) . '/files/import_duplicate_2.csv';
338         $this->_deleteImportFile = FALSE;
339         
340         $result = $this->_doImport(array(), $definition);
341         
342         $this->assertEquals(1, $result['updatecount'], 'should have updated 1 contact');
343         $this->assertEquals('joerg@home.com', $result['results'][0]->email_home, 'duplicates resolving did not work: ' . print_r($result['results']->toArray(), true));
344         $this->assertEquals('Jörg', $result['results'][0]->n_given, 'wrong encoding: ' . print_r($result['results']->toArray(), true));
345     }
346 }