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