Changes: Also save modified contacts when fuzzing
[qtcontacts-tracker:hasselmms-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 #include "slots.h"
44
45 #include <dao/classhierarchy.h>
46 #include <dao/conversion.h>
47 #include <dao/settings.h>
48 #include <dao/support.h>
49
50 #include <engine/engine.h>
51 #include <engine/contactidfetchrequest.h>
52 #include <engine/relationshipsaverequest.h>
53 #include <engine/relationshipfetchrequest.h>
54 #include <engine/trackerchangelistener.h>
55
56 #include <QtTracker/ontologies/nco.h>
57 #include <QtTracker/ontologies/nie.h>
58
59 typedef QPair<QContactDetail, QString> ContactDetailSample;
60 typedef QPair<QString, QString> PairOfStrings;
61
62 static ContactDetailSample makeDetailSample(const QContactDetail &detail, const QString &value)
63 {
64     return qMakePair(detail, value);
65 }
66
67 static ContactDetailSample makeDetailSample(const QString &detailName,
68                                             const QString &fieldName,
69                                             const QString &value)
70 {
71     QContactDetail detail(detailName);
72     detail.setValue(fieldName, value);
73     return qMakePair(detail, value);
74 }
75
76 ut_qtcontacts_trackerplugin::ut_qtcontacts_trackerplugin(QObject *parent) :
77         ut_qtcontacts_trackerplugin_common(QDir(DATADIR), QDir(SRCDIR), parent)
78 {
79 }
80
81 void ut_qtcontacts_trackerplugin::initTestCase()
82 {
83     ::BackEnds::Tracker::tracker()->rawLoad(referenceFileUrl("test-account-1.ttl"));
84 }
85
86 void ut_qtcontacts_trackerplugin::testContacts()
87 {
88     QContact c1, c2;
89
90     QContactManager::Error error;
91
92     error = QContactManager::UnspecifiedError;
93     QVERIFY(engine()->saveContact(&c1, &error));
94     QCOMPARE(error, QContactManager::NoError);
95
96     error = QContactManager::UnspecifiedError;
97     QVERIFY(engine()->saveContact(&c2, &error));
98     QCOMPARE(error, QContactManager::NoError);
99
100     error = QContactManager::UnspecifiedError;
101
102     QContactFilter filter;
103     QList<QContactSortOrder> sortOrders;
104     QList<QContactLocalId> contacts(engine()->contactIds(filter, sortOrders, &error));
105     QCOMPARE(error, QContactManager::NoError);
106
107     QVERIFY2(contacts.contains(c1.localId()), "Previously added contact is not found");
108     QVERIFY2(contacts.contains(c2.localId()), "Previously added contact is not found");
109 }
110
111 void ut_qtcontacts_trackerplugin::testContact()
112 {
113     // Test invalid contact id
114     QContactManager::Error error;
115     const QContactFetchHint hints;
116
117     error = QContactManager::UnspecifiedError;
118     QContact invalidContact = engine()->contactImpl( -1, hints, &error);
119     QVERIFY(error != QContactManager::NoError);
120
121     // Add a contact
122     QContact newContact;
123     const QContactLocalId oldid = newContact.localId();
124     error = QContactManager::UnspecifiedError;
125     QVERIFY(engine()->saveContact(&newContact, &error));
126     QCOMPARE(error, QContactManager::NoError);
127
128     QContactLocalId id = newContact.localId();
129     QVERIFY(id != oldid);
130
131     // Find the added contact
132     error = QContactManager::UnspecifiedError;
133     QContact c = engine()->contactImpl(id, hints, &error);
134     QCOMPARE(c.localId(), newContact.localId());
135     QCOMPARE(error, QContactManager::NoError);
136 }
137
138 void ut_qtcontacts_trackerplugin::testSaveFullname()
139 {
140     const QString fullname = "A Full Name";
141
142     QList<QContact> contacts = parseVCards(referenceFileName("fullname.vcf"), 1);
143     QVERIFY(not contacts.isEmpty());
144
145     QContactName name = contacts.first().detail<QContactName>();
146     QCOMPARE(name.customLabel(), fullname);
147
148     QContactManager::Error error = QContactManager::UnspecifiedError;
149     bool success = engine()->saveContact(&contacts.first(), &error);
150     QCOMPARE(error, QContactManager::NoError);
151     QVERIFY(0 != contacts.first().localId());
152     QVERIFY(success);
153
154     name = contact(contacts.first().localId()).detail<QContactName>();
155     QCOMPARE(name.customLabel(), fullname);
156 }
157
158 void ut_qtcontacts_trackerplugin::testSaveName()
159 {
160     QContact c;
161     QContactLocalId initialId = c.localId();
162     int detailsAdded = 0;
163
164     QMap<QString,QString> nameValues;
165     QContactName name;
166
167     nameValues.insert(QContactName::FieldPrefix, "Mr");
168     nameValues.insert(QContactName::FieldFirstName, "John");
169     nameValues.insert(QContactName::FieldMiddleName, "Rupert");
170     nameValues.insert(QContactName::FieldLastName, "Doe");
171     nameValues.insert(QContactName::FieldSuffix, "III");
172     nameValues.insert(QContactName::FieldCustomLabel, "The Duke");
173
174     foreach (QString field, nameValues.keys()) {
175         name.setValue(field, nameValues.value(field));
176     }
177     c.saveDetail(&name);
178
179     QContactNickname nick;
180     nick.setValue(QLatin1String(QContactNickname::FieldNickname), "Johnny");
181     c.saveDetail(&nick);
182
183     QCOMPARE(c.detail<QContactName>().prefix(), QLatin1String("Mr"));
184     QCOMPARE(c.detail<QContactName>().firstName(), QLatin1String("John"));
185     QCOMPARE(c.detail<QContactName>().middleName(), QLatin1String("Rupert"));
186     QCOMPARE(c.detail<QContactName>().lastName(), QLatin1String("Doe"));
187     QCOMPARE(c.detail<QContactName>().suffix(), QLatin1String("III"));
188     QCOMPARE(c.detail<QContactName>().customLabel(), QLatin1String("The Duke"));
189     QCOMPARE(c.detail<QContactNickname>().nickname(), QLatin1String("Johnny"));
190
191     detailsAdded++;
192
193     QContactManager::Error error(QContactManager::UnspecifiedError);
194     QVERIFY(engine()->saveContact(&c, &error));
195     QCOMPARE(error,  QContactManager::NoError);
196     QVERIFY(c.localId() != initialId);
197     QContact contact = this->contact(c.localId());
198     QList<QContactName> details = contact.details<QContactName>();
199     QList<QContactNickname> details2 = contact.details<QContactNickname>();
200     QCOMPARE(details.count(), detailsAdded);
201     QCOMPARE(details2.count(), detailsAdded);
202     // Name is unique
203     foreach(QString field, nameValues.keys()) {
204         QCOMPARE(details.first().value(field), nameValues.value(field));
205     }
206     QCOMPARE(details2.first().value(QLatin1String(QContactNickname::FieldNickname)), QString("Johnny"));
207
208     // Try changing the name of the saved contact.
209     {
210         QMap<QString,QString> nameValues;
211         QContactName name = c.detail<QContactName>();
212         nameValues.insert(QLatin1String(QContactName::FieldPrefix), "Mr2");
213         nameValues.insert(QLatin1String(QContactName::FieldFirstName), "John2");
214         nameValues.insert(QLatin1String(QContactName::FieldMiddleName), "Rupert2");
215         nameValues.insert(QLatin1String(QContactName::FieldLastName), "");
216         //    nameValues.insert(QContactName::FieldSuffix, "III");
217
218         foreach (QString field, nameValues.keys()) {
219             name.setValue(field, nameValues.value(field));
220         }
221         c.saveDetail(&name);
222
223         QContactNickname nick = c.detail<QContactNickname>();
224         nick.setValue(QLatin1String(QContactNickname::FieldNickname), "Johnny2");
225         c.saveDetail(&nick);
226
227
228         error = QContactManager::UnspecifiedError;
229         QVERIFY(engine()->saveContact(&c, &error));
230         QCOMPARE(error,  QContactManager::NoError);
231         QVERIFY(c.localId() != initialId);
232
233         const QtMobility::QContactFetchHint hints;
234         error = QContactManager::UnspecifiedError;
235         QContact contact = engine()->contactImpl(c.localId(), hints, &error);
236         QCOMPARE(error,  QContactManager::NoError);
237         QList<QContactName> details = contact.details<QContactName>();
238         QList<QContactNickname> details2 = contact.details<QContactNickname>();
239         QCOMPARE(details.count(), detailsAdded);
240         QCOMPARE(details2.count(), detailsAdded);
241
242         // Name is unique
243         foreach(QString field, nameValues.keys()) {
244             QCOMPARE(details.at(0).value(field), nameValues.value(field));
245         }
246
247         QCOMPARE(details2.at(0).value(QLatin1String(QContactNickname::FieldNickname)), QString("Johnny2"));
248      }
249 }
250
251 void ut_qtcontacts_trackerplugin::testSaveNameUnique()
252 {
253     // save contact with one name
254     QContactName name1;
255     name1.setFirstName("Till");
256     name1.setLastName("Eulenspiegel");
257
258     QContact savedContact;
259     QVERIFY(savedContact.saveDetail(&name1));
260
261     QContactManager::Error error(QContactManager::AlreadyExistsError);
262     QVERIFY(engine()->saveContact(&savedContact, &error));
263     QCOMPARE(error, QContactManager::NoError);
264     QVERIFY(0 != savedContact.localId());
265
266     // fetch the contact and compare content
267     QContactFetchHint fetchHint;
268     error = QContactManager::AlreadyExistsError;
269     QContact fetchedContact = engine()->contactImpl(savedContact.localId(), fetchHint, &error);
270     QCOMPARE(error, QContactManager::NoError);
271
272     QCOMPARE(fetchedContact.detail<QContactName>().firstName(), name1.firstName());
273     QCOMPARE(fetchedContact.detail<QContactName>().lastName(), name1.lastName());
274     QCOMPARE(fetchedContact.localId(), savedContact.localId());
275
276     // save contact with second name detail which is invalid
277     QContactName name2;
278     name2.setFirstName("Hans");
279     name2.setLastName("Wurst");
280     QVERIFY(savedContact.saveDetail(&name2));
281
282     // the engine shall drop the odd detail
283     QString warning("Dropping odd details for contact  %1 : \"Name\" detail must be unique ");
284     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning.arg(savedContact.localId())));
285
286     error = QContactManager::NoError;
287     QVERIFY(engine()->saveContact(&savedContact, &error));
288     QCOMPARE(error, QContactManager::NoError);
289
290     // again fetch the contact and compare content
291     error = QContactManager::AlreadyExistsError;
292     fetchedContact = engine()->contactImpl(savedContact.localId(), fetchHint, &error);
293     QCOMPARE(error, QContactManager::NoError);
294
295     QCOMPARE(fetchedContact.detail<QContactName>().firstName(), name1.firstName());
296     QCOMPARE(fetchedContact.detail<QContactName>().lastName(), name1.lastName());
297     QCOMPARE(fetchedContact.localId(), savedContact.localId());
298 }
299
300 // test NB#189108
301 void ut_qtcontacts_trackerplugin::testFetchAll()
302 {
303     // create some few contacts to have something in the db for sure
304     QList<QContact> contacts;
305
306     for(int i = 1; i <= 5; ++i) {
307         QContactNickname nickname;
308         nickname.setNickname(QString::fromLatin1("Fetchy %1").arg(i));
309
310         contacts.append(QContact());
311         QVERIFY(contacts.last().saveDetail(&nickname));
312     }
313
314     QContactManager::Error error = QContactManager::UnspecifiedError;
315     const bool contactsSaved = engine()->saveContacts(&contacts, 0, &error);
316     QCOMPARE(error, QContactManager::NoError);
317     QVERIFY(contactsSaved);
318
319     // directly asks tracker how many contacts are stored
320     RDFVariable contactVariable;
321
322     contactVariable.union_().child().isOfType<nco::PersonContact>();
323     contactVariable.union_().child().isOfType<nco::ContactList>().isOfType<nco::Contact>();
324
325     RDFSelect contactQuery = RDFSelect().addCountColumn(contactVariable);
326     LiveNodes nodes = ::BackEnds::Tracker::tracker()->modelQuery(contactQuery);
327     QVERIFY(nodes->refreshModel(LiveNodeModel::Block));
328     QCOMPARE(nodes->rowCount(), 1);
329
330     // fetch contacts via contact manager engine
331     contacts = engine()->contacts(QContactFilter(), QList<QContactSortOrder>(),
332                                   QContactFetchHint(), &error);
333
334     // compare sparql and engine result
335     QCOMPARE(contacts.count(), nodes->rawRow(0).first().toInt());
336 }
337
338
339 void ut_qtcontacts_trackerplugin::testSaveNothing()
340 {
341     QContactList nothing;
342     QContactManager::Error error = QContactManager::UnspecifiedError;
343     const bool contactsSaved = engine()->saveContacts(&nothing, 0, &error);
344     QCOMPARE(error, QContactManager::NoError);
345     QVERIFY(contactsSaved );
346 }
347
348 struct PhoneValue {
349     QString number;
350     QString context;
351     QString subtype;
352 };
353
354 static void add(QMap<QString, PhoneValue> &phoneValues,
355                 const QString detailUri, const QString &number,
356                 const QString &context, const QString &subtype = QString())
357 {
358     const PhoneValue value = { number, context, subtype };
359     phoneValues.insert(detailUri, value);
360 }
361
362 void ut_qtcontacts_trackerplugin::testSavePhoneNumber_data()
363 {
364     QTest::addColumn<int>("iteration");
365
366     QTest::newRow("1th run") << 0;
367     QTest::newRow("2nd run") << 1;
368     QTest::newRow("3rd run") << 2;
369 }
370
371 void ut_qtcontacts_trackerplugin::testSavePhoneNumber()
372 {
373     QFETCH(int, iteration);
374     Q_UNUSED(iteration);
375
376     // use the same values for 2 contacts
377     QContact c;
378     QContactLocalId initialId = c.localId();
379     int detailsAdded = 0;
380     QContactName name;
381     name.setFirstName("I have phone numbers");
382     name.setLastName("Girl");
383     c.saveDetail(&name);
384
385     QMap<QString, PhoneValue> phoneValues;
386
387     add(phoneValues, "tel:7044866472", "(704)486-6472", QContactDetail::ContextHome);
388     add(phoneValues, "tel:7659571663", "(765)957-1663", QContactDetail::ContextHome);
389     add(phoneValues, "tel:9998881111", "(999)888-1111", QContactDetail::ContextHome, QContactPhoneNumber::SubTypeMobile);
390
391     add(phoneValues, "tel:7921236113", "(792)123-6113", QContactDetail::ContextWork);
392     add(phoneValues, "tel:9184917361", "(918)491-7361", QContactDetail::ContextWork, QContactPhoneNumber::SubTypeMobile);
393     add(phoneValues, "tel:4126701514", "(412)670-1514", QContactDetail::ContextWork, QContactPhoneNumber::SubTypeCar);
394
395     foreach(const QString &detailUri, phoneValues.keys()) {
396         const PhoneValue &value(phoneValues[detailUri]);
397         QContactPhoneNumber phone;
398
399         phone.setNumber(value.number);
400
401         if (not value.context.isEmpty()) {
402             phone.setContexts(value.context);
403         }
404         if (not value.subtype.isEmpty()) {
405             phone.setSubTypes(value.subtype);
406         }
407
408         QVERIFY(c.saveDetail(&phone));
409         detailsAdded++;
410     }
411
412     QContactManager::Error error(QContactManager::UnspecifiedError);
413     QVERIFY(engine()->saveContact(&c, &error));
414     QCOMPARE(error,  QContactManager::NoError);
415     const QContactLocalId savedId(c.localId());
416     QVERIFY(savedId != initialId);
417     // wait for commit transaction to be done, no signals yet
418     for(int i = 0; i < 100; i++) {
419         usleep(10000);
420         QCoreApplication::processEvents();
421     }
422
423     // verify with synchronous read too
424     const QtMobility::QContactFetchHint hints; 
425     error = QContactManager::UnspecifiedError;
426     QContact contact = engine()->contactImpl(c.localId(), hints, &error);
427     QCOMPARE(error,  QContactManager::NoError);
428     QList<QContactPhoneNumber> details = contact.details<QContactPhoneNumber>();
429     QCOMPARE(details.count(), detailsAdded);
430
431     foreach(QContactPhoneNumber detail, details) {
432         QMap<QString, PhoneValue>::ConstIterator i = phoneValues.find(detail.detailUri());
433
434         // Verify that the stored values and attributes are the same as given
435         QVERIFY2(i != phoneValues.end(), qPrintable(detail.number()));
436
437         QCOMPARE(detail.number(), i->number);
438         QCOMPARE(detail.contexts().first(), i->context);
439
440         if (i->subtype.isEmpty()) { // default is voice
441             QVERIFY2(detail.subTypes().contains(QContactPhoneNumber::SubTypeVoice),
442                      qPrintable(detail.number()));
443         } else {
444             QVERIFY2(detail.subTypes().contains(i->subtype),
445                      qPrintable(detail.number()));
446         }
447
448     }
449
450     // save again with normalized phone numbers
451     error = QContactManager::UnspecifiedError;
452     QVERIFY(engine()->saveContact(&contact, &error));
453     QCOMPARE(error,  QContactManager::NoError);
454     QCOMPARE(contact.localId(), savedId);
455     // wait for commit transaction to be done, no signals yet
456     for(int i = 0; i < 100; i++) {
457         usleep(10000);
458         QCoreApplication::processEvents();
459     }
460
461     error = QContactManager::UnspecifiedError;
462     contact = engine()->contactImpl(c.localId(), hints, &error);
463     QCOMPARE(error,  QContactManager::NoError);
464     details = contact.details<QContactPhoneNumber>();
465     QCOMPARE(details.count(), detailsAdded);
466
467     foreach(QContactPhoneNumber detail, details) {
468         QMap<QString, PhoneValue>::ConstIterator i = phoneValues.find(detail.detailUri());
469
470         // Verify that the stored values and attributes are the same as given
471         QVERIFY2(i != phoneValues.end(), qPrintable(detail.detailUri()));
472
473         QCOMPARE(detail.number(), i->number);
474         QCOMPARE(detail.contexts().first(), i->context);
475
476         if (i->subtype.isEmpty()) { // default is voice
477             QVERIFY2(detail.subTypes().contains(QContactPhoneNumber::SubTypeVoice),
478                      qPrintable(detail.detailUri()));
479         } else {
480             QVERIFY2(detail.subTypes().contains(i->subtype),
481                      qPrintable(detail.detailUri()));
482         }
483     }
484
485     // edit one of numbers . values, context and subtypes and save again
486     QString editedPhoneValue = "+7044866473";
487     QContactPhoneNumber phone = details[0];
488     phone.setNumber(editedPhoneValue);
489     phone.setContexts(QContactDetail::ContextWork);
490     phone.setSubTypes(QContactPhoneNumber::SubTypeMobile);
491     c = contact;
492     QCOMPARE(c.localId(), savedId);
493     QVERIFY(c.saveDetail(&phone));
494     error = QContactManager::UnspecifiedError;
495     QVERIFY(engine()->saveContact(&c, &error));
496     QCOMPARE(c.localId(), savedId);
497     QCOMPARE(error,  QContactManager::NoError);
498     c = this->contact(c.localId(), QStringList()<<QContactPhoneNumber::DefinitionName);
499     QCOMPARE(c.localId(), savedId);
500     details = c.details<QContactPhoneNumber>();
501     QCOMPARE(details.count(), detailsAdded);
502     bool found = false;
503     foreach (QContactPhoneNumber detail, details) {
504         if(detail.number() == phone.number())
505         {
506             found = true;
507             QVERIFY(detail.subTypes().contains(QContactPhoneNumber::SubTypeMobile));
508             QVERIFY(detail.contexts().contains(QContactPhoneNumber::ContextWork));
509             break;
510         }
511     }
512     QVERIFY(found);
513 }
514
515 void ut_qtcontacts_trackerplugin::testPhoneNumberContext()
516 {
517     QContact c;
518     QContactPhoneNumber phone;
519     phone.setContexts(QContactDetail::ContextHome);
520     phone.setNumber("555-888");
521     phone.setSubTypes(QContactPhoneNumber::SubTypeMobile);
522     c.saveDetail(&phone);
523     QContact contactToSave = c;
524     // Let's do this all twice, first time save new detail, and next iteration change the context
525     for (int iterations = 0; iterations < 2; iterations++) {
526         QContactManager::Error error(QContactManager::UnspecifiedError);
527         QVERIFY(engine()->saveContact(&contactToSave, &error));
528         QCOMPARE(error, QContactManager::NoError);
529         // wait for commit transaction to be done, no signals yet
530         for(int i = 0; i < 100; i++) {
531             usleep(10000);
532             QCoreApplication::processEvents();
533         }
534
535         QContactFetchRequest request;
536         QContactLocalIdFilter filter;
537         QList<QContactLocalId> ids;
538         ids.append(contactToSave.localId());
539         filter.setIds(ids);
540         request.setFilter(filter);
541
542         QStringList details;
543         details << QContactPhoneNumber::DefinitionName;
544         QContactFetchHint fetchHint;
545         fetchHint.setDetailDefinitionsHint(details);
546         request.setFetchHint(fetchHint);
547
548         Slots slot;
549         QObject::connect(&request, SIGNAL(resultsAvailable()),
550                 &slot, SLOT(resultsAvailable()));
551
552         engine()->startRequest(&request);
553
554         engine()->waitForRequestFinished(&request, 1000);
555
556         // if it takes more, then something is wrong
557         QVERIFY(request.isFinished());
558         QVERIFY(!slot.contacts.isEmpty());
559
560         QContact contactToTest;
561         foreach (QContact savedContact, slot.contacts) {
562             if (savedContact.localId() == contactToSave.localId()) {
563                 contactToTest = savedContact;
564             }
565         }
566         QCOMPARE(contactToTest.localId(), contactToSave.localId()); // Just to be sure we got the saved contact
567         QCOMPARE(contactToTest.details<QContactPhoneNumber>().count(), 1);
568         if (0 == iterations) {
569             // perform context change
570             QContactPhoneNumber phoneToEdit = contactToTest.detail<QContactPhoneNumber>();
571             phoneToEdit.setContexts(QContactDetail::ContextWork);
572             contactToTest.saveDetail(&phoneToEdit);
573             contactToSave = contactToTest;
574         }
575         QVERIFY(contactToTest.details<QContactPhoneNumber>().count() == 1);
576     }
577 }
578
579 void ut_qtcontacts_trackerplugin::testWritingOnlyWorkMobile()
580 {
581     QContact c;
582     QContactPhoneNumber phone;
583     phone.setContexts(QContactDetail::ContextWork);
584     phone.setNumber("555999");
585     phone.setSubTypes(QContactPhoneNumber::SubTypeMobile);
586     c.saveDetail(&phone);
587     QContact& contactToSave = c;
588     QContactManager::Error error(QContactManager::UnspecifiedError);
589     QVERIFY(engine()->saveContact(&contactToSave, &error));
590     QCOMPARE(error, QContactManager::NoError);
591     // wait for commit transaction to be done, no signals yet
592     for(int i = 0; i < 100; i++) {
593         usleep(10000);
594         QCoreApplication::processEvents();
595     }
596
597     QContactFetchRequest request;
598     QContactLocalIdFilter filter;
599     QList<QContactLocalId> ids;
600     ids.append(contactToSave.localId());
601     filter.setIds(ids);
602     request.setFilter(filter);
603     QStringList details;
604     details << QContactPhoneNumber::DefinitionName;
605     QContactFetchHint fetchHint;
606     fetchHint.setDetailDefinitionsHint(details);
607     request.setFetchHint(fetchHint);
608
609     Slots slot;
610     QObject::connect(&request, SIGNAL(resultsAvailable()),
611             &slot, SLOT(resultsAvailable()));
612
613     engine()->startRequest(&request);
614
615     engine()->waitForRequestFinished(&request, 1000);
616
617     // if it takes more, then something is wrong
618     QVERIFY(request.isFinished());
619     QVERIFY(!slot.contacts.isEmpty());
620
621     QContact contactToTest;
622     foreach (QContact savedContact, slot.contacts) {
623         if (savedContact.localId() == c.localId()) {
624             contactToTest = savedContact;
625         }
626     }
627
628     // add implicied subtypes for new fetch request
629     phone.setSubTypes(phone.subTypes() <<
630                       QContactPhoneNumber::SubTypeMessagingCapable <<
631                       QContactPhoneNumber::SubTypeVoice);
632
633     QCOMPARE(contactToTest.localId(), c.localId()); // Just to be sure we got the saved contact
634     QCOMPARE(contactToTest.details<QContactPhoneNumber>().count(), 1);
635     QCOMPARE(contactToTest.detail<QContactPhoneNumber>().number(), phone.number());
636     QCOMPARE(contactToTest.detail<QContactPhoneNumber>().subTypes().toSet(), phone.subTypes().toSet());
637     QCOMPARE(contactToTest.detail<QContactPhoneNumber>().contexts(), phone.contexts());
638 }
639
640 void ut_qtcontacts_trackerplugin::testSaveAddress()
641 {
642     QContact c;
643     QContactName name;
644     name.setFirstName("Aruba & Barbados");
645     name.setLastName("Girl");
646     c.saveDetail(&name);
647     QContactLocalId initialId = c.localId();
648     int detailsAdded = 0;
649
650     // List of pairs of field-value map and context
651     typedef QMap<QString,QString> typeAddress;
652     typedef QPair<typeAddress,QString> typeAddressWithContext;
653     QList<typeAddressWithContext> addressValues;
654
655     // TODO check status of 137174 and other libqttracker1pre6 bugs before refactoring
656     typeAddress values;
657     values.insert(QLatin1String(QContactAddress::FieldCountry), "Barbados");
658     values.insert(QLatin1String(QContactAddress::FieldPostcode), "55555");
659     values.insert(QLatin1String(QContactAddress::FieldStreet), "Martindales Rd");
660     values.insert(QLatin1String(QContactAddress::FieldRegion), "Bridgetown");
661     values.insert(QLatin1String(QContactAddress::FieldLocality), "Bridgetown town");
662
663
664
665     addressValues.append(typeAddressWithContext(values, QLatin1String(QContactDetail::ContextWork)));
666     values.clear();
667     values.insert(QLatin1String(QContactAddress::FieldCountry), "Aruba");
668     values.insert(QLatin1String(QContactAddress::FieldPostcode), "44444");
669     values.insert(QLatin1String(QContactAddress::FieldStreet), "Brazilie Straat");
670     values.insert(QLatin1String(QContactAddress::FieldRegion), "Oranjestad");
671     values.insert(QLatin1String(QContactAddress::FieldLocality), "Bridgetown town");
672     values.insert(QLatin1String(QContactAddress::FieldPostOfficeBox), "00011102");
673
674     addressValues.append(typeAddressWithContext(values, QLatin1String(QContactDetail::ContextHome)));
675     values.clear();
676     values.insert(QLatin1String(QContactAddress::FieldCountry), "ArubaWork");
677     values.insert(QLatin1String(QContactAddress::FieldPostcode), "44445");
678     values.insert(QLatin1String(QContactAddress::FieldStreet), "Sunset Blvd");
679     values.insert(QLatin1String(QContactAddress::FieldRegion), "Oranjestad");
680     values.insert(QLatin1String(QContactAddress::FieldLocality), "Bridgetown town");
681     values.insert(QLatin1String(QContactAddress::FieldPostOfficeBox), "00011103");
682
683     addressValues.append(typeAddressWithContext(values, QLatin1String(QContactDetail::ContextHome)));
684     foreach (typeAddressWithContext addressWithContext, addressValues) {
685         QContactAddress address;
686         foreach (QString field, addressWithContext.first.keys()) {
687             address.setValue(field, addressWithContext.first.value(field));
688         }
689         address.setContexts(addressWithContext.second);
690         c.saveDetail(&address);
691         detailsAdded++;
692     }
693
694     QContactManager::Error error(QContactManager::UnspecifiedError);
695     engine()->saveContact(&c, &error);
696     QCOMPARE(error,  QContactManager::NoError);
697     QVERIFY(c.localId() != initialId);
698     const QtMobility::QContactFetchHint hints;
699     error = QContactManager::UnspecifiedError;
700     QContact contact = engine()->contactImpl(c.localId(), hints, &error);
701     QCOMPARE(error,  QContactManager::NoError);
702     QList<QContactAddress> details = contact.details<QContactAddress>();
703     QCOMPARE(details.count(), detailsAdded);
704     bool found = false;
705     // Test if inserted values are found in some of the details
706     foreach (typeAddressWithContext addressWithContext, addressValues) {
707         foreach (QContactAddress detail, details) {
708             foreach (QString field, addressWithContext.first.keys()) {
709                 found = (detail.value(field) == addressWithContext.first.value(field));
710                 if (!found)
711                     break;
712             }
713             if (found)
714                 break;
715         }
716         QVERIFY2(found, "Inserted detail was not found in the fetched details");
717     }
718 }
719
720 void ut_qtcontacts_trackerplugin::testSaveOrganization()
721 {
722     QList<PairOfStrings> samples;
723
724     samples << PairOfStrings(QContactOrganization::FieldName, "Nokia");
725     samples << PairOfStrings(QContactOrganization::FieldLogoUrl, "nokia.jpg");
726     samples << PairOfStrings(QContactOrganization::FieldDepartment, "Meego R&D");
727     samples << PairOfStrings(QContactOrganization::FieldLocation, "Helsinki");
728     samples << PairOfStrings(QContactOrganization::FieldRole, "Developer");
729     samples << PairOfStrings(QContactOrganization::FieldTitle, "Code Guru");
730
731     QContact contact;
732
733     for(int i = 0; i < samples.count(); ++i) {
734         QContactOrganization org = contact.detail<QContactOrganization>();
735         org.setValue(samples[i].first, samples[i].second);
736         contact.saveDetail(&org);
737
738         QContactManager::Error error = QContactManager::UnspecifiedError;
739         bool success = engine()->saveContact(&contact, &error);
740         QCOMPARE(error,  QContactManager::NoError);
741         QVERIFY(0 != contact.localId());
742         QVERIFY(success);
743
744         error = QContactManager::UnspecifiedError;
745         const QContactLocalId contactLocalId = contact.localId();
746         contact = engine()->contactImpl(contact.localId(), QContactFetchHint(), &error);
747         QCOMPARE(contact.localId(), contactLocalId);
748         QCOMPARE(error,  QContactManager::NoError);
749
750         org = contact.detail<QContactOrganization>();
751
752         for(int j = 0; j < i; ++j) {
753             QCOMPARE(org.value(samples[j].first), samples[j].second);
754         }
755     }
756 }
757
758 void ut_qtcontacts_trackerplugin::testSaveEmailAddress()
759 {
760     QContact c;
761     QContactLocalId initialId = c.localId();
762     int detailsAdded = 0;
763
764     QMap<QString,QString> values;
765     values.insert("john.does@hotmail.com", QContactDetail::ContextHome);
766     values.insert("john.doe@gmail.com", QContactDetail::ContextWork);
767     values.insert("john.doe@nokia.com", QContactDetail::ContextWork);
768     values.insert("john.doe@johndoe.com", QContactDetail::ContextHome);
769     foreach(QString address, values.keys()) {
770         QContactEmailAddress emailAddress;
771         emailAddress.setEmailAddress(address);
772         emailAddress.setContexts(values.value(address));
773         c.saveDetail(&emailAddress);
774         detailsAdded++;
775     }
776     QContactName name;
777     name.setFirstName("Jo");
778     name.setLastName("H N Doe");
779     c.saveDetail(&name);
780     QContactManager::Error error(QContactManager::UnspecifiedError);
781     engine()->saveContact(&c, &error);
782     QCOMPARE(error,  QContactManager::NoError);
783     QVERIFY(c.localId() != initialId);
784     const QtMobility::QContactFetchHint hints;
785     error = QContactManager::UnspecifiedError;
786     QContact contact = engine()->contactImpl(c.localId(), hints, &error);
787     QCOMPARE(error,  QContactManager::NoError);
788     QList<QContactEmailAddress> details = contact.details<QContactEmailAddress>();
789     QCOMPARE(details.count(), detailsAdded);
790     foreach (QContactEmailAddress detail, details) {
791         QString address = detail.value(QContactEmailAddress::FieldEmailAddress);
792         QVERIFY(values.contains(address));
793         QCOMPARE(detail.contexts()[0], values.value(address));
794     }
795 }
796
797 void ut_qtcontacts_trackerplugin::testRemoveContact()
798 {
799     QContact c;
800     QContactPhoneNumber phone;
801     phone.setNumber("+358501234567");
802     c.saveDetail(&phone);
803     QContactEmailAddress email;
804     email.setEmailAddress("super.man@hotmail.com");
805     c.saveDetail(&email);
806     QContactName name;
807     name.setFirstName("Super");
808     name.setLastName("Man");
809     c.saveDetail(&name);
810
811     const QtMobility::QContactFetchHint hints;
812
813     QContactManager::Error error(QContactManager::UnspecifiedError);
814     QVERIFY(engine()->saveContact(&c, &error));
815     QCOMPARE(error,  QContactManager::NoError);
816
817     error = QContactManager::UnspecifiedError;
818     QVERIFY2(engine()->removeContact(c.localId(), &error), "Removing a contact failed");
819     QCOMPARE(error, QContactManager::NoError);
820
821     QVERIFY2(engine()->contactImpl(c.localId(), hints, &error) == QContact(),
822              "Found a contact, which should have been removed");
823 }
824
825 void ut_qtcontacts_trackerplugin::testSaveContacts()
826 {
827     QList<QContact> contacts;
828     for (int i = 0; i < 3; i++) {
829         QContact c;
830         QContactName name;
831         name.setFirstName("John");
832         name.setLastName(QString::number(i,10));
833         c.saveDetail(&name);
834
835         // skip first contact to test GUID detail auto-creation
836         if (i > 0) {
837             QContactGuid uid;
838             uid.setGuid(QUuid::createUuid().toString());
839             c.saveDetail(&uid);
840         }
841
842         QContactGender gender;
843         if ((i%2))
844             gender.setGender(QContactGender::GenderMale);
845         else
846             gender.setGender(QContactGender::GenderFemale);
847         c.saveDetail(&gender);
848         contacts.append(c);
849     }
850
851     QDateTime now(QDateTime::currentDateTime().addSecs(-1));
852
853     QMap<int, QContactManager::Error> errorMap;
854     QContactManager::Error error(QContactManager::UnspecifiedError);
855     engine()->saveContacts(&contacts, &errorMap, &error);
856     QCOMPARE(error, QContactManager::NoError);
857
858     for (int i = 0; i < contacts.count(); i++) {
859         QVERIFY(contacts[i].localId() != 0);
860         error = QContactManager::UnspecifiedError;
861         QContact contact = engine()->contactImpl(contacts[i].localId(), QContactFetchHint(), &error);
862         QCOMPARE(error,  QContactManager::NoError);
863         QCOMPARE(contact.localId(), contacts[i].localId());
864         QList<QContactName> details = contact.details<QContactName>();
865         QCOMPARE(details.count(), 1);
866         QCOMPARE(details.first().lastName(),
867                  QString("%1").arg(QString::number(i,10)));
868         QList<QContactGender> genders = contact.details<QContactGender>();
869         QCOMPARE(genders.count(), 1);
870         QCOMPARE(genders.first().gender(),contacts[i].detail<QContactGender>().gender());
871         QList<QContactGuid> guids = contact.details<QContactGuid>();
872         QCOMPARE(guids.count(), 1);
873         QVERIFY(not guids.first().guid().isEmpty());
874
875         QList<QContactTimestamp> timestamps = contact.details<QContactTimestamp>();
876
877         QCOMPARE(timestamps.count(), 1);
878         QVERIFY(not timestamps.first().lastModified().isNull());
879         QVERIFY(timestamps.first().lastModified() >= now);
880         QVERIFY(not timestamps.first().created().isNull());
881         QVERIFY(timestamps.first().created() >= now);
882     }
883
884     // save contacts again to check if timestamps get updated
885     sleep(1);
886
887     QDateTime later(QDateTime::currentDateTime().addSecs(-1));
888
889     error = QContactManager::UnspecifiedError;
890     engine()->saveContacts(&contacts, &errorMap, &error);
891     QCOMPARE(error, QContactManager::NoError);
892
893     for (int i = 0; i < contacts.count(); i++) {
894         QVERIFY(contacts[i].localId() != 0);
895         error = QContactManager::UnspecifiedError;
896         QContact contact = engine()->contactImpl(contacts[i].localId(), QContactFetchHint(), &error);
897         QCOMPARE(error,  QContactManager::NoError);
898         QCOMPARE(contact.localId(), contacts[i].localId());
899
900         QList<QContactTimestamp> timestamps = contact.details<QContactTimestamp>();
901
902         QCOMPARE(timestamps.count(), 1);
903         QVERIFY(not timestamps.first().lastModified().isNull());
904         QVERIFY(timestamps.first().lastModified() >= later);
905         QVERIFY(not timestamps.first().created().isNull());
906         QVERIFY(timestamps.first().created() >= now);
907         QVERIFY(timestamps.first().created() < later);
908     }
909 }
910
911 void ut_qtcontacts_trackerplugin::testRemoveContacts()
912 {
913     QList<QContactLocalId> addedIds;
914     for (int i = 0; i < 5; i++) {
915         QContact c;
916         QContactName name;
917         name.setFirstName(QString("John%1").arg(QString::number(i,10)));
918         c.saveDetail(&name);
919
920         QContactManager::Error error(QContactManager::UnspecifiedError);
921         QVERIFY(engine()->saveContact(&c, &error));
922         QCOMPARE(error,  QContactManager::NoError);
923
924         addedIds.append(c.localId());
925     }
926     QList<QContactLocalId> toApiRemove;
927     toApiRemove.append(addedIds.takeLast());
928     toApiRemove.append(addedIds.takeLast());
929     QList<QContactLocalId> toPluginRemove(addedIds);
930
931     // Remove all, but last of the added contacts
932     QMap<int, QContactManager::Error> errorMap;
933     QContactManager::Error error(QContactManager::UnspecifiedError);
934     QVERIFY(engine()->removeContacts(toPluginRemove, &errorMap, &error));
935     QCOMPARE(error,  QContactManager::NoError);
936     for (int i = 0; i < errorMap.count(); i++) {
937         QCOMPARE(toPluginRemove[i], 0U);
938     }
939
940     error = QContactManager::UnspecifiedError;
941     QVERIFY(engine()->removeContacts(toApiRemove, &errorMap, &error));
942     QCOMPARE(error, QContactManager::NoError);
943     for (int i = 0; i < errorMap.count(); i++) {
944         QCOMPARE(toApiRemove[i], 0U);
945     }
946 }
947
948 void ut_qtcontacts_trackerplugin::testAvatar()
949 {
950     QContact contactWithAvatar;
951     QContactAvatar avatar;
952
953     avatar.setImageUrl(QUrl("file:///home/user/.contacts/avatars/default_avatar.png"));
954     contactWithAvatar.saveDetail(&avatar);
955     QContactName name;
956     name.setFirstName("John");name.setLastName("A Frog");
957     contactWithAvatar.saveDetail(&name);
958     QContactManager::Error error(QContactManager::UnspecifiedError);
959     QVERIFY(engine()->saveContact( &contactWithAvatar, &error));
960     QCOMPARE(error,  QContactManager::NoError);
961
962     const QtMobility::QContactFetchHint hints;
963     error = QContactManager::UnspecifiedError;
964     QContact c = engine()->contactImpl( contactWithAvatar.localId(), hints, &error);
965     QCOMPARE(error,  QContactManager::NoError);
966     QList<QContactAvatar> avatars = c.details<QContactAvatar>();
967     QVERIFY( avatars.size() );
968     QCOMPARE( avatars[0].imageUrl(), avatar.imageUrl() );
969 }
970
971 void ut_qtcontacts_trackerplugin::testOrganization()
972 {
973     // Company information
974     QContact contactWithCompany1;
975     QContactOrganization company1;
976     company1.setName("Nokia");
977     company1.setDepartment(QStringList() << "Mobile");
978     company1.setRole("Developer");
979     QContactName name;
980     name.setFirstName("John");
981     name.setLastName("TestCompany1");
982     contactWithCompany1.saveDetail(&name);
983     contactWithCompany1.saveDetail(&company1);
984     QContactManager::Error error(QContactManager::UnspecifiedError);
985     QVERIFY(engine()->saveContact(&contactWithCompany1, &error));
986     QCOMPARE(error,  QContactManager::NoError);
987
988     QContactLocalId id1 = contactWithCompany1.localId();
989     QCOMPARE(contact(id1).detail<QContactOrganization>().name(), QString("Nokia"));
990     QCOMPARE(contact(id1).detail<QContactOrganization>().department(), QStringList() << "Mobile");
991     QCOMPARE(contact(id1).detail<QContactOrganization>().role(), QString("Developer"));
992 }
993
994 void ut_qtcontacts_trackerplugin::testUrl()
995 {
996     //Context home, homepage url
997     QContact contactWithUrl1;
998     QContactUrl url1;
999     url1.setUrl("http://home.homepage");
1000     url1.setContexts(QContactDetail::ContextHome);
1001     url1.setSubType(QContactUrl::SubTypeHomePage);
1002     QContactName name;
1003     name.setFirstName("John");name.setLastName("TestUrl1");
1004     contactWithUrl1.saveDetail(&name);
1005     contactWithUrl1.saveDetail(&url1);
1006     QContactManager::Error error(QContactManager::UnspecifiedError);
1007     QVERIFY(engine()->saveContact(&contactWithUrl1, &error));
1008     QCOMPARE(error,  QContactManager::NoError);
1009
1010     //Context work, homepage url
1011     QContact contactWithUrl2;
1012     QContactUrl url2;
1013     url2.setUrl("http://work.homepage");
1014     url2.setContexts(QContactDetail::ContextWork);
1015     url2.setSubType(QContactUrl::SubTypeHomePage);
1016     QContactName name2;
1017     name2.setLastName("TestUrl2");
1018     contactWithUrl2.saveDetail(&name2);
1019     contactWithUrl2.saveDetail(&url2);
1020     error = QContactManager::UnspecifiedError;
1021     QVERIFY(engine()->saveContact(&contactWithUrl2, &error));
1022     QCOMPARE(error,  QContactManager::NoError);
1023
1024     //Context home, favourite url
1025     QContact contactWithUrl3;
1026     QContactUrl url3;
1027     url3.setUrl("http://home.favourite");
1028     url3.setContexts(QContactDetail::ContextHome);
1029     url3.setSubType(QContactUrl::SubTypeFavourite);
1030
1031     name2.setLastName("TestUrl3");
1032     contactWithUrl3.saveDetail(&name2);
1033     contactWithUrl3.saveDetail(&url3);
1034     error = QContactManager::UnspecifiedError;
1035     QVERIFY(engine()->saveContact(&contactWithUrl3, &error));
1036     QCOMPARE(error,  QContactManager::NoError);
1037
1038
1039     QContactLocalId id1 = contactWithUrl1.localId();
1040     QContactLocalId id2 = contactWithUrl2.localId();
1041     QContactLocalId id3 = contactWithUrl3.localId();
1042     QCOMPARE(contact(id1).detail<QContactUrl>().url(), QString("http://home.homepage"));
1043     QCOMPARE(contact(id2).detail<QContactUrl>().url(), QString("http://work.homepage"));
1044     QCOMPARE(contact(id3).detail<QContactUrl>().url(), QString("http://home.favourite"));
1045
1046     QVERIFY(contact(id1).detail<QContactUrl>().contexts()[0] == QContactDetail::ContextHome );
1047     QVERIFY(contact(id2).detail<QContactUrl>().contexts()[0] == QContactDetail::ContextWork );
1048     QVERIFY(contact(id3).detail<QContactUrl>().contexts()[0] == QContactDetail::ContextHome );
1049
1050     QVERIFY(contact(id1).detail<QContactUrl>().subType() == QContactUrl::SubTypeHomePage );
1051     QVERIFY(contact(id2).detail<QContactUrl>().subType() == QContactUrl::SubTypeHomePage );
1052     QVERIFY(contact(id3).detail<QContactUrl>().subType() == QContactUrl::SubTypeFavourite );
1053
1054     // edit type
1055     QContact c1 = contact(id1);
1056     QCOMPARE(c1.details<QContactUrl>().size(), 1);
1057     QContactUrl detail = c1.detail<QContactUrl>();
1058     detail.setContexts(QContactDetail::ContextWork);
1059
1060     c1.saveDetail(&detail);
1061     QVERIFY(c1.detail<QContactUrl>().contexts().size() == 1);
1062     error = QContactManager::UnspecifiedError;
1063     QVERIFY(engine()->saveContact(&c1, &error));
1064     QCOMPARE(error,  QContactManager::NoError);
1065     c1 = contact(id1);
1066     QVERIFY(c1.details<QContactUrl>().size() == 1);
1067
1068
1069     // add additional URL (NB#178354)
1070     detail = QContactUrl();
1071     detail.setUrl("http://meego.com/");
1072     QVERIFY(c1.saveDetail(&detail));
1073
1074     error = QContactManager::UnspecifiedError;
1075     QVERIFY(engine()->saveContact(&c1, &error));
1076     QCOMPARE(error,  QContactManager::NoError);
1077
1078     QSet<QString> expectedUrls = QSet<QString>() << url1.url() << detail.url();
1079     QSet<QString> fetchedUrls;
1080
1081     foreach(const QContactUrl &u, contact(id1).details<QContactUrl>()) {
1082         fetchedUrls.insert(u.url());
1083     }
1084
1085     QCOMPARE(fetchedUrls, expectedUrls);
1086 }
1087
1088 void ut_qtcontacts_trackerplugin::testUniqueDetails_data()
1089 {
1090     QTest::addColumn<QString>("definitionName");
1091     QTest::addColumn<QString>("fieldName");
1092     QTest::addColumn<QVariant>("firstValue");
1093     QTest::addColumn<QVariant>("secondValue");
1094
1095     QTest::newRow("organization")
1096             << QString(QContactOrganization::DefinitionName.latin1())
1097             << QString(QContactOrganization::FieldTitle.latin1())
1098             << QVariant("First Organization")
1099             << QVariant("Second Organization");
1100
1101     QTest::newRow("note")
1102             << QString(QContactNote::DefinitionName.latin1())
1103             << QString(QContactNote::FieldNote.latin1())
1104             << QVariant("First Note")
1105             << QVariant("Second Note");
1106 }
1107
1108 void ut_qtcontacts_trackerplugin::testUniqueDetails()
1109 {
1110     QFETCH(QString, definitionName);
1111     QFETCH(QString, fieldName);
1112     QFETCH(QVariant, firstValue);
1113     QFETCH(QVariant, secondValue);
1114
1115     QContact savedContact;
1116
1117     QContactDetail first(definitionName);
1118     first.setValue(fieldName, firstValue);
1119     QVERIFY(savedContact.saveDetail(&first));
1120
1121     QContactDetail second(definitionName);
1122     second.setValue(fieldName, secondValue);
1123     QVERIFY(savedContact.saveDetail(&second));
1124
1125     const QString warning = "Dropping odd details for contact  0 : \"%1\" detail must be unique ";
1126     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning.arg(definitionName)));
1127
1128     QContactManager::Error error(QContactManager::UnspecifiedError);
1129     bool success(engine()->saveContact(&savedContact, &error));
1130     QCOMPARE(error, QContactManager::NoError);
1131     QVERIFY(0 != savedContact.localId());
1132     QCOMPARE(success, true);
1133
1134     error = QContactManager::UnspecifiedError;
1135     QContact fetchedContact(engine()->contactImpl(savedContact.localId(),
1136                                                   QContactFetchHint(), &error));
1137     QCOMPARE(error, QContactManager::NoError);
1138     QCOMPARE(fetchedContact.localId(), savedContact.localId());
1139
1140     QCOMPARE(fetchedContact.details(definitionName).count(), 1);
1141     QCOMPARE(fetchedContact.detail(definitionName).variantValue(fieldName), firstValue);
1142 }
1143
1144 template<class K, class V> static QHash<K, V>
1145 toHash(const QMap<K,V> &map)
1146 {
1147     QHash<K,V> hash;
1148
1149     for(typename QMap<K,V>::ConstIterator i = map.begin();
1150     i != map.end(); ++i) {
1151         hash.insert(i.key(), i.value());
1152     }
1153
1154     return hash;
1155 }
1156
1157 void ut_qtcontacts_trackerplugin::testCustomDetails()
1158 {
1159     QContact savedContact;
1160
1161     QContactDetail simple("FavoriteColor");
1162     simple.setValue(simple.definitionName(), "Blue");
1163     QVERIFY(savedContact.saveDetail(&simple));
1164
1165     QContactDetail complex("AllTimeFavorites");
1166     complex.setValue("Song", "Underworld - Born Slippy");
1167     complex.setValue("Phone", "Nokia N900");
1168     complex.setValue("Place", "Home");
1169     QVERIFY(savedContact.saveDetail(&complex));
1170
1171     QContactDetail multi("CreditCardNumber");
1172     multi.setValue(multi.definitionName(), "1122334455");
1173     QVERIFY(savedContact.saveDetail(&multi));
1174
1175     QContactDetail multi2(multi.definitionName());
1176     multi2.setValue(multi2.definitionName(), "5544332211");
1177     QVERIFY(savedContact.saveDetail(&multi2));
1178
1179     QContactManager::Error error(QContactManager::UnspecifiedError);
1180     bool success(engine()->saveContact(&savedContact, &error));
1181     QCOMPARE(error, QContactManager::NoError);
1182     QVERIFY(0 != savedContact.localId());
1183     QCOMPARE(success, true);
1184
1185     QContactFetchHint fetchHint;
1186     fetchHint.setDetailDefinitionsHint(QStringList() <<
1187                                        simple.definitionName() <<
1188                                        complex.definitionName() <<
1189                                        multi.definitionName());
1190
1191     error = QContactManager::UnspecifiedError;
1192     QContact fetchedContact(engine()->contactImpl(savedContact.localId(), fetchHint, &error));
1193     QCOMPARE(error, QContactManager::NoError);
1194     QCOMPARE(fetchedContact.localId(), savedContact.localId());
1195
1196     QCOMPARE(fetchedContact.details(simple.definitionName()).count(), 1);
1197     QCOMPARE(fetchedContact.detail(simple.definitionName()).variantValues(),
1198              simple.variantValues());
1199
1200     QCOMPARE(fetchedContact.details(complex.definitionName()).count(), 1);
1201     QCOMPARE(toHash(fetchedContact.detail(complex.definitionName()).variantValues()),
1202              toHash(complex.variantValues()));
1203
1204     QCOMPARE(fetchedContact.details(multi.definitionName()).count(), 2);
1205
1206     bool multiFound = false;
1207     bool multi2Found = false;
1208
1209     foreach(const QContactDetail &detail, fetchedContact.details(multi.definitionName())) {
1210         if (detail == multi) {
1211             multiFound = true;
1212             continue;
1213         }
1214
1215         if (detail == multi2) {
1216             multi2Found = true;
1217             continue;
1218         }
1219
1220         // yes this leaks, but this is ok when a test fails
1221         QVERIFY2(false, QTest::toString(detail.variantValues()));
1222     }
1223
1224     QVERIFY(multiFound);
1225     QVERIFY(multi2Found);
1226 }
1227
1228 typedef QPair<QStringList, QStringList> SubTypeSample;
1229 typedef QList<SubTypeSample> SubTypeSampleList;
1230
1231 Q_DECLARE_METATYPE(SubTypeSampleList);
1232
1233 void ut_qtcontacts_trackerplugin::testRemoveSubType_data()
1234 {
1235     QTest::addColumn<QString>("detailName");
1236     QTest::addColumn<QString>("valueField");
1237     QTest::addColumn<QVariant>("value");
1238     QTest::addColumn<QString>("subTypesField");
1239     QTest::addColumn<SubTypeSampleList>("samples");
1240
1241     QTest::newRow("phone number")
1242             << (QString::fromLatin1(QContactPhoneNumber::DefinitionName.latin1()))
1243             << (QString::fromLatin1(QContactPhoneNumber::FieldNumber.latin1()))
1244             << (QVariant(QString::fromLatin1("33445566")))
1245             << (QString::fromLatin1(QContactPhoneNumber::FieldSubTypes.latin1()))
1246             << (SubTypeSampleList() <<
1247                 qMakePair(QStringList() <<
1248                           QContactPhoneNumber::SubTypeFax <<
1249                           QContactPhoneNumber::SubTypeMobile,
1250                           QStringList() <<
1251                           QContactPhoneNumber::SubTypeFax <<
1252                           QContactPhoneNumber::SubTypeMessagingCapable <<
1253                           QContactPhoneNumber::SubTypeMobile <<
1254                           QContactPhoneNumber::SubTypeVoice) <<
1255                 qMakePair(QStringList() <<
1256                           QContactPhoneNumber::SubTypeMobile,
1257                           QStringList() <<
1258                           QContactPhoneNumber::SubTypeMessagingCapable <<
1259                           QContactPhoneNumber::SubTypeMobile <<
1260                           QContactPhoneNumber::SubTypeVoice) <<
1261                 qMakePair(QStringList() <<
1262                           QContactPhoneNumber::SubTypeLandline,
1263                           QStringList() <<
1264                           QContactPhoneNumber::SubTypeVoice));
1265
1266     QTest::newRow("street address")
1267             << (QString::fromLatin1(QContactAddress::DefinitionName.latin1()))
1268             << (QString::fromLatin1(QContactAddress::FieldCountry.latin1()))
1269             << (QVariant(QString::fromLatin1("Finnland")))
1270             << (QString::fromLatin1(QContactAddress::FieldSubTypes.latin1()))
1271             << (SubTypeSampleList() <<
1272                 qMakePair(QStringList() <<
1273                           QContactAddress::SubTypeInternational <<
1274                           QContactAddress::SubTypeParcel,
1275                           QStringList() <<
1276                           QContactAddress::SubTypeInternational <<
1277                           QContactAddress::SubTypeParcel <<
1278                           QContactAddress::SubTypePostal) <<
1279                 qMakePair(QStringList() <<
1280                           QContactAddress::SubTypeInternational,
1281                           QStringList() <<
1282                           QContactAddress::SubTypeInternational <<
1283                           QContactAddress::SubTypePostal));
1284
1285 }
1286
1287 void ut_qtcontacts_trackerplugin::testRemoveSubType()
1288 {
1289     QFETCH(QString, detailName);
1290     QFETCH(QString, valueField);
1291     QFETCH(QVariant, value);
1292     QFETCH(QString, subTypesField);
1293     QFETCH(SubTypeSampleList, samples);
1294
1295     foreach(const SubTypeSample &sample, samples) {
1296         QContactDetail detail(detailName);
1297         detail.setValue(valueField, value);
1298         detail.setValue(subTypesField, sample.first);
1299
1300         QContact savedContact;
1301         QVERIFY(savedContact.saveDetail(&detail));
1302
1303         QContactManager::Error error(QContactManager::NoError);
1304         QVERIFY(engine()->saveContact(&savedContact, &error));
1305         QCOMPARE(error, QContactManager::NoError);
1306         QVERIFY(0 != savedContact.localId());
1307
1308         QContact fetchedContact(engine()->contactImpl(savedContact.localId(),
1309                                                            QContactFetchHint(), &error));
1310
1311         QCOMPARE(error, QContactManager::NoError);
1312         QCOMPARE(fetchedContact.localId(), savedContact.localId());
1313
1314         detail = fetchedContact.detail(detailName);
1315         QCOMPARE(detail.value<QStringList>(subTypesField).toSet(), sample.second.toSet());
1316         QCOMPARE(detail.variantValue(valueField), value);
1317     }
1318 }
1319
1320 void ut_qtcontacts_trackerplugin::testTags()
1321 {
1322     static const QLatin1String favorite("favourite");
1323
1324     QContactName name;
1325     name.setFirstName("Tuck");
1326     name.setLastName("Sherwood");
1327     name.resetKey(); // XXX workaround for qtcontacts bug
1328
1329     QContactTag tag;
1330     tag.setTag(favorite);
1331     tag.resetKey(); // XXX workaround for qtcontacts bug
1332
1333     // save contact with favorite tag
1334     QContact savedContact;
1335     QVERIFY(savedContact.saveDetail(&name));
1336     QVERIFY(savedContact.saveDetail(&tag));
1337
1338     QList<QContactTag> favoriteTags;
1339     favoriteTags = savedContact.details<QContactTag>(QContactTag::FieldTag, favorite);
1340     QCOMPARE(favoriteTags.count(), 1);
1341
1342     QContactManager::Error error(QContactManager::UnspecifiedError);
1343     QVERIFY(engine()->saveContact(&savedContact, &error));
1344     QCOMPARE(error, QContactManager::NoError);
1345     QVERIFY(0 != savedContact.localId());
1346
1347     // fetch contact with favorite tag
1348     QContact fetchedContact(engine()->contactImpl(savedContact.localId(),
1349                                                   QContactFetchHint(), &error));
1350     QCOMPARE(fetchedContact.localId(), savedContact.localId());
1351     QCOMPARE(error, QContactManager::NoError);
1352
1353     favoriteTags = fetchedContact.details<QContactTag>(QContactTag::FieldTag, favorite);
1354     QCOMPARE(favoriteTags.count(), 1);
1355
1356     // save same contact without favorite tag
1357     QVERIFY(savedContact.removeDetail(&tag));
1358     favoriteTags = savedContact.details<QContactTag>(QContactTag::FieldTag, favorite);
1359     QCOMPARE(favoriteTags.count(), 0);
1360
1361     QVERIFY(engine()->saveContact(&savedContact, &error));
1362     QCOMPARE(error, QContactManager::NoError);
1363     QVERIFY(0 != savedContact.localId());
1364
1365     // fetch contact without favorite tag
1366     fetchedContact = engine()->contactImpl(savedContact.localId(),
1367                                            QContactFetchHint(), &error);
1368     QCOMPARE(fetchedContact.localId(), savedContact.localId());
1369     QCOMPARE(error, QContactManager::NoError);
1370
1371     favoriteTags = fetchedContact.details<QContactTag>(QContactTag::FieldTag, favorite);
1372     QCOMPARE(favoriteTags.count(), 0);
1373 }
1374
1375 /*
1376 void ut_qtcontacts_trackerplugin::testGroups()
1377 {
1378     qDebug() << "Not implemented";
1379     QVERIFY(false);
1380 }
1381
1382 void ut_qtcontacts_trackerplugin::testGroup()
1383 {
1384     qDebug() << "Not implemented";
1385     QVERIFY(false);
1386 }
1387
1388 void ut_qtcontacts_trackerplugin::testSaveGroup()
1389 {
1390     qDebug() << "Not implemented";
1391     QVERIFY(false);
1392 }
1393
1394 void ut_qtcontacts_trackerplugin::testRemoveGroup()
1395 {
1396     qDebug() << "Not implemented";
1397     QVERIFY(false);
1398 }
1399
1400 void ut_qtcontacts_trackerplugin::testDetailDefinitions()
1401 {
1402     qDebug() << "Not implemented";
1403     QVERIFY(false);
1404 }
1405
1406 void ut_qtcontacts_trackerplugin::testDetailDefinition()
1407 {
1408     qDebug() << "Not implemented";
1409     QVERIFY(false);
1410 }
1411
1412 void ut_qtcontacts_trackerplugin::testSaveDetailDefinition()
1413 {
1414     qDebug() << "Not implemented";
1415     QVERIFY(false);
1416 }
1417
1418 void ut_qtcontacts_trackerplugin::testRemoveDetailDefinition()
1419 {
1420     qDebug() << "Not implemented";
1421     QVERIFY(false);
1422 }
1423 */
1424
1425 void ut_qtcontacts_trackerplugin::testSyncContactManagerContactsAddedSince()
1426 {
1427     QDateTime start;
1428     QList<QContactLocalId> addedIds;
1429     syncContactsAddedSinceHelper(start, addedIds);
1430
1431     QContactChangeLogFilter filter(QContactChangeLogFilter::EventAdded);
1432     filter.setSince(start);
1433
1434     QList<QContactSortOrder> sortOrder;
1435     
1436     QContactManager::Error error(QContactManager::UnspecifiedError);
1437     QList<QContactLocalId> contactIds = engine()->contactIds(filter, sortOrder, &error);
1438     QCOMPARE(error, QContactManager::NoError);
1439     QCOMPARE(contactIds.size(), addedIds.size());
1440 }
1441
1442 void ut_qtcontacts_trackerplugin::testSyncTrackerEngineContactsIdsAddedSince()
1443 {
1444     QDateTime start;
1445     QList<QContactLocalId> addedIds;
1446     syncContactsAddedSinceHelper(start, addedIds);
1447
1448     QContactChangeLogFilter filter(QContactChangeLogFilter::EventAdded);
1449     filter.setSince(start);
1450
1451     QList<QContactSortOrder> sortOrder;
1452     QContactManager::Error error(QContactManager::UnspecifiedError);
1453     QList<QContactLocalId> contactIds = engine()->contactIds( filter, sortOrder, &error);
1454     QCOMPARE(contactIds.size(), addedIds.size());
1455 }
1456
1457 void ut_qtcontacts_trackerplugin::testSyncContactManagerContactIdsAddedSince()
1458 {
1459     QDateTime start;
1460     QList<QContactLocalId> addedIds;
1461     syncContactsAddedSinceHelper(start, addedIds);
1462     QContactChangeLogFilter filter(QContactChangeLogFilter::EventAdded);
1463     filter.setSince(start);
1464
1465     QList<QContactSortOrder> sortOrder;
1466     QContactManager::Error error(QContactManager::UnspecifiedError);
1467     QList<QContactLocalId> contactIds = engine()->contactIds(filter, sortOrder, &error);
1468     QCOMPARE(error,  QContactManager::NoError);
1469     QCOMPARE(contactIds.size(), addedIds.size());
1470 }
1471
1472
1473 void ut_qtcontacts_trackerplugin::syncContactsAddedSinceHelper(QDateTime& start, QList<QContactLocalId>& addedIds)
1474 {
1475     for (int i = 0; i < 3; i++) {
1476         QContact c;
1477         QContactName name;
1478         name.setFirstName("A"+QString::number(i));
1479         QVERIFY2(c.saveDetail(&name), qPrintable(name.firstName()));
1480         QContactManager::Error error(QContactManager::UnspecifiedError);
1481         QVERIFY2(engine()->saveContact(&c, &error), qPrintable(name.firstName()));
1482         QCOMPARE(error,  QContactManager::NoError);
1483     }
1484
1485     QTest::qWait(1000);
1486     start = QDateTime::currentDateTime();
1487
1488     for (int i = 0; i < 3; i++) {
1489         QContact c;
1490         QContactName name;
1491         name.setFirstName("B"+QString::number(i));
1492         QVERIFY2(c.saveDetail(&name), qPrintable(name.firstName()));
1493         QContactManager::Error error(QContactManager::UnspecifiedError);
1494         QVERIFY2(engine()->saveContact(&c, &error), qPrintable(name.firstName()));
1495         QCOMPARE(error,  QContactManager::NoError);
1496         addedIds.append(c.localId());
1497     }
1498 }
1499
1500 void ut_qtcontacts_trackerplugin::testContactsAddedSince()
1501 {
1502     QList<QContactLocalId> addedIds;
1503     QDateTime start;
1504     for (int i = 0; i < 3; i++) {
1505         QContact c;
1506         QContactName name;
1507         name.setFirstName("A"+QString::number(i));
1508         QVERIFY2(c.saveDetail(&name), qPrintable(name.firstName()));
1509         QContactManager::Error error(QContactManager::UnspecifiedError);
1510         QVERIFY2(engine()->saveContact(&c, &error), qPrintable(name.firstName()));
1511         QCOMPARE(error,  QContactManager::NoError);
1512     }
1513
1514     QTest::qWait(2000);
1515     start = QDateTime::currentDateTime().addSecs(-1);
1516
1517     for (int i = 0; i < 3; i++) {
1518         QContact c;
1519         QContactName name;
1520         name.setFirstName("B"+QString::number(i));
1521         QVERIFY2(c.saveDetail(&name), qPrintable(name.firstName()));
1522         QContactManager::Error error(QContactManager::UnspecifiedError);
1523         QVERIFY2(engine()->saveContact(&c, &error), qPrintable(name.firstName()));
1524         QCOMPARE(error,  QContactManager::NoError);
1525         addedIds.append(c.localId());
1526     }
1527     QTest::qWait(2000);
1528
1529     for(int i = 0; i < 100; i++)
1530     {
1531         usleep(20000);
1532         QCoreApplication::processEvents();
1533     }
1534
1535
1536     // now one asynchronous request to read all the
1537     QContactFetchRequest request;
1538     QContactChangeLogFilter filter(QContactChangeLogFilter::EventAdded);
1539     filter.setSince(start);
1540     request.setFilter(filter);
1541
1542     // here You specify which details are of interest
1543     QStringList details;
1544     details << QContactAvatar::DefinitionName
1545             << QContactBirthday::DefinitionName
1546             << QContactAddress::DefinitionName
1547             << QContactEmailAddress::DefinitionName
1548             << QContactDisplayLabel::DefinitionName
1549             << QContactGender::DefinitionName
1550             << QContactAnniversary::DefinitionName
1551             << QContactName::DefinitionName
1552             << QContactOnlineAccount::DefinitionName
1553             << QContactOrganization::DefinitionName
1554             << QContactPhoneNumber::DefinitionName;
1555     QContactFetchHint fetchHint;
1556     fetchHint.setDetailDefinitionsHint(details);
1557     request.setFetchHint(fetchHint);
1558
1559
1560     Slots slot;
1561     QObject::connect(&request, SIGNAL(resultsAvailable()),
1562             &slot, SLOT(resultsAvailable()));
1563
1564     // start. clients should, instead of following use
1565     // request.setManager(trackermanagerinstance);
1566     // request.start();
1567     engine()->startRequest(&request);
1568     engine()->waitForRequestFinished(&request, 10000);
1569     // if it takes more, then something is wrong
1570     QVERIFY(request.isFinished());
1571     QVERIFY(request.error() == QContactManager::NoError);
1572     QCOMPARE(slot.contacts.count(), addedIds.count());
1573
1574     foreach(QContact cont, slot.contacts) {
1575         QVERIFY2(addedIds.contains(cont.localId()), "One of the added contacts was not reported as added");
1576     }
1577
1578     QContactLocalIdFetchRequest idreq;
1579     filter.setSince(start);
1580     idreq.setFilter(filter);
1581
1582     Slots slot2;
1583     QObject::connect(&idreq, SIGNAL(resultsAvailable()),
1584             &slot2, SLOT(idResultsAvailable()));
1585     engine()->startRequest(&idreq);
1586     engine()->waitForRequestFinished(&idreq, 10000);
1587     QVERIFY(idreq.isFinished());
1588     QCOMPARE(slot2.ids.count(), addedIds.count());
1589     foreach(QContactLocalId id, slot2.ids) {
1590         QVERIFY2(addedIds.contains(id), "One of the added contacts was not reported as added");
1591     }
1592
1593 }
1594
1595 void ut_qtcontacts_trackerplugin::testContactsModifiedSince()
1596 {
1597     QDateTime start;
1598     QList<QContactLocalId> addedIds;
1599     QList<QContactLocalId> modified;
1600
1601     const int contactsToAdd = 5;
1602     const int contactsToModify = 3;
1603     QVERIFY2(contactsToAdd >= contactsToModify, "Cannot modify more contacts than this test has added");
1604     QVERIFY2(contactsToModify+1 <= contactsToAdd, "Cannot modify more contacts than this test has added");
1605
1606     // Add contacts with only first name and store them to list of added
1607     for (int i = 0; i < contactsToAdd; i++) {
1608         QContact c;
1609         QContactName name;
1610         name.setFirstName("A"+QString::number(i));
1611         QVERIFY2(c.saveDetail(&name), qPrintable(name.firstName()));
1612         QContactManager::Error error(QContactManager::UnspecifiedError);
1613         QVERIFY2(engine()->saveContact(&c, &error), qPrintable(name.firstName()));
1614         QCOMPARE(error,  QContactManager::NoError);
1615         addedIds.append(c.localId());
1616     }
1617
1618     QTest::qWait(2000);
1619     start = QDateTime::currentDateTime();
1620
1621    // Modify and save rest of the contacts
1622     for (int i = 0; i < contactsToModify; i++) {
1623         QContact c = contact(addedIds[i]);
1624         QContactName name = c.detail<QContactName>();
1625         // Modify name
1626         name.setFirstName("B"+QString::number(i));
1627         QVERIFY2(c.saveDetail(&name), qPrintable(name.firstName()));
1628         QContactManager::Error error(QContactManager::UnspecifiedError);
1629         QVERIFY2(engine()->saveContact(&c, &error), qPrintable(name.firstName()));
1630         QCOMPARE(error,  QContactManager::NoError);
1631         modified.append(c.localId());
1632     }
1633     // Set filter
1634     QContactChangeLogFilter filter(QContactChangeLogFilter::EventChanged);
1635     filter.setSince(start);
1636
1637     QContactLocalIdFetchRequest idfetch;
1638     QContactFetchRequest fetch;
1639     idfetch.setFilter(filter);
1640     fetch.setFilter(filter);
1641     engine()->startRequest(&idfetch);
1642     engine()->waitForRequestFinished(&idfetch, 10000);
1643     QVERIFY2(idfetch.isFinished(), "Id fetch request did not finish on time");
1644     QVERIFY2(idfetch.error() == QContactManager::NoError, "Id fetch request finished with errors");
1645     QList<QContactLocalId> actuallyModifiedIds = idfetch.ids();
1646     engine()->startRequest(&fetch);
1647     engine()->waitForRequestFinished(&fetch, 10000);
1648     QVERIFY2(fetch.isFinished(), "Fetch request did not finish on time");
1649     QVERIFY2(fetch.error() == QContactManager::NoError, "Fetch request finished with errors");
1650     QList<QContact> actuallyModified = fetch.contacts();
1651
1652     // Num of actually modified should be same as supposedly modified
1653     QCOMPARE(actuallyModifiedIds.count(), modified.count());
1654     QCOMPARE(actuallyModified.count(), modified.count());
1655     // All the ids of the modified contacts should be found in the result list
1656     foreach (QContactLocalId id, modified) {
1657         QVERIFY2(actuallyModifiedIds.contains(id), "One the modified contacts was not reported as modified");
1658     }
1659 }
1660
1661 void ut_qtcontacts_trackerplugin::testContactsRemovedSince()
1662 {
1663     QDateTime start = QDateTime::currentDateTime();
1664     QContactChangeLogFilter filter(QContactChangeLogFilter::EventRemoved);
1665     filter.setSince(start);
1666     QList<QContactSortOrder> sorts;
1667     QContactManager::Error error(QContactManager::UnspecifiedError);
1668     QTest::ignoreMessage(QtWarningMsg, "\"QContactFilter::ChangeLogFilter\" - "
1669                          "unsupported event type: \"QContactChangeLogFilter::EventRemoved\" ");
1670     QList<QContactLocalId> actuallyRemoved = engine()->contactIds(filter, sorts, &error);
1671     QCOMPARE(error,  QContactManager::NotSupportedError);
1672     QVERIFY(actuallyRemoved.isEmpty());
1673 }
1674 /*
1675 void ut_qtcontacts_trackerplugin::testGroupsAddedSince()
1676 {
1677     qDebug() << "Not implemented";
1678     QVERIFY(false);
1679 }
1680
1681 void ut_qtcontacts_trackerplugin::testGroupsModifiedSince()
1682 {
1683     qDebug() << "Not implemented";
1684     QVERIFY(false);
1685 }
1686
1687 void ut_qtcontacts_trackerplugin::testGroupsRemovedSince()
1688 {
1689     qDebug() << "Not implemented";
1690     QVERIFY(false);
1691 }
1692 */
1693
1694 void ut_qtcontacts_trackerplugin::cleanupTestCase()
1695 {
1696     resetEngine();
1697 }
1698
1699 void ut_qtcontacts_trackerplugin::cleanup()
1700 {
1701     QContactManager::Error error;
1702
1703     foreach (QContactLocalId id, addedContacts) {
1704         engine()->removeContact(id, &error);
1705     }
1706
1707     addedContacts.clear();
1708 }
1709
1710
1711 void ut_qtcontacts_trackerplugin::testNcoTypes()
1712 {
1713     using namespace SopranoLive;
1714
1715     QList<QContactLocalId> ids;
1716     RDFVariable RDFContact = RDFVariable::fromType<nco::PersonContact>();
1717     RDFSelect query;
1718
1719     query.addColumn("contact_uri", RDFContact);
1720     query.addColumn("contactId", RDFContact.property<nco::contactLocalUID>());
1721     LiveNodes ncoContacts = ::BackEnds::Tracker::tracker()->modelQuery(query);
1722     foreach( Live<nco::PersonContact> p, ncoContacts ) {
1723         QVERIFY(p.hasType<nco::Contact>());
1724         QVERIFY(p.hasType<nco::Role>());
1725         QVERIFY(p.hasType<nco::PersonContact>());
1726     }
1727 }
1728
1729 void ut_qtcontacts_trackerplugin::testClassHierarchy()
1730 {
1731     const QTrackerClassHierarchy &classes(engine()->classes());
1732
1733     // test isSubClassOf()
1734     QVERIFY(classes.isSubClassOf(nco::PersonContact::iri(), nco::Contact::iri()));
1735     QVERIFY(classes.isSubClassOf(nco::VoicePhoneNumber::iri(), nco::PhoneNumber::iri()));
1736     QVERIFY(classes.isSubClassOf(nco::CellPhoneNumber::iri(), nco::VoicePhoneNumber::iri()));
1737
1738     // test inheritedClasses()
1739     QCOMPARE(classes.inheritedClasses(nco::PersonContact::iri(), QStringList()),
1740              QSet<QUrl>() << nco::PersonContact::iri() <<
1741              nco::Contact::iri() << nco::Role::iri() <<
1742              nie::InformationElement::iri() <<
1743              rdfs::Resource::iri());
1744
1745     QCOMPARE(classes.inheritedClasses(nco::PersonContact::iri(),
1746                                       QStringList(QLatin1String(nco_namespace_prefix))),
1747              QSet<QUrl>() << nco::PersonContact::iri() <<
1748              nco::Contact::iri() << nco::Role::iri());
1749
1750     // test enum values
1751     int carPhoneNumberId = classes.getId(nco::CarPhoneNumber::iri());
1752     int genderFemaleId = classes.getId(nco::gender_female::iri());
1753
1754     QVERIFY(0 != carPhoneNumberId);
1755     QCOMPARE(classes.getIri(carPhoneNumberId), nco::CarPhoneNumber::iri());
1756
1757     QVERIFY(0 != genderFemaleId);
1758     QCOMPARE(classes.getIri(genderFemaleId), nco::gender_female::iri());
1759 }
1760
1761 void ut_qtcontacts_trackerplugin::testAsyncReadContacts()
1762 {
1763     addedContacts.clear();
1764     // Add at least one contact to be sure that this doesn't fail because tracker is clean
1765
1766     QStringList firstNames, lastNames;
1767     firstNames << "aa" << "ab" << "ac" << "dd" << "fe";
1768     lastNames << "fe" << "ab" << "dd" << "dd" << "aa";
1769     for (int i = 0; i < firstNames.count(); i++) {
1770         QContact c;
1771         QContactName name;
1772         name.setFirstName(firstNames.at(i));
1773         name.setLastName(lastNames.at(i));
1774         QContactAvatar avatar;
1775         avatar.setImageUrl(QUrl("default_avatar.png"));
1776         QVERIFY(c.saveDetail(&name));
1777         QVERIFY(c.saveDetail(&avatar));
1778         QContactManager::Error error(QContactManager::UnspecifiedError);
1779         QVERIFY(engine()->saveContact(&c, &error));
1780         QCOMPARE(error,  QContactManager::NoError);
1781         addedContacts.append(c.localId());
1782     }
1783     
1784     // Prepare the filter for the request - we really should test only the contact we add here.
1785     QContactLocalIdFilter filter;
1786     filter.setIds(addedContacts);
1787
1788     // this one will get complete contacts
1789
1790     Slots slot;
1791     QContactFetchRequest request;
1792     QList<QContactSortOrder> sorting;
1793     QContactSortOrder sort, sort1;
1794     sort.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldLastName);
1795     sort1.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirstName);
1796     sorting << sort << sort1;
1797     QStringList details; details << QContactName::DefinitionName << QContactAvatar::DefinitionName;
1798     QContactFetchHint fetchHint;
1799     fetchHint.setDetailDefinitionsHint(details);
1800     request.setFetchHint(fetchHint);
1801     request.setSorting(sorting);
1802     request.setFilter(filter);
1803
1804     QObject::connect(&request, SIGNAL(resultsAvailable()),
1805             &slot, SLOT(resultsAvailable()));
1806
1807     // this one only ids
1808     QContactLocalIdFetchRequest request1;
1809     request1.setFilter(filter);
1810     QObject::connect(&request1, SIGNAL(resultsAvailable()),
1811             &slot, SLOT(idResultsAvailable()));
1812
1813     // the purpose is to compare if all contacts are loaded, and
1814     // if optional fields are defined properly in request
1815
1816     // start both at once
1817     engine()->startRequest(&request);
1818     engine()->startRequest(&request1);
1819     engine()->waitForRequestFinished(&request, 10000);
1820     engine()->waitForRequestFinished(&request1, 10000);
1821
1822
1823     // if it takes more, then something is wrong
1824     QVERIFY(request.isFinished());
1825     QVERIFY(request1.isFinished());
1826
1827     // there need1 to be something added to be verified
1828     QVERIFY(!request.contacts().isEmpty());
1829     // now ask for one contact
1830     QVERIFY(!slot.contacts.isEmpty());
1831     // there need to be something added to be verified
1832     QVERIFY(!request1.ids().isEmpty());
1833     // now ask for one contact
1834     QVERIFY(!slot.ids.isEmpty());
1835
1836     QCOMPARE(slot.contacts.count(), slot.ids.count());
1837     QVERIFY(slot.contacts.count() >= firstNames.count());
1838     for( int i = 0; i < slot.contacts.size() -1 ; i++)
1839     {
1840         QContact contact = slot.contacts[i];
1841         QContact contact1 = slot.contacts[i+1];
1842         QString last0 = contact.detail<QContactName>().lastName();
1843         QString first0 = contact.detail<QContactName>().firstName();
1844         QString last1 = contact1.detail<QContactName>().lastName();
1845         QString first1 = contact1.detail<QContactName>().firstName();
1846         // sorting
1847         qDebug() << "contacts:" << contact.localId() << first0 << last0;
1848         bool test = last0 < last1 || (last0 == last1 && first0 <= first1);
1849         if (!test) {
1850             qDebug() << "contacts sort failed. First: " << contact1.localId() << first0 << last1 << "lasts: " << last0 << last1;
1851         }
1852         QVERIFY2(test, "Sorting failed.");
1853     }
1854
1855 }
1856
1857 void ut_qtcontacts_trackerplugin::testSortContacts()
1858 {
1859     // create sample contacts
1860     const QStringList samples = QStringList() << "Adelhoefer" << "Lose" << "Zumwinkel";
1861     QList<QContact> contacts;
1862
1863     foreach(const QString &lastName, samples) {
1864         QContactName name;
1865         name.setLastName(lastName);
1866         contacts.append(QContact());
1867         QVERIFY(contacts.last().saveDetail(&name));
1868     }
1869
1870     // save sample contacts
1871     QContactManager::Error error = QContactManager::UnspecifiedError;
1872     bool success = engine()->saveContacts(&contacts, 0, &error);
1873     QCOMPARE(error, QContactManager::NoError);
1874     QVERIFY(success);
1875
1876     // build local id list
1877     QContactLocalIdList localIds;
1878
1879     for(int i = 0; i < contacts.count(); ++i) {
1880         QVERIFY2(0 != contacts[i].localId(), qPrintable(QString::number(i)));
1881         localIds.append(contacts[i].localId());
1882     }
1883
1884     QCOMPARE(localIds.count(), samples.count());
1885
1886     // prepare fetch request
1887     QContactLocalIdFilter filter;
1888     filter.setIds(localIds);
1889
1890     QContactFetchHint fetchHint;
1891     fetchHint.setDetailDefinitionsHint(QStringList() << QContactName::DefinitionName);
1892
1893     QList<QContactSortOrder> sortOrders;
1894     sortOrders.append(QContactSortOrder());
1895
1896     sortOrders.last().setDetailDefinitionName(QContactName::DefinitionName,
1897                                               QContactName::FieldLastName);
1898
1899     // fetch contacts in ascending order
1900     error = QContactManager::UnspecifiedError;
1901     sortOrders.last().setDirection(Qt::AscendingOrder);
1902     contacts = engine()->contacts(filter, sortOrders, fetchHint, &error);
1903     QCOMPARE(error, QContactManager::NoError);
1904     QCOMPARE(contacts.count(), localIds.count());
1905
1906     // verify fetched contacts are in ascending order
1907     QContactLocalIdList fetchedIds;
1908     QStringList fetchedNames;
1909
1910     foreach(const QContact &c, contacts) {
1911         fetchedNames.append(c.detail<QContactName>().lastName());
1912         fetchedIds.append(c.localId());
1913     }
1914
1915     QCOMPARE(fetchedNames, samples);
1916     QCOMPARE(fetchedIds, localIds);
1917
1918     // fetch contacts in descending order
1919     error = QContactManager::UnspecifiedError;
1920     sortOrders.last().setDirection(Qt::DescendingOrder);
1921     contacts = engine()->contacts(filter, sortOrders, fetchHint, &error);
1922     QCOMPARE(error, QContactManager::NoError);
1923     QCOMPARE(contacts.count(), localIds.count());
1924
1925     // verify fetched contacts are in descending order
1926     fetchedNames.clear();
1927     fetchedIds.clear();
1928
1929     foreach(const QContact &c, contacts) {
1930         fetchedNames.prepend(c.detail<QContactName>().lastName());
1931         fetchedIds.prepend(c.localId());
1932     }
1933
1934     QCOMPARE(fetchedNames, samples);
1935     QCOMPARE(fetchedIds, localIds);
1936 }
1937
1938 void ut_qtcontacts_trackerplugin::testFilterContacts()
1939 {
1940     // this one will get complete contacts
1941     QContact c;
1942     QContactName name;
1943     name.setFirstName("Zuba");
1944     name.setLastName("Zub");
1945     c.saveDetail(&name);
1946     QContactPhoneNumber phone;
1947
1948     phone.setNumber("4872444");
1949     c.saveDetail(&phone);
1950
1951     QContactBirthday birthday;
1952     birthday.setDate(QDate(2010, 2, 14));
1953     c.saveDetail(&birthday);
1954
1955     QContactManager::Error error(QContactManager::UnspecifiedError);
1956     engine()->saveContact(&c, &error);
1957     QCOMPARE(error,  QContactManager::NoError);
1958
1959     QStringList details;
1960     details << QContactName::DefinitionName << QContactAvatar::DefinitionName
1961             << QContactPhoneNumber::DefinitionName;
1962
1963     QContactFetchRequest request;
1964     QContactDetailFilter filter;
1965     filter.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
1966
1967     Slots slot;
1968     QObject::connect(&request, SIGNAL(resultsAvailable()),
1969             &slot, SLOT(resultsAvailable()));
1970     filter.setValue(QString("4872444"));
1971     filter.setMatchFlags(QContactFilter::MatchEndsWith);
1972
1973     QContactFetchHint fetchHint;
1974     fetchHint.setDetailDefinitionsHint(details);
1975     request.setFetchHint(fetchHint);
1976     request.setFilter(filter);
1977
1978     engine()->startRequest(&request);
1979     engine()->waitForRequestFinished(&request, 1000);
1980
1981     // if it takes more, then something is wrong
1982     QVERIFY(request.isFinished());
1983     QVERIFY(!request.contacts().isEmpty());
1984
1985     QVERIFY(!slot.contacts.isEmpty());
1986
1987     bool containsThisId = false;
1988     foreach(const QContact &contact, slot.contacts)
1989     {
1990         if( contact.localId() == c.localId())
1991             containsThisId = true;
1992         bool containsPhone = false;
1993         foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName))
1994         {
1995             if(detail.value(QContactPhoneNumber::FieldNumber).contains("4872444"))
1996             {
1997                 containsPhone = true;
1998                 break;
1999             }
2000         }
2001         QVERIFY(containsPhone);
2002     }
2003     QVERIFY(containsThisId);
2004
2005     // filter by birthday range
2006     QContactDetailRangeFilter rangeFilter;
2007     rangeFilter.setDetailDefinitionName(QContactBirthday::DefinitionName,
2008                                         QContactBirthday::FieldBirthday);
2009     // include lower & exclude upper by default
2010     rangeFilter.setRange(QDate(2010, 2, 14), QDate(2010, 2, 15));
2011     QContactFetchHint fetchHintBirthday;
2012     fetchHintBirthday.setDetailDefinitionsHint(QStringList()<< QContactBirthday::DefinitionName);
2013     error = QContactManager::UnspecifiedError;
2014     QList<QContact> contacts(engine()->contacts(rangeFilter, QList<QContactSortOrder>(),
2015                                                 fetchHintBirthday, &error));
2016     QCOMPARE(error,  QContactManager::NoError);
2017     QVERIFY(!contacts.isEmpty());
2018     bool containsOurContact(false);
2019     foreach(const QContact &cont, contacts) {
2020         QCOMPARE(cont.detail<QContactBirthday>().date(), QDate(2010, 2, 14));
2021
2022         if(c.id() == cont.id()) {
2023             containsOurContact = true;
2024         }
2025     }
2026     QVERIFY(containsOurContact);
2027 }
2028
2029 void ut_qtcontacts_trackerplugin::testFilterContactsEndsWithAndPhoneNumber()
2030 {
2031     QTrackerContactSettings settings;
2032     QContactLocalId initialMatchCount = settings.localPhoneNumberLength();
2033
2034     QContact matchingContact;
2035     QContactName name;
2036     name.setFirstName("Zuba");
2037     name.setLastName("Zub");
2038     matchingContact.saveDetail(&name);
2039     QContactPhoneNumber phone;
2040     phone.setContexts(QContactPhoneNumber::ContextWork);
2041     phone.setNumber("3210987654321");
2042     matchingContact.saveDetail(&phone);
2043     QContactPhoneNumber phone1;
2044     phone1.setNumber("98653");
2045     matchingContact.saveDetail(&phone1);
2046     QContactManager::Error error(QContactManager::UnspecifiedError);
2047     QVERIFY(engine()->saveContact(&matchingContact, &error));
2048     QCOMPARE(error,  QContactManager::NoError);
2049
2050     QStringList details;
2051     details << QContactName::DefinitionName << QContactAvatar::DefinitionName
2052             << QContactPhoneNumber::DefinitionName;
2053
2054     QContactFetchRequest request;
2055     QContactDetailFilter filter;
2056     filter.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
2057     QContactFetchHint fetchHint;
2058     fetchHint.setDetailDefinitionsHint(details);
2059     // test matching of 7 last digits
2060     int matchCount = 7;
2061     qDebug() << "Test matching of" << matchCount << "last digits.";
2062     settings.setLocalPhoneNumberLength(matchCount);
2063
2064     // shorter phone numbers do exact match
2065     {
2066         filter.setValue("98653");
2067         filter.setMatchFlags(QContactFilter::MatchPhoneNumber);
2068         error = QContactManager::UnspecifiedError;
2069         QList<QContact> conts = engine()->contacts(filter, QList<QContactSortOrder>(), fetchHint, &error);
2070         QCOMPARE(error,  QContactManager::NoError);
2071         QVERIFY(!conts.isEmpty());
2072         bool containsMatchingC(false);
2073         foreach(const QContact &contact, conts) {
2074             if (contact.localId() == matchingContact.localId())
2075                 containsMatchingC = true;
2076             bool containsPhone = false;
2077             foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName)) {
2078                 // only exact match for shorter phone numbers
2079                 if (detail.value(QContactPhoneNumber::FieldNumber)=="98653") {
2080                     containsPhone = true;
2081                     break;
2082                 }
2083             }
2084             QVERIFY(containsPhone);
2085         }
2086         QVERIFY(containsMatchingC);
2087     }
2088
2089     // settings phone number match
2090     {
2091         filter.setValue("37654321");
2092         filter.setMatchFlags(QContactFilter::MatchPhoneNumber);
2093         error = QContactManager::UnspecifiedError;
2094         QList<QContact> conts = engine()->contacts(filter, QList<QContactSortOrder>(), fetchHint, &error);
2095         QCOMPARE(error,  QContactManager::NoError);
2096         QVERIFY(!conts.isEmpty());
2097         bool containsMatchingC(false);
2098         foreach(const QContact &contact, conts) {
2099             if (contact.localId() == matchingContact.localId())
2100                 containsMatchingC = true;
2101             bool containsPhone = false;
2102             foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName)) {
2103                 // only exact match for shorter phone numbers
2104                 if (normalizePhoneNumber(detail.value(QContactPhoneNumber::FieldNumber)).right(matchCount)=="7654321") {
2105                     containsPhone = true;
2106                     break;
2107                 }
2108             }
2109             QVERIFY(containsPhone);
2110         }
2111         QVERIFY(containsMatchingC);
2112     }
2113
2114     Slots slot;
2115     QObject::connect(&request, SIGNAL(resultsAvailable()),
2116             &slot, SLOT(resultsAvailable()));
2117
2118     {
2119
2120         QString matchValue = "3000007654321";
2121         QContact nonMatchingContact;
2122         nonMatchingContact.saveDetail(&name);
2123         phone.setNumber("3210980654321");
2124         nonMatchingContact.saveDetail(&phone);
2125         error = QContactManager::UnspecifiedError;
2126         QVERIFY(engine()->saveContact(&nonMatchingContact, &error));
2127         QCOMPARE(error,  QContactManager::NoError);
2128
2129         filter.setValue(matchValue);
2130         filter.setMatchFlags(QContactFilter::MatchEndsWith);
2131
2132         request.setFetchHint(fetchHint);
2133         request.setFilter(filter);
2134
2135         engine()->startRequest(&request);
2136         engine()->waitForRequestFinished(&request, 1000);
2137         QVERIFY(request.isFinished());
2138         QVERIFY(!slot.contacts.isEmpty());
2139
2140         bool containsMatchingId = false;
2141         bool containsNonMatchingId = false;
2142         foreach(const QContact &contact, slot.contacts) {
2143             if (contact.localId() == nonMatchingContact.localId())
2144                 containsNonMatchingId = true;
2145             if (contact.localId() == matchingContact.localId())
2146                 containsMatchingId = true;
2147             bool containsPhone = false;
2148             foreach(const QContactDetail &detail, contact.details(QContactPhoneNumber::DefinitionName)) {
2149                 if (detail.value(QContactPhoneNumber::FieldNumber).endsWith(matchValue.right(matchCount))) {
2150                     containsPhone = true;
2151                     break;
2152                 }
2153             }
2154             QVERIFY(containsPhone);
2155         }
2156         QVERIFY(containsMatchingId);
2157         QVERIFY(!containsNonMatchingId);
2158     }
2159
2160     {
2161         // test matching of 11 last digits
2162         matchCount = 11;
2163         qDebug() << "Test matching of" << matchCount << "last digits.";
2164         settings.setLocalPhoneNumberLength(matchCount);
2165         QString matchValue = "3010987654321";
2166         QContact nonMatchingContact;
2167         nonMatchingContact.saveDetail(&name);
2168         phone.setNumber("3200987654321");
2169         nonMatchingContact.saveDetail(&phone);
2170         error = QContactManager::UnspecifiedError;
2171         engine()->saveContact(&nonMatchingContact, &error);
2172         QCOMPARE(error,  QContactManager::NoError);
2173
2174         QContact matchingContactWithShorterNumber;
2175         QContactName name1;
2176         name1.setFirstName("ShortNumber");
2177         name1.setLastName("Zub1");
2178         matchingContactWithShorterNumber.saveDetail(&name1);
2179         QContactPhoneNumber phone1;
2180         phone1.setNumber("54321");
2181         matchingContactWithShorterNumber.saveDetail(&phone1);
2182         error = QContactManager::UnspecifiedError;
2183         engine()->saveContact(&matchingContactWithShorterNumber, &error);
2184         QCOMPARE(error,  QContactManager::NoError);
2185
2186
2187         filter.setValue(matchValue);
2188         filter.setMatchFlags(QContactFilter::MatchEndsWith);
2189
2190         request.setFetchHint(fetchHint);
2191         request.setFilter(filter);
2192
2193         engine()->startRequest(&request);
2194         engine()->waitForRequestFinished(&request, 1000);
2195
2196         QVERIFY(request.isFinished());
2197         QVERIFY(!slot.contacts.isEmpty());
2198
2199         bool containsMatchingId = false;
2200         bool containsNonMatchingId = false;
2201         foreach(const QContact &contact, slot.contacts) {
2202             if (contact.localId() == nonMatchingContact.localId())
2203                 containsNonMatchingId = true;
2204             if (contact.localId() == matchingContact.localId())
2205                 containsMatchingId = true;
2206             bool containsPhone = false;
2207             foreach(const QContactPhoneNumber &detail, contact.details<QContactPhoneNumber>()) {
2208                 if (detail.number().endsWith(matchValue.right(matchCount))) {
2209                     containsPhone = true;
2210                     break;
2211                 }
2212             }
2213             QVERIFY(containsPhone);
2214         }
2215         QVERIFY(containsMatchingId);
2216         QVERIFY(!containsNonMatchingId);
2217
2218         // now verify with short number
2219         filter.setValue("54321");
2220         filter.setMatchFlags(QContactFilter::MatchEndsWith);
2221
2222         request.setFetchHint(fetchHint);
2223         request.setFilter(filter);
2224
2225         engine()->startRequest(&request);
2226         engine()->waitForRequestFinished(&request, 1000);
2227
2228         QVERIFY(request.isFinished());
2229         QVERIFY(!slot.contacts.isEmpty());
2230         bool containsShort = false;
2231         foreach(const QContact &contact, slot.contacts) {
2232             if (contact.localId() == matchingContactWithShorterNumber.localId())
2233                 containsShort = true;
2234         }
2235         QVERIFY(containsShort);
2236     }
2237     settings.setLocalPhoneNumberLength(initialMatchCount);
2238 }
2239
2240 void ut_qtcontacts_trackerplugin::testFilterTwoNameFields()
2241 {
2242     // init test
2243     QMap<QContactLocalId, QContactName> names;
2244     for (int i = 0; i < 3; i++) {
2245         QContact c;
2246         QContactName name;
2247         name.setFirstName(QUuid::createUuid().toString() + QString::number(i));
2248         name.setLastName(QUuid::createUuid().toString() + QString::number(i));
2249         c.saveDetail(&name);
2250         QContactAvatar avatar;
2251         avatar.setImageUrl(QUrl(QUuid::createUuid().toString()));
2252         c.saveDetail(&avatar);
2253         QContactManager::Error error(QContactManager::UnspecifiedError);
2254         QVERIFY(engine()->saveContact(&c, &error));
2255         QCOMPARE(error,  QContactManager::NoError);
2256         names.insert(c.localId(), name);
2257         addedContacts.append(c.localId());
2258     }
2259
2260     // Init filter
2261     QContactLocalId searchId = names.keys().at(1);
2262     QString searchFirst = names.value(searchId).firstName();
2263     QString searchLast = names.value(searchId).lastName();
2264     QContactUnionFilter ufilter;
2265     QContactDetailFilter filterFirst;
2266     filterFirst.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirstName);
2267     filterFirst.setMatchFlags(QContactFilter::MatchExactly);
2268     filterFirst.setValue(searchFirst);
2269     QContactDetailFilter filterLast;
2270     filterLast.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldLastName);
2271     filterLast.setMatchFlags(QContactFilter::MatchExactly);