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