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