New: contacts() and contactsIds methods, reporting filter errors
[qtcontacts-tracker:qtcontacts-tracker.git] / tests / ut_qtcontacts_trackerplugin / ut_qtcontacts_trackerplugin.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Mobility Components.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "ut_qtcontacts_trackerplugin.h"
43
44 #include <QMap>
45 #include <QPair>
46 #include <QUuid>
47
48 #include <QtTracker/Tracker>
49 #include <QtTracker/ontologies/nco.h>
50 #include <QtTracker/ontologies/nie.h>
51 #include <qcontactfilters.h>
52 #include <qtcontacts.h>
53 #include <trackerchangelistener.h>
54 #include <qcontactrelationshipsaverequest.h>
55 #include <qcontactrelationshipfetchrequest.h>
56 #include <qtrackercontactidfetchrequest.h>
57 #include <qcontacttrackerbackend_p.h>
58 #include <qtrackercontactasyncrequest.h>
59
60 #include "contactmanager.h"
61
62 // update this when creating debian package
63 const QString PATH_TO_SPARQL_TESTS("./ut_qtcontacts_trackerplugin_data");
64
65 ut_qtcontacts_trackerplugin::ut_qtcontacts_trackerplugin()
66 {
67
68 }
69
70 void ut_qtcontacts_trackerplugin::initTestCase()
71 {
72     QMap<QString, QString> trackerEngineParams;
73     trackerEngine = new QContactTrackerEngine(trackerEngineParams);
74     errorMap = new QMap<int, QContactManager::Error>();
75 }
76
77 void ut_qtcontacts_trackerplugin::testContacts()
78 {
79     QContact c1;
80     QContact c2;
81
82     trackerEngine->saveContact(&c1, error);
83     trackerEngine->saveContact(&c2, error);
84     QVERIFY2((error == QContactManager::NoError),"Saving contact");
85     QList<QContactLocalId> contacts = trackerEngine->contactIds(queryFilter, sortOrders, error);
86     QVERIFY2(contacts.contains(c1.localId()), "Previously added contact is not found");
87     QVERIFY2(contacts.contains(c2.localId()), "Previously added contact is not found");
88 }
89
90 void ut_qtcontacts_trackerplugin::testContact()
91 {
92     // Test invalid contact id
93     QContact invalidContact = trackerEngine->contact_impl( -1, error);
94     QVERIFY(error != QContactManager::NoError);
95
96     // Add a contact
97     QContact newContact;
98     const QContactLocalId oldid = newContact.localId();
99     QVERIFY( trackerEngine->saveContact( &newContact, error ) );
100
101     QContactLocalId id = newContact.localId();
102     QVERIFY( id != oldid );
103
104     // Find the added contact
105     QContact c = trackerEngine->contact_impl( id, error );
106     QVERIFY( c.localId() == newContact.localId() );
107 }
108
109 void ut_qtcontacts_trackerplugin::testSaveName()
110 {
111     QContact c;
112     QContactLocalId initialId = c.localId();
113     int detailsAdded = 0;
114
115     QMap<QString,QString> nameValues;
116     QContactName name;
117     nameValues.insert(QLatin1String(QContactName::FieldPrefix), "Mr");
118     nameValues.insert(QLatin1String(QContactName::FieldFirst), "John");
119     nameValues.insert(QLatin1String(QContactName::FieldMiddle), "Rupert");
120     nameValues.insert(QLatin1String(QContactName::FieldLast), "Doe");
121 //    nameValues.insert(QContactName::FieldSuffix, "III");
122
123     foreach (QString field, nameValues.keys()) {
124         name.setValue(field, nameValues.value(field));
125     }
126     c.saveDetail(&name);
127
128     QContactNickname nick;
129     nick.setValue(QLatin1String(QContactNickname::FieldNickname), "Johnny");
130     c.saveDetail(&nick);
131
132     QVERIFY(c.detail<QContactName>().prefix() == "Mr");
133     QVERIFY(c.detail<QContactName>().firstName() == "John");
134     QVERIFY(c.detail<QContactName>().middleName() == "Rupert");
135     QVERIFY(c.detail<QContactName>().lastName() == "Doe");
136     QVERIFY(c.detail<QContactNickname>().nickname() == "Johnny");
137
138     detailsAdded++;
139
140     trackerEngine->saveContact(&c, error);
141     QCOMPARE(error,  QContactManager::NoError);
142     QVERIFY(c.localId() != initialId);
143     QContact contact = trackerEngine->contact_impl(c.localId(), error);
144     QList<QContactName> details = contact.details<QContactName>();
145     QList<QContactNickname> details2 = contact.details<QContactNickname>();
146     QCOMPARE(details.count(), detailsAdded);
147     QCOMPARE(details2.count(), detailsAdded);
148     // Name is unique
149     foreach(QString field, nameValues.keys()) {
150         QCOMPARE(details.at(0).value(field), nameValues.value(field));
151     }
152     QCOMPARE(details2.at(0).value(QLatin1String(QContactNickname::FieldNickname)), QString("Johnny"));
153
154     // Try changing the name of the saved contact.
155     {
156         QMap<QString,QString> nameValues;
157         QContactName name = c.detail<QContactName>();
158         nameValues.insert(QLatin1String(QContactName::FieldPrefix), "Mr2");
159         nameValues.insert(QLatin1String(QContactName::FieldFirst), "John2");
160         nameValues.insert(QLatin1String(QContactName::FieldMiddle), "Rupert2");
161         nameValues.insert(QLatin1String(QContactName::FieldLast), "");
162         //    nameValues.insert(QContactName::FieldSuffix, "III");
163
164         foreach (QString field, nameValues.keys()) {
165             name.setValue(field, nameValues.value(field));
166         }
167         c.saveDetail(&name);
168
169         QContactNickname nick = c.detail<QContactNickname>();
170         nick.setValue(QLatin1String(QContactNickname::FieldNickname), "Johnny2");
171         c.saveDetail(&nick);
172
173
174         QVERIFY(trackerEngine->saveContact(&c, error));
175         QCOMPARE(error,  QContactManager::NoError);
176         QVERIFY(c.localId() != initialId);
177
178         QContact contact = trackerEngine->contact_impl(c.localId(), error);
179         QCOMPARE(error,  QContactManager::NoError);
180         QList<QContactName> details = contact.details<QContactName>();
181         QList<QContactNickname> details2 = contact.details<QContactNickname>();
182         QCOMPARE(details.count(), detailsAdded);
183         QCOMPARE(details2.count(), detailsAdded);
184         // Name is unique
185         foreach(QString field, nameValues.keys()) {
186             QCOMPARE(details.at(0).value(field), nameValues.value(field));
187         }
188         QCOMPARE(details2.at(0).value(QLatin1String(QContactNickname::FieldNickname)), QString("Johnny2"));
189
190         // now try to add new name detail fails - this is how currently unique fields are implemented
191         // so cover it in unit tests
192         QContactName name1;
193         name1.setValue(QContactName::FieldFirst, "Something that wont be stored as name is unique");
194         c.saveDetail(&name1);
195         // validate that unique name is not saved
196         QVERIFY(!trackerEngine->saveContact(&c, error));
197         details = contact.details<QContactName>();
198         details2 = contact.details<QContactNickname>();
199         QCOMPARE(details.count(), detailsAdded);
200         QCOMPARE(details2.count(), detailsAdded);
201     }
202 }
203
204 void ut_qtcontacts_trackerplugin::testSavePhoneNumber()
205 {
206     // use the same values for 2 contacts
207     for (int i = 0; i <2; i++ )
208     {
209     QContact c;
210     QContactLocalId initialId = c.localId();
211     int detailsAdded = 0;
212     QContactName name;
213     name.setFirstName("I have phone numbers");
214     name.setLastName("Girl");
215     c.saveDetail(&name);
216
217     // key: phonenumber; value: context,subtype
218     QMap<QString,QPair<QString,QString> > phoneValues;
219
220     phoneValues.insert("(704)486-6472", QPair<QString,QString>(QLatin1String(QContactDetail::ContextHome), QString()));
221     phoneValues.insert("(765)957-1663", QPair<QString,QString>(QLatin1String(QContactDetail::ContextHome), QString()));
222     phoneValues.insert("(999)888-1111", QPair<QString,QString>(QLatin1String(QContactDetail::ContextHome),
223                                                                QLatin1String(QContactPhoneNumber::SubTypeMobile)));
224
225     phoneValues.insert("(792)123-6113", QPair<QString,QString>(QLatin1String(QContactDetail::ContextWork), QString()));
226     phoneValues.insert("(918)491-7361", QPair<QString,QString>(QLatin1String(QContactDetail::ContextWork),
227                                                   QLatin1String(QContactPhoneNumber::SubTypeMobile)));
228     phoneValues.insert("(412)670-1514", QPair<QString,QString>(QLatin1String(QContactDetail::ContextWork),
229                                                   QLatin1String(QContactPhoneNumber::SubTypeCar)));
230     QMap<QString,QPair<QString,QString> > formattedPhoneValues;
231
232
233     foreach (QString number, phoneValues.keys()) {
234         QContactPhoneNumber phone;
235         phone.setNumber(number);
236         // Stripped automatically on saving RFC 3966 visual-separators reg exp "[(|-|.|)| ]"
237         formattedPhoneValues.insert(QString(number).replace( QRegExp("[\\(|" \
238                 "\\-|" \
239                 "\\.|" \
240                 "\\)|" \
241                 " ]"), ""),phoneValues.value(number));
242         if (!phoneValues.value(number).first.isEmpty()) {
243             phone.setContexts(phoneValues.value(number).first);
244         }
245         if (!phoneValues.value(number).second.isEmpty()) {
246             phone.setSubTypes(phoneValues.value(number).second);
247         }
248         c.saveDetail(&phone);
249         detailsAdded++;
250     }
251
252     trackerEngine->saveContact(&c, error);
253     QCOMPARE(error,  QContactManager::NoError);
254     QVERIFY(c.localId() != initialId);
255     // wait for commit transaction to be done, no signals yet
256     for(int i = 0; i < 100; i++)
257     {
258         usleep(10000);
259         QCoreApplication::processEvents();
260     }
261
262
263     // verify with synchronous read too
264     QContact contact = trackerEngine->contact_impl(c.localId(), error);
265     QCOMPARE(error,  QContactManager::NoError);
266     QList<QContactPhoneNumber> details = contact.details<QContactPhoneNumber>();
267
268
269     QCOMPARE(details.count(), detailsAdded);
270
271
272     foreach (QContactPhoneNumber detail, details) {
273         // Verify that the stored values and attributes are the same as given
274         QVERIFY(formattedPhoneValues.contains(detail.number()));
275         QCOMPARE(detail.contexts()[0], formattedPhoneValues.value(detail.number()).first);
276         if( formattedPhoneValues.value(detail.number()).second.isEmpty()) // default empty is voice
277             QCOMPARE(detail.subTypes()[0], QLatin1String(QContactPhoneNumber::SubTypeVoice));
278         else
279             QCOMPARE(detail.subTypes()[0], formattedPhoneValues.value(detail.number()).second);
280     }
281
282     // edit one of numbers . values, context and subtypes and save again
283     QString editedPhoneValue = "+7044866473";
284     QContactPhoneNumber phone = details[0];
285     phone.setNumber(editedPhoneValue);
286     phone.setContexts(QContactDetail::ContextWork);
287     phone.setSubTypes(QContactPhoneNumber::SubTypeMobile);
288     c = contact;
289     c.saveDetail(&phone);
290     trackerEngine->saveContact(&c, error);
291     QCOMPARE(error,  QContactManager::NoError);
292     c = this->contact(c.localId(), QStringList()<<QContactPhoneNumber::DefinitionName);
293     details = c.details<QContactPhoneNumber>();
294     QCOMPARE(details.count(), detailsAdded);
295     bool found = false;
296     foreach (QContactPhoneNumber detail, details) {
297         if(detail.number() == phone.number())
298         {
299             found = true;
300             QVERIFY(detail.subTypes().contains(QContactPhoneNumber::SubTypeMobile));
301             QVERIFY(detail.contexts().contains(QContactPhoneNumber::ContextWork));
302             break;
303         }
304     }
305     QVERIFY(found);
306     }
307 }
308
309 void ut_qtcontacts_trackerplugin::testPhoneNumberContext()
310 {
311     QContact c;
312     QContactPhoneNumber phone;
313     phone.setContexts(QContactDetail::ContextHome);
314     phone.setNumber("555-888");
315     phone.setSubTypes(QContactPhoneNumber::SubTypeMobile);
316     c.saveDetail(&phone);
317     QContact contactToSave = c;
318     // Let's do this all twice, first time save new detail, and next iteration change the context
319     for (int iterations = 0; iterations < 2; iterations++) {
320         QVERIFY(trackerEngine->saveContact(&contactToSave, error));
321         // wait for commit transaction to be done, no signals yet
322         for(int i = 0; i < 100; i++) {
323             usleep(10000);
324             QCoreApplication::processEvents();
325         }
326
327         QContactFetchRequest request;
328         QContactLocalIdFilter filter;
329         QList<QContactLocalId> ids;
330         ids.append(contactToSave.localId());
331         filter.setIds(ids);
332         request.setFilter(filter);
333
334         QStringList details;
335         details << QContactPhoneNumber::DefinitionName;
336         request.setDefinitionRestrictions(details);
337
338         Slots slot;
339         QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
340                 &slot, SLOT(progress(QContactFetchRequest*, bool )));
341
342         trackerEngine->startRequest(&request);
343
344         for(int i = 0; i < 100; i++) {
345             usleep(100000);
346             QCoreApplication::processEvents();
347             if(request.isFinished() )
348                 break;
349         }
350
351         // if it takes more, then something is wrong
352         QVERIFY(request.isFinished());
353         QVERIFY(!slot.contacts.isEmpty());
354
355         QContact contactToTest;
356         foreach (QContact savedContact, slot.contacts) {
357             if (savedContact.localId() == contactToSave.localId()) {
358                 contactToTest = savedContact;
359             }
360         }
361         QVERIFY(contactToTest.localId() == contactToSave.localId()); // Just to be sure we got the saved contact
362         qDebug()<<contactToTest.details<QContactPhoneNumber>().count();
363         
364         QVERIFY(contactToTest.details<QContactPhoneNumber>().count() == 1);
365         if (0 == iterations) {
366             // perform context change
367             QContactPhoneNumber phoneToEdit = contactToTest.detail<QContactPhoneNumber>();
368             phoneToEdit.setContexts(QContactDetail::ContextWork);
369             contactToTest.saveDetail(&phoneToEdit);
370             contactToSave = contactToTest;
371         }
372         QVERIFY(contactToTest.details<QContactPhoneNumber>().count() == 1);
373     }
374 }
375
376 void ut_qtcontacts_trackerplugin::testWritingOnlyWorkMobile()
377 {
378     QContact c;
379     QContactPhoneNumber phone;
380     phone.setContexts(QContactDetail::ContextWork);
381     phone.setNumber("555999");
382     phone.setSubTypes(QContactPhoneNumber::SubTypeMobile);
383     c.saveDetail(&phone);
384     QContact& contactToSave = c;
385     QVERIFY(trackerEngine->saveContact(&contactToSave, error));
386     // wait for commit transaction to be done, no signals yet
387     for(int i = 0; i < 100; i++) {
388         usleep(10000);
389         QCoreApplication::processEvents();
390     }
391
392     QContactFetchRequest request;
393     QContactLocalIdFilter filter;
394     QList<QContactLocalId> ids;
395     ids.append(contactToSave.localId());
396     filter.setIds(ids);
397     request.setFilter(filter);
398     QStringList details;
399     details << QContactPhoneNumber::DefinitionName;
400     request.setDefinitionRestrictions(details);
401
402     Slots slot;
403     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
404             &slot, SLOT(progress(QContactFetchRequest*, bool )));
405
406     trackerEngine->startRequest(&request);
407
408     for(int i = 0; i < 100; i++) {
409         usleep(100000);
410         QCoreApplication::processEvents();
411         if(request.isFinished() )
412             break;
413     }
414
415     // if it takes more, then something is wrong
416     QVERIFY(request.isFinished());
417     QVERIFY(!slot.contacts.isEmpty());
418
419     QContact contactToTest;
420     foreach (QContact savedContact, slot.contacts) {
421         if (savedContact.localId() == c.localId()) {
422             contactToTest = savedContact;
423         }
424     }
425     QVERIFY(contactToTest.localId() == c.localId()); // Just to be sure we got the saved contact
426     QVERIFY(contactToTest.details<QContactPhoneNumber>().count() == 1);
427     QVERIFY(contactToTest.detail<QContactPhoneNumber>().number() == phone.number());
428     QVERIFY(contactToTest.detail<QContactPhoneNumber>().subTypes() == phone.subTypes());
429     QVERIFY(contactToTest.detail<QContactPhoneNumber>().contexts() == phone.contexts());
430 }
431
432 void ut_qtcontacts_trackerplugin::testSaveAddress()
433 {
434     QContact c;
435     QContactName name;
436     name.setFirstName("Aruba & Barbados");
437     name.setLastName("Girl");
438     c.saveDetail(&name);
439     QContactLocalId initialId = c.localId();
440     int detailsAdded = 0;
441
442     // List of pairs of field-value map and context
443     typedef QMap<QString,QString> typeAddress;
444     typedef QPair<typeAddress,QString> typeAddressWithContext;
445     QList<typeAddressWithContext> addressValues;
446
447     // TODO check status of 137174 and other libqttracker1pre6 bugs before refactoring
448     typeAddress values;
449     values.insert(QLatin1String(QContactAddress::FieldCountry), "Barbados");
450     values.insert(QLatin1String(QContactAddress::FieldPostcode), "55555");
451     values.insert(QLatin1String(QContactAddress::FieldStreet), "Martindales Rd");
452     values.insert(QLatin1String(QContactAddress::FieldRegion), "Bridgetown");
453     addressValues.append(typeAddressWithContext(values, QLatin1String(QContactDetail::ContextHome)));
454     values.clear();
455     values.insert(QLatin1String(QContactAddress::FieldCountry), "Aruba");
456     values.insert(QLatin1String(QContactAddress::FieldPostcode), "44444");
457     values.insert(QLatin1String(QContactAddress::FieldStreet), "Brazilie Straat");
458     values.insert(QLatin1String(QContactAddress::FieldRegion), "Oranjestad");
459     addressValues.append(typeAddressWithContext(values, QLatin1String(QContactDetail::ContextHome)));
460     values.clear();
461     values.insert(QLatin1String(QContactAddress::FieldCountry), "ArubaWork");
462     values.insert(QLatin1String(QContactAddress::FieldPostcode), "44445");
463     values.insert(QLatin1String(QContactAddress::FieldStreet), "Sunset Blvd");
464     values.insert(QLatin1String(QContactAddress::FieldRegion), "Oranjestad");
465     addressValues.append(typeAddressWithContext(values, QLatin1String(QContactDetail::ContextHome)));
466     foreach (typeAddressWithContext addressWithContext, addressValues) {
467         QContactAddress address;
468         foreach (QString field, addressWithContext.first.keys()) {
469             address.setValue(field, addressWithContext.first.value(field));
470         }
471         address.setContexts(addressWithContext.second);
472         c.saveDetail(&address);
473         detailsAdded++;
474     }
475
476     trackerEngine->saveContact(&c, error);
477     QCOMPARE(error,  QContactManager::NoError);
478     QVERIFY(c.localId() != initialId);
479     QContact contact = trackerEngine->contact_impl(c.localId(), error);
480     QList<QContactAddress> details = contact.details<QContactAddress>();
481     QCOMPARE(details.count(), detailsAdded);
482     bool found = false;
483     // Test if inserted values are found in some of the details
484     foreach (typeAddressWithContext addressWithContext, addressValues) {
485         foreach (QContactAddress detail, details) {
486             foreach (QString field, addressWithContext.first.keys()) {
487                 found = (detail.value(field) == addressWithContext.first.value(field));
488                 if (!found)
489                     break;
490             }
491             if (found)
492                 break;
493         }
494         QVERIFY2(found, "Inserted detail was not found in the fetched details");
495     }
496 }
497
498 void ut_qtcontacts_trackerplugin::testSaveEmailAddress()
499 {
500     QContact c;
501     QContactLocalId initialId = c.localId();
502     int detailsAdded = 0;
503
504     QMap<QString,QString> values;
505     values.insert("john.does@hotmail.com", QContactDetail::ContextHome);
506     values.insert("john.doe@gmail.com", QContactDetail::ContextWork);
507     values.insert("john.doe@nokia.com", QContactDetail::ContextWork);
508     values.insert("john.doe@johndoe.com", QContactDetail::ContextHome);
509     foreach(QString address, values.keys()) {
510         QContactEmailAddress emailAddress;
511         emailAddress.setEmailAddress(address);
512         emailAddress.setContexts(values.value(address));
513         c.saveDetail(&emailAddress);
514         detailsAdded++;
515     }
516     QContactName name;
517     name.setFirstName("Jo");
518     name.setLastName("H N Doe");
519     c.saveDetail(&name);
520     trackerEngine->saveContact(&c, error);
521     QCOMPARE(error,  QContactManager::NoError);
522     QVERIFY(c.localId() != initialId);
523     QContact contact = trackerEngine->contact_impl(c.localId(), error);
524     QList<QContactEmailAddress> details = contact.details<QContactEmailAddress>();
525     QCOMPARE(details.count(), detailsAdded);
526     foreach (QContactEmailAddress detail, details) {
527         QString address = detail.value(QContactEmailAddress::FieldEmailAddress);
528         QVERIFY(values.contains(address));
529         QCOMPARE(detail.contexts()[0], values.value(address));
530     }
531 }
532
533 void ut_qtcontacts_trackerplugin::testRemoveContact()
534 {
535     QContact c;
536     QContactPhoneNumber phone;
537     phone.setNumber("+358501234567");
538     c.saveDetail(&phone);
539     QContactEmailAddress email;
540     email.setEmailAddress("super.man@hotmail.com");
541     c.saveDetail(&email);
542     QContactName name;
543     name.setFirstName("Super");
544     name.setLastName("Man");
545     c.saveDetail(&name);
546
547     QVERIFY2(trackerEngine->saveContact(&c, error) && error == QContactManager::NoError, "Saving a contact failed");
548     QVERIFY2(trackerEngine->removeContact(c.localId(), error), "Removing a contact failed");
549     QCOMPARE(error, QContactManager::NoError);
550     QVERIFY2(trackerEngine->contact_impl(c.localId(), error) == QContact(), "Found a contact, which should have been removed");
551 }
552
553 void ut_qtcontacts_trackerplugin::testSaveContacts()
554 {
555     QList<QContact> contacts;
556     for (int i = 0; i < 3; i++) {
557         QContact c;
558         QContactName name;
559         name.setFirstName("John");
560         name.setLastName(QString::number(i,10));
561         c.saveDetail(&name);
562         contacts.append(c);
563     }
564
565     QMap<int, QContactManager::Error>* errorMap;    
566     trackerEngine->saveContacts(&contacts, errorMap, error);
567     QCOMPARE(error, QContactManager::NoError);
568     for (int i = 0; i < contacts.count(); i++) {
569         QVERIFY(contacts[i].localId() != 0);
570         QList<QContactName> details = trackerEngine->contact_impl(contacts[i].localId(), error).details<QContactName>();
571         QVERIFY(details.count());
572         QCOMPARE(details.at(0).lastName(),
573                  QString("%1").arg(QString::number(i,10)));
574     }
575 }
576
577 void ut_qtcontacts_trackerplugin::testRemoveContacts()
578 {
579     QList<QContactLocalId> addedIds;
580     for (int i = 0; i < 5; i++) {
581         QContact c;
582         QContactName name;
583         name.setFirstName(QString("John%1").arg(QString::number(i,10)));
584         c.saveDetail(&name);
585         QVERIFY2(trackerEngine->saveContact(&c, error) && error == QContactManager::NoError, "Saving a contact failed");
586         addedIds.append(c.localId());
587     }
588     QList<QContactLocalId> toApiRemove;
589     toApiRemove.append(addedIds.takeLast());
590     toApiRemove.append(addedIds.takeLast());
591     QList<QContactLocalId> toPluginRemove(addedIds);
592     // Remove all, but last of the added contacts
593     bool success = trackerEngine->removeContacts(&toPluginRemove, errorMap, error);
594     QCOMPARE(success, true);
595     for (int i = 0; i < errorMap->count(); i++) {
596         QVERIFY(toPluginRemove[i] == 0);
597     }
598     QCOMPARE(error, QContactManager::NoError);
599
600     success = ContactManager::instance()->removeContacts(&toApiRemove, errorMap);
601     QCOMPARE(success, true);
602     for (int i = 0; i < errorMap->count(); i++) {
603         QVERIFY(toApiRemove[i] == 0);
604     }
605
606     // Try to remove some previously removed contacts, but one valid contact
607     success = trackerEngine->removeContacts(&addedIds, errorMap, error);
608     QCOMPARE(errorMap->count(), addedIds.count());
609     for (int i = 0; i < errorMap->count() - 1; i++) {
610         QVERIFY2(addedIds[i] != 0, "Manager should not mark id as zero");
611     }
612 }
613
614 void ut_qtcontacts_trackerplugin::testAvatar()
615 {
616     QContact contactWithAvatar;
617     QContactAvatar avatar;
618
619     avatar.setAvatar("file:///home/user/.contacts/avatars/default_avatar.png");
620     contactWithAvatar.saveDetail(&avatar);
621     QContactName name;
622     name.setFirstName("John");name.setLastName("A Frog");
623     contactWithAvatar.saveDetail(&name);
624     QVERIFY(trackerEngine->saveContact( &contactWithAvatar, error));
625
626     QContact c = trackerEngine->contact_impl( contactWithAvatar.localId(), error);
627     QList<QContactAvatar> avatars = c.details<QContactAvatar>();
628     QVERIFY( avatars.size() );
629     QCOMPARE( avatars[0].avatar(), avatar.avatar() );
630 }
631
632 void ut_qtcontacts_trackerplugin::testUrl()
633 {
634
635     //Context home, homepage url
636     QContact contactWithUrl1;
637     QContactUrl url1;
638     url1.setUrl("http://home.homepage");
639     url1.setContexts(QContactDetail::ContextHome);
640     url1.setSubType(QContactUrl::SubTypeHomePage);
641     QContactName name;
642     name.setFirstName("John");name.setLastName("TestUrl1");
643     contactWithUrl1.saveDetail(&name);
644     contactWithUrl1.saveDetail(&url1);
645     QVERIFY(trackerEngine->saveContact(&contactWithUrl1, error));
646
647     //Context work, homepage url
648     QContact contactWithUrl2;
649     QContactUrl url2;
650     url2.setUrl("http://work.homepage");
651     url2.setContexts(QContactDetail::ContextWork);
652     url2.setSubType(QContactUrl::SubTypeHomePage);
653     QContactName name2;
654     name2.setLastName("TestUrl2");
655     contactWithUrl2.saveDetail(&name2);
656     contactWithUrl2.saveDetail(&url2);
657     QVERIFY(trackerEngine->saveContact(&contactWithUrl2, error));
658
659     //Context home, favourite url
660     QContact contactWithUrl3;
661     QContactUrl url3;
662     url3.setUrl("http://home.favourite");
663     url3.setContexts(QContactDetail::ContextHome);
664     url3.setSubType(QContactUrl::SubTypeFavourite);
665
666     name2.setLastName("TestUrl3");
667     contactWithUrl3.saveDetail(&name2);
668     contactWithUrl3.saveDetail(&url3);
669     QVERIFY(trackerEngine->saveContact(&contactWithUrl3, error));
670
671
672     QContactLocalId id1 = contactWithUrl1.localId();
673     QContactLocalId id2 = contactWithUrl2.localId();
674     QContactLocalId id3 = contactWithUrl3.localId();
675     QCOMPARE(trackerEngine->contact_impl(id1, error).detail<QContactUrl>().url(), QString("http://home.homepage"));
676     QCOMPARE(trackerEngine->contact_impl(id2, error).detail<QContactUrl>().url(), QString("http://work.homepage"));
677     QCOMPARE(trackerEngine->contact_impl(id3, error).detail<QContactUrl>().url(), QString("http://home.favourite"));
678
679     QVERIFY(trackerEngine->contact_impl(id1, error).detail<QContactUrl>().contexts()[0] ==
680             QContactDetail::ContextHome );
681     QVERIFY(trackerEngine->contact_impl(id2, error).detail<QContactUrl>().contexts()[0] ==
682             QContactDetail::ContextWork );
683     QVERIFY(trackerEngine->contact_impl(id3, error).detail<QContactUrl>().contexts()[0] ==
684             QContactDetail::ContextHome );
685
686     QVERIFY(trackerEngine->contact_impl(id1, error).detail<QContactUrl>().subType() ==
687             QContactUrl::SubTypeHomePage );
688     QVERIFY(trackerEngine->contact_impl(id2, error).detail<QContactUrl>().subType() ==
689             QContactUrl::SubTypeHomePage );
690     QVERIFY(trackerEngine->contact_impl(id3, error).detail<QContactUrl>().subType() ==
691             QContactUrl::SubTypeFavourite );
692
693 }
694
695 /*
696 void ut_qtcontacts_trackerplugin::testGroups()
697 {
698     qDebug() << "Not implemented";
699     QVERIFY(false);
700 }
701
702 void ut_qtcontacts_trackerplugin::testGroup()
703 {
704     qDebug() << "Not implemented";
705     QVERIFY(false);
706 }
707
708 void ut_qtcontacts_trackerplugin::testSaveGroup()
709 {
710     qDebug() << "Not implemented";
711     QVERIFY(false);
712 }
713
714 void ut_qtcontacts_trackerplugin::testRemoveGroup()
715 {
716     qDebug() << "Not implemented";
717     QVERIFY(false);
718 }
719
720 void ut_qtcontacts_trackerplugin::testDetailDefinitions()
721 {
722     qDebug() << "Not implemented";
723     QVERIFY(false);
724 }
725
726 void ut_qtcontacts_trackerplugin::testDetailDefinition()
727 {
728     qDebug() << "Not implemented";
729     QVERIFY(false);
730 }
731
732 void ut_qtcontacts_trackerplugin::testSaveDetailDefinition()
733 {
734     qDebug() << "Not implemented";
735     QVERIFY(false);
736 }
737
738 void ut_qtcontacts_trackerplugin::testRemoveDetailDefinition()
739 {
740     qDebug() << "Not implemented";
741     QVERIFY(false);
742 }
743 */
744 void ut_qtcontacts_trackerplugin::testContactsAddedSince()
745 {
746     QList<QContactLocalId> addedIds;
747     QDateTime start;
748     for (int i = 0; i < 3; i++) {
749         QContact c;
750         QContactName name;
751         name.setFirstName("A"+QString::number(i));
752         QVERIFY2(c.saveDetail(&name), "Failed to save detail");
753         QVERIFY2(trackerEngine->saveContact(&c, error), "Failed to save contact");
754     }
755
756     QTest::qWait(1000);
757     start = QDateTime::currentDateTime();
758
759     for (int i = 0; i < 3; i++) {
760         QContact c;
761         QContactName name;
762         name.setFirstName("B"+QString::number(i));
763         QVERIFY2(c.saveDetail(&name), "Failed to save detail");
764         QVERIFY2(trackerEngine->saveContact(&c, error), "Failed to save contact");
765         addedIds.append(c.localId());
766     }
767
768     // now one asynchronous request to read all the
769     QContactFetchRequest request;
770     QContactChangeLogFilter filter(QContactChangeLogFilter::EventAdded);
771     filter.setSince(start);
772     request.setFilter(filter);
773
774     // here You specify which details are of interest
775     QStringList details;
776     details << QContactAvatar::DefinitionName
777             << QContactBirthday::DefinitionName
778             << QContactAddress::DefinitionName
779             << QContactEmailAddress::DefinitionName
780             << QContactDisplayLabel::DefinitionName
781             << QContactGender::DefinitionName
782             << QContactAnniversary::DefinitionName
783             << QContactName::DefinitionName
784             << QContactOnlineAccount::DefinitionName
785             << QContactOrganization::DefinitionName
786             << QContactPhoneNumber::DefinitionName;
787     request.setDefinitionRestrictions(details);
788
789     Slots slot;
790     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
791             &slot, SLOT(progress(QContactFetchRequest*, bool )));
792
793     // start. clients should, instead of following use
794     // request.setManager(trackermanagerinstance);
795     // request.start();
796     trackerEngine->startRequest(&request);
797     trackerEngine->waitForRequestFinished(&request, 10000);
798     // if it takes more, then something is wrong
799     QVERIFY(request.isFinished());
800     QCOMPARE(slot.contacts.count(), addedIds.count());
801
802     foreach(QContact cont, slot.contacts) {
803         QVERIFY2(addedIds.contains(cont.localId()), "One of the added contacts was not reported as added");
804     }
805
806     QContactLocalIdFetchRequest idreq;
807     filter.setSince(start);
808     idreq.setFilter(filter);
809
810     Slots slot2;
811     QObject::connect(&idreq, SIGNAL(progress(QContactLocalIdFetchRequest*, bool)),
812             &slot2, SLOT(progress(QContactLocalIdFetchRequest*, bool )));
813     trackerEngine->startRequest(&idreq);
814     trackerEngine->waitForRequestFinished(&idreq, 10000);
815     QVERIFY(idreq.isFinished());
816     QCOMPARE(slot2.ids.count(), addedIds.count());
817     foreach(QContactLocalId id, slot2.ids) {
818         QVERIFY2(addedIds.contains(id), "One of the added contacts was not reported as added");
819     }
820
821 }
822
823 void ut_qtcontacts_trackerplugin::testContactsModifiedSince()
824 {
825     QDateTime start;
826     QList<QContactLocalId> addedIds;
827     QList<QContactLocalId> modified;
828
829     const int contactsToAdd = 5;
830     const int contactsToModify = 3;
831     QVERIFY2(contactsToAdd >= contactsToModify, "Cannot modify more contacts than this test has added");
832     QVERIFY2(contactsToModify+1 <= contactsToAdd, "Cannot modify more contacts than this test has added");
833
834     // Add contacts with only first name and store them to list of added
835     for (int i = 0; i < contactsToAdd; i++) {
836         QContact c;
837         QContactName name;
838         name.setFirstName("A"+QString::number(i));
839         QVERIFY2(c.saveDetail(&name), "Failed to save detail");
840         QVERIFY2(trackerEngine->saveContact(&c, error), "Failed to save contact");
841         addedIds.append(c.localId());
842     }
843
844     QTest::qWait(2000);
845     start = QDateTime::currentDateTime();
846
847    // Modify and save rest of the contacts
848     for (int i = 0; i < contactsToModify; i++) {
849         QContact c = trackerEngine->contact_impl(addedIds[i], error);
850         QContactName name = c.detail<QContactName>();
851         // Modify name
852         name.setFirstName("B"+QString::number(i));
853         QVERIFY2(c.saveDetail(&name), "Failed to save detail");
854         QVERIFY2(trackerEngine->saveContact(&c, error), "Failed to save contact");
855         modified.append(c.localId());
856     }
857     // Set filter
858     QContactChangeLogFilter filter(QContactChangeLogFilter::EventChanged);
859     filter.setSince(start);
860
861     QContactLocalIdFetchRequest idfetch;
862     QContactFetchRequest fetch;
863     idfetch.setFilter(filter);
864     fetch.setFilter(filter);
865     trackerEngine->startRequest(&idfetch);
866     trackerEngine->waitForRequestFinished(&idfetch, 10000);
867     QVERIFY2(idfetch.isFinished(), "Id fetch request did not finish on time");
868     QVERIFY2(idfetch.error() == QContactManager::NoError, "Id fetch request finished with errors");
869     QList<QContactLocalId> actuallyModifiedIds = idfetch.ids();
870     trackerEngine->startRequest(&fetch);
871     trackerEngine->waitForRequestFinished(&fetch, 10000);
872     QVERIFY2(fetch.isFinished(), "Fetch request did not finish on time");
873     QVERIFY2(fetch.error() == QContactManager::NoError, "Fetch request finished with errors");
874     QList<QContact> actuallyModified = fetch.contacts();
875
876     // Num of actually modified should be same as supposedly modified
877     QCOMPARE(actuallyModifiedIds.count(), modified.count());
878     QCOMPARE(actuallyModified.count(), modified.count());
879     // All the ids of the modified contacts should be found in the result list
880     foreach (QContactLocalId id, modified) {
881         QVERIFY2(actuallyModifiedIds.contains(id), "One the modified contacts was not reported as modified");
882     }
883 }
884
885 void ut_qtcontacts_trackerplugin::testContactsRemovedSince()
886 {
887     QDateTime start = QDateTime::currentDateTime();
888     QContactChangeLogFilter filter(QContactChangeLogFilter::EventRemoved);
889     filter.setSince(start);
890     QList<QContactSortOrder> sorts;
891     QList<QContactLocalId> actuallyRemoved = trackerEngine->contactIds(filter, sorts, error);
892     QVERIFY(actuallyRemoved.isEmpty());
893     QVERIFY(error == QContactManager::NotSupportedError);
894 }
895 /*
896 void ut_qtcontacts_trackerplugin::testGroupsAddedSince()
897 {
898     qDebug() << "Not implemented";
899     QVERIFY(false);
900 }
901
902 void ut_qtcontacts_trackerplugin::testGroupsModifiedSince()
903 {
904     qDebug() << "Not implemented";
905     QVERIFY(false);
906 }
907
908 void ut_qtcontacts_trackerplugin::testGroupsRemovedSince()
909 {
910     qDebug() << "Not implemented";
911     QVERIFY(false);
912 }
913 */
914
915 void ut_qtcontacts_trackerplugin::cleanupTestCase()
916 {
917     delete trackerEngine;
918     delete errorMap;
919 }
920
921 void ut_qtcontacts_trackerplugin::cleanup()
922 {
923     foreach (QContactLocalId id, addedContacts) {
924         trackerEngine->removeContact(id, error);
925     }
926     addedContacts.clear();
927 }
928
929
930 void ut_qtcontacts_trackerplugin::testNcoTypes()
931 {
932     using namespace SopranoLive;
933
934     QList<QContactLocalId> ids;
935     RDFVariable RDFContact = RDFVariable::fromType<nco::PersonContact>();
936     RDFSelect query;
937
938     query.addColumn("contact_uri", RDFContact);
939     query.addColumn("contactId", RDFContact.property<nco::contactUID>());
940     LiveNodes ncoContacts = ::tracker()->modelQuery(query);
941     foreach( Live<nco::PersonContact> p, ncoContacts ) {
942         QVERIFY(p.hasType<nco::Contact>());
943         QVERIFY(p.hasType<nco::Role>());
944         QVERIFY(p.hasType<nco::PersonContact>());
945     }
946 }
947
948 void ut_qtcontacts_trackerplugin::testAsyncReadContacts()
949 {
950     addedContacts.clear();
951     // Add at least one contact to be sure that this doesn't fail because tracker is clean
952
953     QStringList firstNames, lastNames;
954     firstNames << "aa" << "ab" << "ac" << "dd" << "fe";
955     lastNames << "fe" << "ab" << "dd" << "dd" << "aa";
956     for (int i = 0; i < firstNames.count(); i++) {
957         QContact c;
958         QContactName name;
959         name.setFirstName(firstNames.at(i));
960         name.setLastName(lastNames.at(i));
961         QContactAvatar avatar;
962         avatar.setAvatar("default_avatar.png");
963         avatar.setSubType(QContactAvatar::SubTypeImage);
964         QVERIFY(c.saveDetail(&name));
965         QVERIFY(c.saveDetail(&avatar));
966         QVERIFY(trackerEngine->saveContact(&c, error));
967         addedContacts.append(c.localId());
968     }
969     
970     // Prepare the filter for the request - we really should test only the contact we add here.
971     QContactLocalIdFilter filter;
972     filter.setIds(addedContacts);
973
974     // this one will get complete contacts
975
976     Slots slot;
977     QContactFetchRequest request;
978     QList<QContactSortOrder> sorting;
979     QContactSortOrder sort, sort1;
980     sort.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldLast);
981     sort1.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirst);
982     sorting << sort << sort1;
983     QStringList details; details << QContactName::DefinitionName << QContactAvatar::DefinitionName;
984     request.setDefinitionRestrictions(details);
985     request.setSorting(sorting);
986     request.setFilter(filter);
987
988     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
989             &slot, SLOT(progress(QContactFetchRequest*, bool )));
990
991     // this one only ids
992     QContactLocalIdFetchRequest request1;
993     request1.setFilter(filter);
994     QObject::connect(&request1, SIGNAL(progress(QContactLocalIdFetchRequest*, bool)),
995             &slot, SLOT(progress(QContactLocalIdFetchRequest*, bool )));
996
997     // the purpose is to compare if all contacts are loaded, and
998     // if optional fields are defined properly in request
999
1000     // start both at once
1001     trackerEngine->startRequest(&request);
1002     trackerEngine->startRequest(&request1);
1003     trackerEngine->waitForRequestFinished(&request, 10000);
1004     trackerEngine->waitForRequestFinished(&request1, 10000);
1005
1006
1007     // if it takes more, then something is wrong
1008     QVERIFY(request.isFinished());
1009     QVERIFY(request1.isFinished());
1010
1011     // there need1 to be something added to be verified
1012     QVERIFY(!request.contacts().isEmpty());
1013     // now ask for one contact
1014     QVERIFY(!slot.contacts.isEmpty());
1015     // there need to be something added to be verified
1016     QVERIFY(!request1.ids().isEmpty());
1017     // now ask for one contact
1018     QVERIFY(!slot.ids.isEmpty());
1019
1020     QVERIFY2(slot.contacts.count() == slot.ids.count(), "not all contacts were loaded");
1021     QVERIFY(slot.contacts.count() >= firstNames.count());
1022     for( int i = 0; i < slot.contacts.size() -1 ; i++)
1023     {
1024         QContact contact = slot.contacts[i];
1025         QContact contact1 = slot.contacts[i+1];
1026         QString last0 = contact.detail<QContactName>().lastName();
1027         QString first0 = contact.detail<QContactName>().firstName();
1028         QString last1 = contact1.detail<QContactName>().lastName();
1029         QString first1 = contact1.detail<QContactName>().firstName();
1030         // sorting
1031         qDebug() << "contacts:" << contact.localId() << first0 << last0;
1032         bool test = last0 < last1 || (last0 == last1 && first0 <= first1);
1033         if (!test) {
1034             qDebug() << "contacts sort failed. First: " << contact1.localId() << first0 << last1 << "lasts: " << last0 << last1;
1035         }
1036         QVERIFY2(test, "Sorting failed.");
1037     }
1038
1039 }
1040
1041 void ut_qtcontacts_trackerplugin::testFilterContacts()
1042 {
1043     // this one will get complete contacts
1044     QContact c;
1045     QContactName name;
1046     name.setFirstName("Zuba");
1047     name.setLastName("Zub");
1048     c.saveDetail(&name);
1049     QContactPhoneNumber phone;
1050
1051     phone.setNumber("4872444");
1052     c.saveDetail(&phone);
1053     trackerEngine->saveContact(&c, error);
1054
1055     QStringList details;
1056     details << QContactName::DefinitionName << QContactAvatar::DefinitionName
1057             << QContactPhoneNumber::DefinitionName;
1058
1059     QContactFetchRequest request;
1060     QContactDetailFilter filter;
1061     filter.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
1062
1063     Slots slot;
1064     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
1065             &slot, SLOT(progress(QContactFetchRequest*, bool )));
1066     filter.setValue(QString("4872444"));
1067     filter.setMatchFlags(QContactFilter::MatchEndsWith);
1068
1069     request.setDefinitionRestrictions(details);
1070     request.setFilter(filter);
1071
1072     trackerEngine->startRequest(&request);
1073
1074     for(int i = 0; i < 100; i++)
1075     {
1076         usleep(100000);
1077         QCoreApplication::processEvents();
1078         if(request.isFinished() )
1079             break;
1080     }
1081
1082     // if it takes more, then something is wrong
1083     QVERIFY(request.isFinished());
1084     QVERIFY(!request.contacts().isEmpty());
1085
1086     QVERIFY(!slot.contacts.isEmpty());
1087
1088     bool containsThisId = false;
1089     foreach(const QContact &contact, slot.contacts)
1090     {
1091         if( contact.localId() == c.localId())
1092             containsThisId = true;
1093         bool containsPhone = false;
1094         foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName))
1095         {
1096             if(detail.value(QContactPhoneNumber::FieldNumber).contains("4872444"))
1097             {
1098                 containsPhone = true;
1099                 break;
1100             }
1101         }
1102         QVERIFY(containsPhone);
1103     }
1104     QVERIFY(containsThisId);
1105 }
1106
1107 void ut_qtcontacts_trackerplugin::testFilterContactsEndsWith()
1108 {
1109     QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Nokia", "Trackerplugin");
1110     QString restoreValue = settings.value("phoneNumberMatchDigitCount", "7").toString();
1111
1112     QContact matchingContact;
1113     QContactName name;
1114     name.setFirstName("Zuba");
1115     name.setLastName("Zub");
1116     matchingContact.saveDetail(&name);
1117     QContactPhoneNumber phone;
1118     // TODO doesnt work yet phone.setContexts(QContactPhoneNumber::ContextWork);
1119     phone.setNumber("3210987654321");
1120     matchingContact.saveDetail(&phone);
1121     trackerEngine->saveContact(&matchingContact, error);
1122
1123     QStringList details;
1124     details << QContactName::DefinitionName << QContactAvatar::DefinitionName
1125             << QContactPhoneNumber::DefinitionName;
1126
1127     QContactFetchRequest request;
1128     QContactDetailFilter filter;
1129     filter.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
1130
1131     Slots slot;
1132     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
1133             &slot, SLOT(progress(QContactFetchRequest*, bool )));
1134
1135     {
1136         // test matching of 7 last digits
1137         int matchCount = 7;
1138         qDebug() << "Test matching of" << matchCount << "last digits.";
1139         settings.setValue("phoneNumberMatchDigitCount", matchCount);
1140         QString matchValue = "3000007654321";
1141         QContact nonMatchingContact;
1142         nonMatchingContact.saveDetail(&name);
1143         phone.setNumber("3210980654321");
1144         nonMatchingContact.saveDetail(&phone);
1145         trackerEngine->saveContact(&nonMatchingContact, error);
1146
1147         filter.setValue(matchValue);
1148         filter.setMatchFlags(QContactFilter::MatchEndsWith);
1149
1150         request.setDefinitionRestrictions(details);
1151         request.setFilter(filter);
1152
1153         trackerEngine->startRequest(&request);
1154
1155         for(int i = 0; i < 100; i++) {
1156             usleep(100000);
1157             QCoreApplication::processEvents();
1158             if (request.isFinished())
1159                 break;
1160         }
1161         QVERIFY(request.isFinished());
1162         QVERIFY(!slot.contacts.isEmpty());
1163
1164         bool containsMatchingId = false;
1165         bool containsNonMatchingId = false;
1166         foreach(const QContact &contact, slot.contacts) {
1167             if (contact.localId() == nonMatchingContact.localId())
1168                 containsNonMatchingId = true;
1169             if (contact.localId() == matchingContact.localId())
1170                 containsMatchingId = true;
1171             bool containsPhone = false;
1172             foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName)) {
1173                 if (detail.value(QContactPhoneNumber::FieldNumber).endsWith(matchValue.right(matchCount))) {
1174                     containsPhone = true;
1175                     break;
1176                 }
1177             }
1178             QVERIFY(containsPhone);
1179         }
1180         QVERIFY(containsMatchingId);
1181         QVERIFY(!containsNonMatchingId);
1182     }
1183
1184     {
1185         // test matching of 11 last digits
1186         int matchCount = 11;
1187         qDebug() << "Test matching of" << matchCount << "last digits.";
1188         settings.setValue("phoneNumberMatchDigitCount", matchCount);
1189         QString matchValue = "3010987654321";
1190         QContact nonMatchingContact;
1191         nonMatchingContact.saveDetail(&name);
1192         phone.setNumber("3200987654321");
1193         nonMatchingContact.saveDetail(&phone);
1194         trackerEngine->saveContact(&nonMatchingContact, error);
1195
1196         QContact matchingContactWithShorterNumber;
1197         QContactName name1;
1198         name1.setFirstName("ShortNumber");
1199         name1.setLastName("Zub1");
1200         matchingContactWithShorterNumber.saveDetail(&name1);
1201         QContactPhoneNumber phone1;
1202         phone1.setNumber("54321");
1203         matchingContactWithShorterNumber.saveDetail(&phone1);
1204         trackerEngine->saveContact(&matchingContactWithShorterNumber, error);
1205         QVERIFY(QContactManager::NoError == error);
1206
1207
1208         filter.setValue(matchValue);
1209         filter.setMatchFlags(QContactFilter::MatchEndsWith);
1210
1211         request.setDefinitionRestrictions(details);
1212         request.setFilter(filter);
1213
1214         trackerEngine->startRequest(&request);
1215
1216         for(int i = 0; i < 100; i++) {
1217             usleep(100000);
1218             QCoreApplication::processEvents();
1219             if (request.isFinished())
1220                 break;
1221         }
1222         QVERIFY(request.isFinished());
1223         QVERIFY(!slot.contacts.isEmpty());
1224
1225         bool containsMatchingId = false;
1226         bool containsNonMatchingId = false;
1227         foreach(const QContact &contact, slot.contacts) {
1228             if (contact.localId() == nonMatchingContact.localId())
1229                 containsNonMatchingId = true;
1230             if (contact.localId() == matchingContact.localId())
1231                 containsMatchingId = true;
1232             bool containsPhone = false;
1233             foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName)) {
1234                 if (detail.value(QContactPhoneNumber::FieldNumber).endsWith(matchValue.right(matchCount))) {
1235                     containsPhone = true;
1236                     break;
1237                 }
1238             }
1239             QVERIFY(containsPhone);
1240         }
1241         QVERIFY(containsMatchingId);
1242         QVERIFY(!containsNonMatchingId);
1243
1244         // now verify with short number
1245         filter.setValue("54321");
1246         filter.setMatchFlags(QContactFilter::MatchEndsWith);
1247
1248         request.setDefinitionRestrictions(details);
1249         request.setFilter(filter);
1250
1251         trackerEngine->startRequest(&request);
1252
1253         for(int i = 0; i < 100; i++) {
1254             usleep(100000);
1255             QCoreApplication::processEvents();
1256             if (request.isFinished())
1257                 break;
1258         }
1259         QVERIFY(request.isFinished());
1260         QVERIFY(!slot.contacts.isEmpty());
1261         bool containsShort = false;
1262         foreach(const QContact &contact, slot.contacts) {
1263             if (contact.localId() == matchingContactWithShorterNumber.localId())
1264                 containsShort = true;
1265         }
1266         QVERIFY(containsShort);
1267     }
1268     settings.setValue("phoneNumberMatchDigitCount", restoreValue);
1269 }
1270
1271 void ut_qtcontacts_trackerplugin::testFilterTwoNameFields()
1272 {
1273     // init test
1274     QMap<QContactLocalId, QContactName> names;
1275     for (int i = 0; i < 3; i++) {
1276         QContact c;
1277         QContactName name;
1278         name.setFirstName(QUuid::createUuid().toString() + QString::number(i));
1279         name.setLastName(QUuid::createUuid().toString() + QString::number(i));
1280         c.saveDetail(&name);
1281         QContactAvatar avatar;
1282         avatar.setAvatar(QUuid::createUuid().toString());
1283         c.saveDetail(&avatar);
1284         QVERIFY(trackerEngine->saveContact(&c, error));        
1285         names.insert(c.localId(), name);
1286         QCOMPARE(error, QContactManager::NoError);
1287         addedContacts.append(c.localId());
1288     }
1289
1290     // Init filter
1291     QContactLocalId searchId = names.keys().at(1);
1292     QString searchFirst = names.value(searchId).firstName();
1293     QString searchLast = names.value(searchId).lastName();
1294     QContactUnionFilter ufilter;
1295     QContactDetailFilter filterFirst;
1296     filterFirst.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirst);
1297     filterFirst.setMatchFlags(QContactFilter::MatchExactly);
1298     filterFirst.setValue(searchFirst);
1299     QContactDetailFilter filterLast;
1300     filterLast.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldLast);
1301     filterLast.setMatchFlags(QContactFilter::MatchExactly);
1302     filterLast.setValue(searchLast);
1303     ufilter.setFilters(QList<QContactFilter>() << filterFirst << filterLast);
1304
1305     // Init request
1306     QContactFetchRequest request;
1307     request.setFilter(ufilter);
1308     trackerEngine->startRequest(&request);
1309     trackerEngine->waitForRequestFinished(&request, 10000);
1310
1311
1312     // Test fetch result
1313     QCOMPARE(request.contacts().count(), 1);
1314     QCOMPARE(request.contacts().at(0).localId(), searchId);
1315     QCOMPARE(request.contacts().at(0).detail<QContactName>().firstName(), searchFirst);
1316     QCOMPARE(request.contacts().at(0).detail<QContactName>().lastName(), searchLast);
1317 }
1318
1319 void ut_qtcontacts_trackerplugin::testTrackerUriToUniqueId()
1320 {
1321     QString uri = "contact:1234567";
1322     QContactLocalId id = url2UniqueId( uri );
1323     QCOMPARE( (int)id, 1234567 );
1324 }
1325
1326 void ut_qtcontacts_trackerplugin::testQRelationshipAndMetacontacts()
1327 {
1328     QContact firstContact;
1329     QContactName name;
1330     name.setFirstName("FirstMeta");
1331     firstContact.saveDetail(&name);
1332     QVERIFY(trackerEngine->saveContact(&firstContact, error));
1333
1334     QList<QContactLocalId> secondIds;
1335     QStringList names(QStringList()<<"SecondMeta"<<"ThirdMeta");
1336     foreach (QString firstname, names)
1337     {
1338         QContact secondContact;
1339         QContactName name1;
1340         name1.setFirstName(firstname);
1341         secondContact.saveDetail(&name1);
1342         QVERIFY(trackerEngine->saveContact(&secondContact, error));
1343         secondIds<<secondContact.id().localId();
1344         QContactRelationship rel;
1345         rel.setRelationshipType(QContactRelationship::Is);
1346         rel.setFirst(firstContact.id());
1347         rel.setSecond(secondContact.id());
1348         QContactRelationshipSaveRequest req;
1349         req.setRelationships(QList<QContactRelationship>()<<rel);
1350         QVERIFY(trackerEngine->startRequest(&req));
1351         trackerEngine->waitForRequestFinished(&req, 10000);
1352         // if it takes more, then something is wrong
1353         QVERIFY(req.isFinished());
1354         QVERIFY(QContactManager::NoError == req.error());
1355     }
1356
1357     QContactRelationshipFetchRequest req1;
1358     req1.setFirst(firstContact.id());
1359     QVERIFY(trackerEngine->startRequest(&req1));
1360     trackerEngine->waitForRequestFinished(&req1, 10000);
1361     // if it takes more, then something is wrong
1362     QVERIFY(req1.isFinished());
1363     QVERIFY(QContactManager::NoError == req1.error());
1364     QVERIFY(2 == req1.relationships().size());
1365     foreach(QContactRelationship r, req1.relationships())
1366     {
1367         QVERIFY(secondIds.removeOne(r.second().localId()));
1368     }
1369 }
1370
1371 void ut_qtcontacts_trackerplugin::insertContact(const QString& URI, QContactLocalId uid, QString imId, QString imStatus, QString accountPath, QString protocol )
1372 {
1373     QProcess inserter;
1374     QStringList args;
1375     args << URI << QString::number(uid) << imId << accountPath << imStatus << "In Helsinki" << protocol << "Some" << "Guy";
1376     inserter.start( PATH_TO_SPARQL_TESTS+"/insertTpContact.sparql", args );
1377     inserter.waitForFinished();
1378 }
1379
1380 void ut_qtcontacts_trackerplugin::updateIMContactStatus(const QString& uri, QString imStatus)
1381 {
1382     QProcess inserter;
1383     QStringList args;
1384     args << uri << imStatus;
1385     inserter.start( PATH_TO_SPARQL_TESTS+"/updateTpStatus.sparql", args );
1386     inserter.waitForFinished();
1387 }
1388
1389 void ut_qtcontacts_trackerplugin::testIMContactsAndMetacontactMasterPresence()
1390 {
1391     if( !QFileInfo(PATH_TO_SPARQL_TESTS).exists() )
1392     {
1393         qWarning()<<Q_FUNC_INFO<<"is disabled - test scripts are not installed";
1394         return;
1395     }
1396     QList<unsigned int> idstoremove;
1397     QContactLocalId masterContactId; // using one master contact later for additional testing
1398     for( int i = 0; i < 2; i++ )
1399     {
1400         unsigned int contactid = qHash(QString("/org/freedesktop/fake/account/") + QString::number(999998+i) + "@ovi.com");
1401         idstoremove << contactid;
1402         insertContact(QString("telepathy://org/freedesktop/fake/account/") + QString::number(999998+i) + "@ovi.com",
1403                 contactid, QString::number(999998 + i)+ "@ovi.com", "nco:presence-status-available", QString("http://www.sopranolive.org/backends/tracker/generated_unique_id/105323876#%1").arg(999998+i),"ovi.com");
1404         QContact c = contact(contactid, QStringList()<<QContactOnlineAccount::DefinitionName);
1405         QVERIFY(c.localId() == contactid);
1406         QVERIFY(c.detail<QContactOnlineAccount>().serviceProvider() == "ovi.com");
1407         QContact firstContact;
1408         QContactName name;
1409         name.setFirstName("FirstMetaWithIM"+QString::number(contactid));
1410         firstContact.saveDetail(&name);
1411         QVERIFY(trackerEngine->saveContact(&firstContact, error));
1412
1413         // save metarelationship
1414         QContactRelationship rel;
1415         rel.setRelationshipType(QContactRelationship::Is);
1416         rel.setFirst(firstContact.id());
1417         idstoremove << firstContact.localId();
1418         masterContactId = firstContact.localId();
1419         rel.setSecond(c.id());
1420         QContactRelationshipSaveRequest req;
1421         req.setRelationships(QList<QContactRelationship>()<<rel);
1422         QVERIFY(trackerEngine->startRequest(&req));
1423         trackerEngine->waitForRequestFinished(&req, 1000);
1424         QVERIFY(req.isFinished());
1425         QVERIFY(QContactManager::NoError == req.error());
1426     }
1427
1428     // expected behavior - for now - is that master contact contains details from
1429     // IMContacts - that way we don't have to use QContactRelationships to fetch
1430     // all contacts in master contact in order to calculate master presence
1431     {
1432         QList<QContact> cons = contacts(QList<QContactLocalId> ()
1433                 << masterContactId << qHash(QString("/org/freedesktop/fake/account/") + QString::number(999999) + "@ovi.com"), QStringList()
1434                 << QContactOnlineAccount::DefinitionName);
1435         QVERIFY(cons.size() == 1);
1436         QVERIFY(cons[0].id().localId() == masterContactId);
1437
1438         bool containDetail = false;
1439         foreach(QContactOnlineAccount det, cons[0].details<QContactOnlineAccount>())
1440             {
1441                 if (det.value("Account") == "999999@ovi.com" // deprecated, going to account URI
1442                         || det.accountUri() == "999999@ovi.com")
1443                 {
1444                     QVERIFY(det.presence() == QContactOnlineAccount::PresenceAvailable);
1445                     // keeping the reference to tp contact
1446                     QVERIFY(det.value("QContactLocalId") == QString::number(qHash(QString("/org/freedesktop/fake/account/") + QString::number(999999) + "@ovi.com")));
1447                     containDetail = true;
1448                 }
1449             }
1450         QVERIFY(containDetail);
1451     }
1452     //now update presence to IM contact and check it in metacontact (TODO and if signal is emitted)
1453     updateIMContactStatus(QString("telepathy://org/freedesktop/fake/account/") + QString::number(999999) + "@ovi.com", "nco:presence-status-offline");
1454     {
1455         QList<QContact> cons = contacts(QList<QContactLocalId> ()
1456                 << masterContactId << qHash(QString("/org/freedesktop/fake/account/") + QString::number(999999) + "@ovi.com"), QStringList()
1457                 << QContactOnlineAccount::DefinitionName);
1458         QVERIFY(cons.size() == 1);
1459         QVERIFY(cons[0].id().localId() == masterContactId);
1460
1461         bool containDetail = false;
1462         foreach(QContactOnlineAccount det, cons[0].details<QContactOnlineAccount>())
1463             {
1464                 if (det.value("Account") == "999999@ovi.com" // deprecated, going to account URI
1465                         || det.accountUri() == "999999@ovi.com")
1466                 {
1467                     QVERIFY(det.presence() == QContactOnlineAccount::PresenceOffline);
1468                     // keeping the reference to tp contact
1469                     QVERIFY(det.value("QContactLocalId") == QString::number(qHash(QString("/org/freedesktop/fake/account/") + QString::number(999999) + "@ovi.com")));
1470                     containDetail = true;
1471                 }
1472             }
1473         QVERIFY(containDetail);
1474     }
1475
1476     // TODO load only one contact should load also content from other in the same metacontacts
1477     {
1478         QList<QContact> cons = contacts(QList<QContactLocalId> ()
1479                 << masterContactId, QStringList()
1480                 << QContactOnlineAccount::DefinitionName);
1481         QVERIFY(cons.size() == 1);
1482         QVERIFY(cons[0].id().localId() == masterContactId);
1483
1484         bool containDetail = false;
1485         foreach(QContactOnlineAccount det, cons[0].details<QContactOnlineAccount>())
1486             {
1487                 if (det.value("Account") == "999999@ovi.com" // deprecated, going to account URI
1488                         || det.accountUri() == "999999@ovi.com")
1489                 {
1490                     QVERIFY(det.presence() == QContactOnlineAccount::PresenceOffline);
1491                     // keeping the reference to tp contact
1492                     QVERIFY(det.value("QContactLocalId") == QString::number(qHash(QString("/org/freedesktop/fake/account/") + QString::number(999999) + "@ovi.com")));
1493                     containDetail = true;
1494                 }
1495             }
1496         QVERIFY(containDetail);
1497     }
1498
1499     // remove them
1500     foreach(unsigned int id, idstoremove)
1501     {
1502         QVERIFY2(trackerEngine->removeContact(id, error), "Removing a contact failed");
1503     }
1504 }
1505
1506 void ut_qtcontacts_trackerplugin::testIMContactsFilterring()
1507 {
1508     QList<unsigned int> idstoremove;
1509     QList<QContactLocalId> idsToRetrieveThroughFilter;
1510     for( int i = 0; i < 3; i++ )
1511     {
1512         unsigned int contactid = qHash(QString("/org/freedesktop/fake/account/") + QString::number(999995+i) + "@ovi.com");
1513         idstoremove << contactid;
1514         insertContact(QString("telepathy://org/freedesktop/fake/account/") + QString::number(999995+i) + "@ovi.com",
1515                 contactid, QString::number(999995 + i)+ "@ovi.com", "nco:presence-status-available",
1516                 QString("www.sopranolive.org/backends/tracker/generated_unique_id/105323876#ovi%1").arg(i/2), QString("ovi%1.com").arg(i/2));
1517         if(!i/2)
1518             idsToRetrieveThroughFilter << contactid;
1519     }
1520
1521
1522     {
1523     // now filter by service provider ovi0.com needs to return 2 contacts, 999995 & 999996
1524     QList<QContactLocalId> ids(idsToRetrieveThroughFilter);
1525
1526     QContactFetchRequest request;
1527     QContactDetailFilter filter;
1528     filter.setDetailDefinitionName(QContactOnlineAccount::DefinitionName, QContactOnlineAccount::FieldServiceProvider);
1529
1530     Slots slot;
1531     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
1532             &slot, SLOT(progress(QContactFetchRequest*, bool )));
1533     filter.setValue(QString("ovi0.com"));
1534     filter.setMatchFlags(QContactFilter::MatchExactly);
1535
1536     request.setDefinitionRestrictions(QStringList()<<QContactOnlineAccount::DefinitionName);
1537     request.setFilter(filter);
1538
1539     trackerEngine->startRequest(&request);
1540
1541     for(int i = 0; i < 100; i++)
1542     {
1543         usleep(100000);
1544         QCoreApplication::processEvents();
1545         if(request.isFinished() )
1546             break;
1547     }
1548
1549     // if it takes more, then something is wrong
1550     QVERIFY(request.isFinished());
1551     QVERIFY(!request.contacts().isEmpty());
1552
1553     QVERIFY(request.contacts().size() >= 2);
1554     foreach(const QContact &contact, request.contacts())
1555     {
1556         QVERIFY(contact.detail<QContactOnlineAccount>().serviceProvider() == "ovi0.com");
1557         ids.removeOne(contact.localId());
1558     }
1559     QVERIFY(ids.isEmpty());
1560     }
1561
1562     // now account path filter
1563     {
1564     // now filter by account path 999995 & 999996
1565     QList<QContactLocalId> ids(idsToRetrieveThroughFilter);
1566
1567     QContactFetchRequest request;
1568     QContactDetailFilter filter;
1569     filter.setDetailDefinitionName(QContactOnlineAccount::DefinitionName, "AccountPath");
1570
1571     Slots slot;
1572     QObject::connect(&request, SIGNAL(progress(QContactFetchRequest*, bool)),
1573             &slot, SLOT(progress(QContactFetchRequest*, bool )));
1574     // see insertTpContact
1575     filter.setValue(QString("www.sopranolive.org/backends/tracker/generated_unique_id/105323876#ovi0"));
1576     filter.setMatchFlags(QContactFilter::MatchExactly);
1577
1578     request.setDefinitionRestrictions(QStringList()<<QContactOnlineAccount::DefinitionName);
1579     request.setFilter(filter);
1580
1581     trackerEngine->startRequest(&request);
1582
1583     for(int i = 0; i < 100; i++)
1584     {
1585         usleep(100000);
1586         QCoreApplication::processEvents();
1587         if(request.isFinished() )
1588             break;
1589     }
1590
1591     // if it takes more, then something is wrong
1592     QVERIFY(request.isFinished());
1593     QVERIFY(!request.contacts().isEmpty());
1594
1595     QVERIFY(request.contacts().size() >= 2);
1596     foreach(const QContact &contact, request.contacts())
1597     {
1598         QVERIFY(contact.detail<QContactOnlineAccount>().serviceProvider() == "ovi0.com");
1599         ids.removeOne(contact.localId());
1600     }
1601     QVERIFY(ids.isEmpty());
1602     }
1603
1604
1605     // remove them
1606     foreach(unsigned int id, idstoremove)
1607     {
1608         QVERIFY2(trackerEngine->removeContact(id, error), "Removing a contact failed");
1609     }
1610
1611 }
1612
1613 void ut_qtcontacts_trackerplugin::testContactsWithoutMeContact() {
1614     QContact c;
1615     QContactName name;
1616     name.setFirstName("Totally");
1617     name.setLastName("Unique");
1618     c.saveDetail(&name);
1619     trackerEngine->saveContact(&c, error);
1620     QContactLocalId id = c.localId();  // Store ID for later removal. 
1621     
1622     // Prepare the filter for the request - we fetch only the one contact saved above.
1623     QList<QContactLocalId> ids;
1624     ids << id;
1625     QContactLocalIdFilter filter;
1626     filter.setIds(ids);
1627     
1628     // Prepare the requst - give filter to it and specify which fields to fetch. We fetch only the name.
1629     QStringList details;
1630     details << QContactName::DefinitionName;
1631
1632     QContactLocalIdFetchRequest nameFetchRequest;
1633     nameFetchRequest.setFilter(filter);
1634
1635     // Start the request and wait for it to finish.
1636     trackerEngine->startRequest(&nameFetchRequest);
1637     trackerEngine->waitForRequestFinished(&nameFetchRequest, 1000);
1638
1639     // Requst finished. Test that only one contact is removed.
1640     QList<QContactLocalId> contacts = nameFetchRequest.ids();
1641     QVERIFY2(contacts.count() < 2, "We expected to get only one contact. Got more.");
1642     QVERIFY2(contacts.count() != 0, "We expected to get one contact. Got none.");
1643     QVERIFY2(contacts.first() == id, "Did not get the requested contact back.");
1644     
1645     // Cleaning up.
1646     trackerEngine->removeContact(id, error);
1647
1648 }
1649
1650 /***************************     Helper functions for unit tests   ***************'*/
1651
1652 QContact ut_qtcontacts_trackerplugin::contact(QContactLocalId id, QStringList details)
1653 {
1654     QList<QContact> conts = contacts(QList<QContactLocalId>()<<id, details);
1655     return conts.size()?conts[0]:QContact();
1656 }
1657
1658 QList<QContact> ut_qtcontacts_trackerplugin::contacts(QList<QContactLocalId> ids, QStringList details)
1659 {
1660     QContactFetchRequest request;
1661     QContactLocalIdFilter filter;
1662     filter.setIds(ids);
1663     request.setFilter(filter);
1664
1665     request.setDefinitionRestrictions(details);
1666
1667     trackerEngine->startRequest(&request);
1668     trackerEngine->waitForRequestFinished(&request, 1000);
1669
1670     return request.contacts();
1671 }
1672
1673 void Slots::progress(QContactLocalIdFetchRequest* self, bool appendOnly)
1674 {
1675     Q_UNUSED(appendOnly)
1676     if( self->state() == QContactAbstractRequest::FinishedState )
1677     {
1678         ids << self->ids();
1679     }
1680 }
1681
1682 void Slots::progress(QContactFetchRequest* self, bool appendOnly)
1683 {
1684     Q_UNUSED(appendOnly)
1685     contacts = self->contacts();
1686     QList<QContactLocalId> idsFromAllContactReq;
1687     foreach( QContact contact, contacts)
1688     {
1689         idsFromAllContactReq << contact.localId();
1690     }
1691 }
1692
1693 QString Slots::requestStatusToString(QContactAbstractRequest::Status status)
1694 {
1695     switch (status) {
1696         case QContactAbstractRequest::Inactive:
1697             return "Inactive";
1698         case QContactAbstractRequest::Active:
1699             return "Active";
1700         case QContactAbstractRequest::Cancelling:
1701             return "Cancelling";
1702         case QContactAbstractRequest::Cancelled:
1703             return "Cancelled";
1704         case QContactAbstractRequest::Finished:
1705             return "Finished";
1706         default:
1707             return QString::number((int)status);
1708     }
1709 }
1710
1711 QTEST_MAIN(ut_qtcontacts_trackerplugin)