1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#define QT_STATICPLUGIN
35
36#include <QtTest/QtTest>
37#include <QtGlobal>
38#include <QtCore/qnumeric.h>
39
40#include <QtContacts>
41#include "qcontactmanagerdataholder.h"
42
43#if defined(USE_VERSIT_PLZ)
44// This makes it easier to create specific QContacts
45#include <QtVersit/qversitcontactimporter.h>
46#include <QtVersit/qversitdocument.h>
47#include <QtVersit/qversitreader.h>
48QTVERSIT_USE_NAMESPACE
49#endif
50
51QTCONTACTS_USE_NAMESPACE
52
53#define QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(params) params.remove(QString::fromLatin1(QTCONTACTS_VERSION_NAME)); \
54 params.remove(QString::fromLatin1(QTCONTACTS_IMPLEMENTATION_VERSION_NAME))
55
56#define QTRY_COMPARE_SIGNALS_LOCALID_COUNT(__signalSpy, __expectedCount) \
57 do { \
58 int __spiedSigCount = 0; \
59 const int __step = 50; \
60 const int __timeout = 5000; \
61 for (int __i = 0; __i < __timeout; __i+=__step) { \
62 /* accumulate added from signals */ \
63 __spiedSigCount = 0; \
64 const QList<QList<QVariant> > __spiedSignals = __signalSpy; \
65 foreach (const QList<QVariant> &__arguments, __spiedSignals) { \
66 foreach (QContactId __localId, __arguments.first().value<QList<QContactId> >()) { \
67 QVERIFY(!(__localId.isNull())); \
68 __spiedSigCount++; \
69 } \
70 } \
71 if(__spiedSigCount == __expectedCount) { \
72 break; \
73 } \
74 QTest::qWait(__step); \
75 } \
76 QCOMPARE(__spiedSigCount, __expectedCount); \
77 } while(0)
78
79//TESTED_COMPONENT=src/contacts
80
81// to get QFETCH to work with the template expression...
82typedef QMap<QString,QString> tst_QContactManager_QStringMap;
83Q_DECLARE_METATYPE(tst_QContactManager_QStringMap)
84Q_DECLARE_METATYPE(QList<QContactId>)
85Q_DECLARE_METATYPE(QList<QContactDetail::DetailType>)
86
87/* A class that no backend can support */
88class UnsupportedMetatype {
89 int foo;
90};
91Q_DECLARE_METATYPE(UnsupportedMetatype)
92Q_DECLARE_METATYPE(QContact)
93Q_DECLARE_METATYPE(QContactManager::Error)
94Q_DECLARE_METATYPE(Qt::CaseSensitivity)
95
96class tst_QContactManager : public QObject
97{
98Q_OBJECT
99
100public:
101 tst_QContactManager();
102 virtual ~tst_QContactManager();
103
104private:
105 void dumpContactDifferences(const QContact& a, const QContact& b);
106 void dumpContact(const QContact &c);
107 void dumpContacts(QContactManager *cm);
108 bool isSuperset(const QContact& ca, const QContact& cb);
109 QList<QContactDetail> removeAllDefaultDetails(const QList<QContactDetail>& details);
110 void addManagers(); // add standard managers to the data
111 QContact createContact(QString firstName, QString lastName, QString phoneNumber);
112 void saveContactName(QContact *contact,QContactName *contactName, const QString &name) const;
113
114 QScopedPointer<QContactManagerDataHolder> managerDataHolder;
115
116public slots:
117 void initTestCase();
118 void cleanupTestCase();
119private slots:
120
121 void doDump();
122 void doDump_data() {addManagers();}
123
124 /* Special test with special data */
125 void uriParsing();
126 void nameSynthesis();
127
128 /* Tests that are run on all managers */
129 void metadata();
130 void nullIdOperations();
131 void add();
132 void update();
133 void remove();
134 void addAndUpdate();
135 void batch();
136 void observerDeletion();
137 void signalEmission();
138 void actionPreferences();
139 void selfContactId();
140 void detailOrders();
141 void relationships();
142 void contactType();
143 void lateDeletion();
144 void compareVariant();
145 void createCollection();
146 void modifyCollection();
147 void removeCollection();
148 void saveContactIntoCollections();
149
150#if defined(USE_VERSIT_PLZ)
151 void partialSave();
152 void partialSave_data() {addManagers();}
153#endif
154
155 /* Tests that take no data */
156 void errorStayingPut();
157 void ctors();
158 void invalidManager();
159 void memoryManager();
160 void overrideManager();
161 void changeSet();
162 void fetchHint();
163 void lazyConnections();
164 void testInterSectionOfIdFilters();
165 void testInterSectionOfIdAndDetailFilters();
166
167 /* Special test with special data */
168 void uriParsing_data();
169 void nameSynthesis_data();
170 void compareVariant_data();
171
172 /* Tests that are run on all managers */
173 void metadata_data() {addManagers();}
174 void nullIdOperations_data() {addManagers();}
175 void add_data() {addManagers();}
176 void update_data() {addManagers();}
177 void remove_data() {addManagers();}
178 void addAndUpdate_data() {addManagers();}
179 void batch_data() {addManagers();}
180 void signalEmission_data() {addManagers();}
181 void actionPreferences_data() {addManagers();}
182 void selfContactId_data() {addManagers();}
183 void detailOrders_data() {addManagers();}
184 void relationships_data() {addManagers();}
185 void contactType_data() {addManagers();}
186 void lateDeletion_data() {addManagers();}
187 void testInterSectionOfIdFilters_data() {addManagers();}
188 void testInterSectionOfIdAndDetailFilters_data() {addManagers();}
189 void createCollection_data() {addManagers();}
190 void modifyCollection_data() {addManagers();}
191 void removeCollection_data() {addManagers();}
192 void saveContactIntoCollections_data() {addManagers();}
193};
194
195// Helper class that connects to a signal on ctor, and disconnects on dtor
196class QTestSignalSink : public QObject {
197 Q_OBJECT
198public:
199 // signal and object must remain valid for the lifetime
200 QTestSignalSink(QObject *object, const char *signal)
201 : mObject(object), mSignal(signal)
202 {
203 connect(sender: object, signal, receiver: this, SLOT(ignored()));
204 }
205
206 ~QTestSignalSink()
207 {
208 disconnect(sender: mObject, signal: mSignal, receiver: this, SLOT(ignored()));
209 }
210
211public slots:
212 void ignored() {}
213
214private:
215 QObject *mObject;
216 const char * const mSignal;
217};
218
219QT_BEGIN_NAMESPACE
220static uint qHash(const QMetaMethod &m)
221{
222 return qHash(key: m.methodIndex());
223}
224QT_END_NAMESPACE
225
226/* Two backends for testing lazy signal connections */
227class QContactLazyEngine2 : public QContactManagerEngine
228{
229public:
230 QContactLazyEngine2() {}
231 QString managerName() const {return "lazy2";}
232
233 /*! \reimp */
234 int managerVersion() const {return 0;}
235
236 void connectNotify(const QMetaMethod &signal)
237 {
238 connectionCounts[signal]++;
239 }
240 void disconnectNotify(const QMetaMethod &signal)
241 {
242 connectionCounts[signal]--;
243 }
244
245 static QHash<QMetaMethod, int> connectionCounts; // signal to count
246};
247QHash<QMetaMethod, int> QContactLazyEngine2::connectionCounts;
248
249class QContactLazyEngine : public QContactManagerEngine
250{
251public:
252 QContactLazyEngine() {}
253 QString managerName() const {
254 return "lazy";}
255
256 /*! \reimp */
257 int managerVersion() const {return 0;}
258
259 void connectNotify(const QMetaMethod &signal)
260 {
261 connectionCounts[signal]++;
262 }
263 void disconnectNotify(const QMetaMethod &signal)
264 {
265 connectionCounts[signal]--;
266 }
267 static QHash<QMetaMethod, int> connectionCounts; // signal to count
268};
269QHash<QMetaMethod, int> QContactLazyEngine::connectionCounts;
270
271/* Static lazy engine factory */
272class LazyEngineFactory : public QContactManagerEngineFactory
273{
274 Q_OBJECT
275 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QContactManagerEngineFactoryInterface" FILE "lazy.json")
276 public:
277 QContactManagerEngine* engine(const QMap<QString, QString>& parameters, QContactManager::Error* error);
278 QString managerName() const {return "testlazy";}
279};
280
281QContactManagerEngine* LazyEngineFactory::engine(const QMap<QString, QString>& parameters, QContactManager::Error* error)
282{
283 // Return one or the other
284 Q_UNUSED(error)
285 if (parameters.value(akey: "version") == QString("1"))
286 return new QContactLazyEngine();
287 else
288 return new QContactLazyEngine2();
289}
290
291static inline QContactId makeId(const QString &managerName, uint id)
292{
293 return QContactId(QStringLiteral("qtcontacts:basic%1:").arg(a: managerName), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
294}
295
296tst_QContactManager::tst_QContactManager()
297{
298}
299
300tst_QContactManager::~tst_QContactManager()
301{
302}
303
304void tst_QContactManager::initTestCase()
305{
306 managerDataHolder.reset(other: new QContactManagerDataHolder());
307
308 /* Make sure these other test plugins are NOT loaded by default */
309 // These are now removed from the list of managers in addManagers()
310 //QVERIFY(!QContactManager::availableManagers().contains("testdummy"));
311 //QVERIFY(!QContactManager::availableManagers().contains("teststaticdummy"));
312 //QVERIFY(!QContactManager::availableManagers().contains("maliciousplugin"));
313}
314
315void tst_QContactManager::cleanupTestCase()
316{
317 managerDataHolder.reset(other: 0);
318}
319
320void tst_QContactManager::dumpContactDifferences(const QContact& ca, const QContact& cb)
321{
322 // Try to narrow down the differences
323 QContact a(ca);
324 QContact b(cb);
325
326 QContactName n1 = a.detail(type: QContactName::Type);
327 QContactName n2 = b.detail(type: QContactName::Type);
328
329 // Check the name components in more detail
330 QCOMPARE(n1.firstName(), n2.firstName());
331 QCOMPARE(n1.middleName(), n2.middleName());
332 QCOMPARE(n1.lastName(), n2.lastName());
333 QCOMPARE(n1.prefix(), n2.prefix());
334 QCOMPARE(n1.suffix(), n2.suffix());
335
336 // Now look at the rest
337 QList<QContactDetail> aDetails = a.details();
338 QList<QContactDetail> bDetails = b.details();
339
340 // They can be in any order, so loop
341 // First remove any matches
342 foreach(QContactDetail d, aDetails) {
343 foreach(QContactDetail d2, bDetails) {
344 if(d == d2) {
345 a.removeDetail(detail: &d);
346 b.removeDetail(detail: &d2);
347 break;
348 }
349 }
350 }
351
352 // Now dump the extra details that were unmatched in A (note that Type is always present).
353 // We ignore timestamp since it can get autogenerated too
354 aDetails = a.details();
355 bDetails = b.details();
356 foreach(QContactDetail d, aDetails) {
357 if (d.type() != QContactType::Type && d.type() != QContactTimestamp::Type)
358 qDebug() << "A contact had extra detail:" << d.type() << d.values();
359 }
360 // and same for B
361 foreach(QContactDetail d, bDetails) {
362 if (d.type() != QContactType::Type && d.type() != QContactTimestamp::Type)
363 qDebug() << "B contact had extra detail:" << d.type() << d.values();
364 }
365
366 if (a.type() != b.type()) {
367 qDebug() << "A contact type =" << a.type();
368 qDebug() << "B contact type =" << b.type();
369 }
370}
371
372bool tst_QContactManager::isSuperset(const QContact& ca, const QContact& cb)
373{
374 // returns true if contact ca is a superset of contact cb
375 // we use this test instead of equality because dynamic information
376 // such as presence/location, and synthesized information such as (possibly) type,
377 // may differ between a contact in memory and the contact in the managed store.
378
379 QContact a(ca);
380 QContact b(cb);
381 QList<QContactDetail> aDetails = a.details();
382 QList<QContactDetail> bDetails = b.details();
383
384 // They can be in any order, so loop
385 // First remove any matches
386 foreach(QContactDetail d, aDetails) {
387 foreach(QContactDetail d2, bDetails) {
388 if(d == d2) {
389 a.removeDetail(detail: &d);
390 b.removeDetail(detail: &d2);
391 break;
392 }
393 }
394 }
395
396 // Second remove any superset matches (eg, backend adds a field)
397 aDetails = a.details();
398 bDetails = b.details();
399 foreach (QContactDetail d, aDetails) {
400 foreach (QContactDetail d2, bDetails) {
401 if (d.type() == d2.type()) {
402 bool canRemove = true;
403 QMap<int, QVariant> d2map = d2.values();
404 foreach (int key, d2map.keys()) {
405 if (d.value(field: key) != d2.value(field: key)) {
406 // d can have _more_ keys than d2,
407 // but not _less_; and it cannot
408 // change the value.
409 canRemove = false;
410 }
411 }
412
413 if (canRemove) {
414 // if we get to here, we can remove the details.
415 a.removeDetail(detail: &d);
416 b.removeDetail(detail: &d2);
417 break;
418 }
419 }
420 }
421 }
422
423 QList<QContactType::TypeValues> validTypes;
424 validTypes << QContactType::TypeContact << QContactType::TypeGroup;
425 // check for contact type updates
426 if (validTypes.contains(t: a.type()))
427 if (validTypes.contains(t: b.type()))
428 if (a.type() != b.type())
429 return false; // nonempty type is different.
430
431 // Now check to see if b has any details remaining; if so, a is not a superset.
432 // Note Type can never be removed.
433 if (b.details().size() > 1
434 || (b.details().size() == 1 && (b.details().value(i: 0).type() != QContactType::Type)))
435 return false;
436 return true;
437}
438
439void tst_QContactManager::dumpContact(const QContact& contact)
440{
441 QContactManager m;
442 qDebug() << "Contact: " << contact.id();
443 QList<QContactDetail> details = contact.details();
444 foreach(QContactDetail d, details) {
445 qDebug() << " " << d.type() << ":";
446 qDebug() << " Vals:" << d.values();
447 }
448}
449
450void tst_QContactManager::dumpContacts(QContactManager *cm)
451{
452 QList<QContactId> ids = cm->contactIds();
453
454 qDebug() << "There are" << ids.count() << "contacts in" << cm->managerUri();
455
456 foreach (QContactId id, ids) {
457 QContact c = cm->contact(contactId: id);
458 dumpContact(contact: c);
459 }
460}
461
462void tst_QContactManager::uriParsing_data()
463{
464 QTest::addColumn<QString>(name: "uri");
465 QTest::addColumn<bool>(name: "good"); // is this a good uri or not
466 QTest::addColumn<QString>(name: "manager");
467 QTest::addColumn<QMap<QString, QString> >(name: "parameters");
468
469 QMap<QString, QString> inparameters;
470 inparameters.insert(key: "foo", value: "bar");
471 inparameters.insert(key: "bazflag", value: QString());
472 inparameters.insert(key: "bar", value: "glob");
473
474 QMap<QString, QString> inparameters2;
475 inparameters2.insert(key: "this has spaces", value: QString());
476 inparameters2.insert(key: "and& an", value: " &amp;");
477 inparameters2.insert(key: "and an ", value: "=quals");
478
479 QTest::newRow(dataTag: "built") << QContactManager::buildUri(managerName: "manager", params: inparameters) << true << "manager" << inparameters;
480 QTest::newRow(dataTag: "built with escaped parameters") << QContactManager::buildUri(managerName: "manager", params: inparameters2) << true << "manager" << inparameters2;
481 QTest::newRow(dataTag: "no scheme") << "this should not split" << false << QString() << tst_QContactManager_QStringMap();
482 QTest::newRow(dataTag: "wrong scheme") << "invalidscheme:foo bar" << false << QString() << tst_QContactManager_QStringMap();
483 QTest::newRow(dataTag: "right scheme, no colon") << "qtcontacts" << false << QString() << tst_QContactManager_QStringMap();
484 QTest::newRow(dataTag: "no manager, colon, no params") << "qtcontacts::" << false << "manager" << tst_QContactManager_QStringMap();
485 QTest::newRow(dataTag: "yes manager, no colon, no params") << "qtcontacts:manager" << true << "manager" << tst_QContactManager_QStringMap();
486 QTest::newRow(dataTag: "yes manager, yes colon, no params") << "qtcontacts:manager:" << true << "manager"<< tst_QContactManager_QStringMap();
487 QTest::newRow(dataTag: "yes params") << "qtcontacts:manager:foo=bar&bazflag=&bar=glob" << true << "manager" << inparameters;
488 QTest::newRow(dataTag: "yes params but misformed") << "qtcontacts:manager:foo=bar&=gloo&bar=glob" << false << "manager" << inparameters;
489 QTest::newRow(dataTag: "yes params but misformed 2") << "qtcontacts:manager:=&=gloo&bar=glob" << false << "manager" << inparameters;
490 QTest::newRow(dataTag: "yes params but misformed 3") << "qtcontacts:manager:==" << false << "manager" << inparameters;
491 QTest::newRow(dataTag: "yes params but misformed 4") << "qtcontacts:manager:&&" << false << "manager" << inparameters;
492 QTest::newRow(dataTag: "yes params but misformed 5") << "qtcontacts:manager:&goo=bar" << false << "manager" << inparameters;
493 QTest::newRow(dataTag: "yes params but misformed 6") << "qtcontacts:manager:goo&bar" << false << "manager" << inparameters;
494 QTest::newRow(dataTag: "yes params but misformed 7") << "qtcontacts:manager:goo&bar&gob" << false << "manager" << inparameters;
495 QTest::newRow(dataTag: "yes params but misformed 8") << "qtcontacts:manager:==&&==&goo=bar" << false << "manager" << inparameters;
496 QTest::newRow(dataTag: "yes params but misformed 9") << "qtcontacts:manager:foo=bar=baz" << false << "manager" << inparameters;
497 QTest::newRow(dataTag: "yes params but misformed 10") << "qtcontacts:manager:foo=bar=baz=glob" << false << "manager" << inparameters;
498 QTest::newRow(dataTag: "no manager but yes params") << "qtcontacts::foo=bar&bazflag=&bar=glob" << false << QString() << inparameters;
499 QTest::newRow(dataTag: "no manager or params") << "qtcontacts::" << false << QString() << inparameters;
500 QTest::newRow(dataTag: "no manager or params or colon") << "qtcontacts:" << false << QString() << inparameters;
501}
502
503void tst_QContactManager::addManagers()
504{
505 QTest::addColumn<QString>(name: "uri");
506
507 QStringList managers = QContactManager::availableManagers();
508
509 /* Known one that will not pass */
510 managers.removeAll(t: "invalid");
511 managers.removeAll(t: "testdummy");
512 managers.removeAll(t: "teststaticdummy");
513 managers.removeAll(t: "maliciousplugin");
514 managers.removeAll(t: "testlazy");
515
516 // "internal" engines
517 managers.removeAll(t: "social");
518 managers.removeAll(t: "simcard");
519 managers.removeAll(t: "com.nokia.messaging.contacts.engines.mail.contactslookup");
520
521
522 foreach(QString mgr, managers) {
523 QMap<QString, QString> params;
524 QTest::newRow(dataTag: QString("mgr='%1'").arg(a: mgr).toLatin1().constData()) << QContactManager::buildUri(managerName: mgr, params);
525 if (mgr == "memory") {
526 params.insert(key: "id", value: "tst_QContactManager");
527 QTest::newRow(dataTag: QString("mgr='%1', params").arg(a: mgr).toLatin1().constData()) << QContactManager::buildUri(managerName: mgr, params);
528 }
529 }
530}
531
532/*
533 * Helper method for creating a QContact instance with name and phone number
534 * details.
535 */
536QContact tst_QContactManager::createContact(
537 QString firstName,
538 QString lastName,
539 QString phoneNumber)
540{
541 QContact contact;
542 QContactName n;
543
544 if (!firstName.isEmpty()) {
545 n.setFirstName(firstName);
546 };
547 if (!lastName.isEmpty()) {
548 n.setLastName(lastName);
549 }
550 if (!n.isEmpty()) {
551 contact.saveDetail(detail: &n);
552 }
553
554 if (!phoneNumber.isEmpty()) {
555 QContactPhoneNumber ph;
556 ph.setNumber(phoneNumber);
557 contact.saveDetail(detail: &ph);
558 }
559
560 return contact;
561}
562
563void tst_QContactManager::saveContactName(QContact *contact, QContactName *contactName, const QString &name) const
564{
565 contactName->setFirstName(name);
566 contactName->setLastName(name);
567 contact->saveDetail(detail: contactName);
568}
569
570void tst_QContactManager::metadata()
571{
572 // ensure that the backend is publishing its metadata (name / parameters / uri) correctly
573 QFETCH(QString, uri);
574 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
575 QVERIFY(QContactManager::buildUri(cm->managerName(), cm->managerParameters()) == cm->managerUri());
576}
577
578
579void tst_QContactManager::nullIdOperations()
580{
581 QFETCH(QString, uri);
582 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
583 QVERIFY(!cm->removeContact(QContactId()));
584 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
585
586
587 QContact c = cm->contact(contactId: QContactId());
588 QVERIFY(c.id() == QContactId());
589 QVERIFY(c.isEmpty());
590 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
591}
592
593void tst_QContactManager::uriParsing()
594{
595 QFETCH(QString, uri);
596 QFETCH(bool, good);
597 QFETCH(QString, manager);
598 QFETCH(tst_QContactManager_QStringMap, parameters);
599
600 QString outmanager;
601 QMap<QString, QString> outparameters;
602
603 if (good) {
604 /* Good split */
605 /* Test splitting */
606 QVERIFY(QContactManager::parseUri(uri, 0, 0)); // no out parms
607
608 // 1 out param
609 QVERIFY(QContactManager::parseUri(uri, &outmanager, 0));
610 QCOMPARE(manager, outmanager);
611 QVERIFY(QContactManager::parseUri(uri, 0, &outparameters));
612
613 QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
614
615 QCOMPARE(parameters, outparameters);
616
617 outmanager.clear();
618 outparameters.clear();
619 QVERIFY(QContactManager::parseUri(uri, &outmanager, &outparameters));
620
621 QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
622
623 QCOMPARE(manager, outmanager);
624 QCOMPARE(parameters, outparameters);
625 } else {
626 /* bad splitting */
627 outmanager.clear();
628 outparameters.clear();
629 QVERIFY(QContactManager::parseUri(uri, 0, 0) == false);
630 QVERIFY(QContactManager::parseUri(uri, &outmanager, 0) == false);
631 QVERIFY(outmanager.isEmpty());
632 QVERIFY(QContactManager::parseUri(uri, 0, &outparameters) == false);
633 QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
634 QVERIFY(outparameters.isEmpty());
635
636 /* make sure the in parameters don't change with a bad split */
637 outmanager = manager;
638 outparameters = parameters;
639 QVERIFY(QContactManager::parseUri(uri, &outmanager, 0) == false);
640 QCOMPARE(manager, outmanager);
641 QVERIFY(QContactManager::parseUri(uri, 0, &outparameters) == false);
642 QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
643 QCOMPARE(parameters, outparameters);
644 }
645}
646
647void tst_QContactManager::ctors()
648{
649 /* test the different ctors to make sure we end up with the same uri */
650 QVERIFY(QContactManager::availableManagers().count() >= 1); // invalid + something else
651 QVERIFY(QContactManager::availableManagers().contains("invalid"));
652 QString defaultStore = QContactManager::availableManagers().value(i: 0);
653
654 qDebug() << "Available managers:" << QContactManager::availableManagers();
655
656 QMap<QString, QString> randomParameters;
657 randomParameters.insert(key: "something", value: "old");
658 randomParameters.insert(key: "something...", value: "new");
659 randomParameters.insert(key: "something ", value: "borrowed");
660 randomParameters.insert(key: " something", value: "blue");
661
662 QObject parent;
663
664 QContactManager cm; // default
665 QContactManager cm2(defaultStore);
666 QContactManager cm3(defaultStore, QMap<QString, QString>());
667
668 QContactManager cm9b(0); // QObject* ctor, should be same as cm2 etc
669 QContactManager cm9c(&parent); // same as cm2 etc.
670
671 QScopedPointer<QContactManager> cm5(QContactManager::fromUri(uri: QContactManager::buildUri(managerName: defaultStore, params: QMap<QString, QString>())));
672 QScopedPointer<QContactManager> cm6(QContactManager::fromUri(uri: cm.managerUri())); // uri is not a name; should fail.
673 QScopedPointer<QContactManager> cm9(QContactManager::fromUri(uri: QString(), parent: &parent));
674
675 QVERIFY(cm9->parent() == &parent);
676 QVERIFY(cm9b.parent() == 0);
677 QVERIFY(cm9c.parent() == &parent);
678
679
680 /* OLD TEST WAS THIS: */
681 //QCOMPARE(cm.managerUri(), cm2.managerUri());
682 //QCOMPARE(cm.managerUri(), cm3.managerUri());
683 //QCOMPARE(cm.managerUri(), cm5->managerUri());
684 //QCOMPARE(cm.managerUri(), cm6->managerUri());
685 //QCOMPARE(cm.managerUri(), cm9->managerUri());
686 /* NEW TEST IS THIS: Test that the names of the managers are the same */
687 QCOMPARE(cm.managerName(), cm2.managerName());
688 QCOMPARE(cm.managerName(), cm3.managerName());
689 QCOMPARE(cm.managerName(), cm5->managerName());
690 QCOMPARE(cm.managerName(), cm6->managerName());
691 QCOMPARE(cm.managerName(), cm9->managerName());
692 QCOMPARE(cm.managerName(), cm9b.managerName());
693 QCOMPARE(cm.managerName(), cm9c.managerName());
694
695 /* Test that we get invalid stores when we do silly things */
696 QContactManager em("non existent");
697 QContactManager em2("non existent", QMap<QString, QString>());
698 QContactManager em3("memory", randomParameters);
699
700 /* Also invalid, since we don't have one of these anyway */
701 QScopedPointer<QContactManager> em4(QContactManager::fromUri(uri: "invalid uri"));
702 QScopedPointer<QContactManager> em5(QContactManager::fromUri(uri: QContactManager::buildUri(managerName: "nonexistent", params: QMap<QString, QString>())));
703 QScopedPointer<QContactManager> em6(QContactManager::fromUri(uri: em3.managerUri()));
704
705
706 /*
707 * Sets of stores that should be equivalent:
708 * - 1, 2, 4, 5
709 * - 3, 6
710 */
711
712 /* First some URI testing for equivalent stores */
713 QVERIFY(em.managerUri() == em2.managerUri());
714 QVERIFY(em.managerUri() == em5->managerUri());
715 QVERIFY(em.managerUri() == em4->managerUri());
716 QVERIFY(em2.managerUri() == em4->managerUri());
717 QVERIFY(em2.managerUri() == em5->managerUri());
718 QVERIFY(em4->managerUri() == em5->managerUri());
719
720 QVERIFY(em3.managerUri() == em6->managerUri());
721
722 /* Test the stores that should not be the same */
723 QVERIFY(em.managerUri() != em3.managerUri());
724 QVERIFY(em.managerUri() != em6->managerUri());
725
726 /* now the components */
727 QCOMPARE(em.managerName(), QString("invalid"));
728 QCOMPARE(em2.managerName(), QString("invalid"));
729 QCOMPARE(em3.managerName(), QString("memory"));
730 QCOMPARE(em4->managerName(), QString("invalid"));
731 QCOMPARE(em5->managerName(), QString("invalid"));
732 QCOMPARE(em6->managerName(), QString("memory"));
733 QCOMPARE(em.managerParameters(), tst_QContactManager_QStringMap());
734 QCOMPARE(em2.managerParameters(), tst_QContactManager_QStringMap());
735 QCOMPARE(em4->managerParameters(), tst_QContactManager_QStringMap());
736 QCOMPARE(em5->managerParameters(), tst_QContactManager_QStringMap());
737 QCOMPARE(em3.managerParameters(), em6->managerParameters()); // memory engine discards the given params, replaces with id.
738
739 // Finally test the platform specific engines are actually the defaults
740 QCOMPARE(defaultStore, QString("invalid"));
741}
742
743void tst_QContactManager::doDump()
744{
745 // Only do this if it has been explicitly selected
746 if (QCoreApplication::arguments().contains(str: "doDump")) {
747 QFETCH(QString, uri);
748 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
749
750 dumpContacts(cm: cm.data());
751 }
752}
753
754Q_DECLARE_METATYPE(QVariant)
755
756
757void tst_QContactManager::add()
758{
759 QFETCH(QString, uri);
760 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
761
762 QContact alice = createContact(firstName: "Alice", lastName: "inWonderland", phoneNumber: "1234567");
763 int currCount = cm->contactIds().count();
764 QVERIFY(cm->saveContact(&alice));
765 QVERIFY(cm->error() == QContactManager::NoError);
766
767 QVERIFY(!alice.id().managerUri().isEmpty());
768 QVERIFY(!(alice.id().isNull()));
769 QCOMPARE(cm->contactIds().count(), currCount+1);
770
771 QContact added = cm->contact(contactId: alice.id());
772 QVERIFY(added.id() == alice.id());
773
774 if (!isSuperset(ca: added, cb: alice)) {
775 dumpContacts(cm: cm.data());
776 dumpContactDifferences(ca: added, cb: alice);
777 QCOMPARE(added, alice);
778 }
779
780 // now a contact with many details of a particular definition
781 // if the detail is not unique it should then support minimum of two of the same kind
782 const int nrOfdetails = 2;
783 QContact veryContactable = createContact(firstName: "Very", lastName: "Contactable", phoneNumber: "");
784 for (int i = 0; i < nrOfdetails; i++) {
785 QString phnStr = QString::number(i);
786 QContactPhoneNumber vcphn;
787 vcphn.setNumber(phnStr);
788 QVERIFY(veryContactable.saveDetail(&vcphn));
789 }
790
791 // check that all the numbers were added successfully
792 QVERIFY(veryContactable.details(QContactPhoneNumber::Type).size() == nrOfdetails);
793
794 // check if it can be saved
795 QVERIFY(cm->saveContact(&veryContactable));
796
797 // verify save
798 QContact retrievedContactable = cm->contact(contactId: veryContactable.id());
799 if (!isSuperset(ca: retrievedContactable, cb: veryContactable)) {
800 dumpContactDifferences(ca: veryContactable, cb: retrievedContactable);
801 QCOMPARE(veryContactable, retrievedContactable);
802 }
803}
804
805void tst_QContactManager::testInterSectionOfIdAndDetailFilters()
806{
807 QFETCH(QString, uri);
808 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
809
810 //prepare filter data
811 QContact alice = createContact(firstName: "Alice", lastName: "inWonderland", phoneNumber: "1234567");
812 QVERIFY(cm->saveContact(&alice));
813
814 QContact john = createContact(firstName: "John", lastName: "inFinland", phoneNumber: "2345678");
815 QVERIFY(cm->saveContact(&john));
816
817 QContactIdFilter idFilter1;
818 QList<QContactId> contactIdList;
819 contactIdList.append(t: alice.id());
820 idFilter1.setIds(contactIdList);
821
822 QContactDetailFilter df;
823 df.setDetailType(type: QContactName::Type,field: QContactName::FieldFirstName);
824 df.setValue("Alice");
825
826 contactIdList.clear();
827
828 QContactIntersectionFilter isf;
829 isf.append(filter: idFilter1);
830 isf.append(filter: df);
831
832 //Intersection filter of a matching Idfilter and detailfilter
833 QList<QContact> contactList = cm->contacts(filter: isf);
834 QCOMPARE(contactList.size(), 1);
835
836 contactIdList.clear();
837
838 //Intersection filter of a non matching Idfilter and detailfilter
839 isf.remove(filter: df);
840 df.setValue("John");
841 isf.append(filter: df);
842
843 contactList = cm->contacts(filter: isf);
844 QCOMPARE(contactList.size(), 0);
845}
846
847void tst_QContactManager::testInterSectionOfIdFilters()
848{
849 QFETCH(QString, uri);
850 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
851
852 //prepare filter data
853 QContact alice = createContact(firstName: "Alice", lastName: "inWonderland", phoneNumber: "1234567");
854 QVERIFY(cm->saveContact(&alice));
855
856 QContact john = createContact(firstName: "John", lastName: "inFinland", phoneNumber: "2345678");
857 QVERIFY(cm->saveContact(&john));
858
859 QContactIdFilter idFilter1;
860 QList<QContactId> contactIdList;
861 contactIdList.append(t: alice.id());
862 idFilter1.setIds(contactIdList);
863
864 QContactIdFilter idFilter2;
865 contactIdList.clear();
866 contactIdList.append(t: john.id());
867 idFilter2.setIds(contactIdList);
868
869 contactIdList.clear();
870
871 //Test intersection filter with two different idFilters
872 QContactIntersectionFilter isf;
873 isf.append(filter: idFilter1);
874 isf.append(filter: idFilter2);
875
876 QList<QContact> contactList = cm->contacts(filter: idFilter1);
877 QCOMPARE(contactList.size(), 1);
878 QCOMPARE(contactList.at(0).id(), alice.id());
879
880 contactIdList.clear();
881
882 //When we intersect with two idFilters each having different
883 //contact Ids the result should be zero
884 contactList = cm->contacts(filter: isf);
885 QCOMPARE(contactList.size(), 0);
886
887
888 //Test intersection filter with two idFilters
889 //each having same contactid as other the result should be 1
890 isf.remove(filter: idFilter2);
891 contactIdList.append(t: alice.id());
892 idFilter2.setIds(contactIdList);
893
894 contactIdList.clear();
895
896 isf.append(filter: idFilter2);
897 contactList = cm->contacts(filter: isf);
898 QCOMPARE(contactList.size(), 1);
899
900 contactIdList.clear();
901
902 // Test intersection filter with two idFilters
903 // idFilter1 has alice's contactId
904 // And idfilter2 has alice's and John's contactId
905 // The result should be one and its alice
906
907 contactIdList << alice.id() << john.id();
908 idFilter2.setIds(contactIdList);
909 isf.append(filter: idFilter2);
910
911 contactIdList.clear();
912
913 contactList = cm->contacts(filter: isf);
914 QCOMPARE(contactList.size(), 1);
915 QCOMPARE(contactList.at(0).id(), alice.id());
916
917 //clean up filters and the contactIdList
918 isf.remove(filter: idFilter2);
919 isf.remove(filter: idFilter1);
920 contactIdList.clear();
921
922 //Test with null contactId filter: idFilter1 has one contact and idFilter2 has null id
923 //idFilters with null id should not return any thing so result should be zero
924 contactIdList.append(t: alice.id());
925 idFilter1.setIds(contactIdList);
926 contactIdList.clear();
927 contactIdList.append(t: QContactId());
928 idFilter2.setIds(contactIdList);
929 isf.append(filter: idFilter1);
930 isf.append(filter: idFilter2);
931 QCOMPARE(isf.filters().size(), 2);
932 contactList = cm->contacts(filter: isf);
933 QCOMPARE(contactList.size(), 0);
934
935 //clean up filters and the contactIdList
936 isf.remove(filter: idFilter2);
937 isf.remove(filter: idFilter1);
938 contactIdList.clear();
939
940 //Three filters: intersection of two IdFilters each having the same contact id
941 //as the other with an IdFilter having one different contactId the result should be zero
942 contactIdList.append(t: alice.id());
943 idFilter1.setIds(contactIdList);
944 contactIdList.clear();
945
946 contactIdList.append(t: john.id());
947 idFilter2.setIds(contactIdList);
948 contactIdList.clear();
949
950 QContactIdFilter idFilter3;
951 contactIdList.append(t: john.id());
952 idFilter3.setIds(contactIdList);
953 contactIdList.clear();
954
955 isf.append(filter: idFilter1);
956 isf.append(filter: idFilter2);
957 isf.append(filter: idFilter3);
958
959 QCOMPARE(isf.filters().size(), 3);
960 contactList = cm->contacts(filter: isf);
961 QCOMPARE(contactList.size(), 0);
962
963 //clean up filters and the contactIdList
964 isf.remove(filter: idFilter1);
965 isf.remove(filter: idFilter2);
966 isf.remove(filter: idFilter3);
967 contactIdList.clear();
968}
969
970void tst_QContactManager::update()
971{
972 QFETCH(QString, uri);
973 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
974
975 /* Save a new contact first */
976 int contactCount = cm->contacts().size();
977 QContact alice = createContact(firstName: "Alice", lastName: "inWonderland", phoneNumber: "1234567");
978 QVERIFY(cm->saveContact(&alice));
979 QVERIFY(cm->error() == QContactManager::NoError);
980 contactCount += 1; // added a new contact.
981 QCOMPARE(cm->contacts().size(), contactCount);
982
983 /* Update name */
984 QContactName name = alice.detail(type: QContactName::Type);
985 saveContactName(contact: &alice, contactName: &name, name: "updated");
986 QVERIFY(cm->saveContact(&alice));
987 QVERIFY(cm->error() == QContactManager::NoError);
988 saveContactName(contact: &alice, contactName: &name, name: "updated2");
989 QVERIFY(cm->saveContact(&alice));
990 QVERIFY(cm->error() == QContactManager::NoError);
991 alice = cm->contact(contactId: alice.id()); // force reload of (persisted) alice
992 QContact updated = cm->contact(contactId: alice.id());
993 QContactName updatedName = updated.detail(type: QContactName::Type);
994 updatedName.setFirstName("updated2"); // Necessary to ensure that updatedName and name are actually the same
995 QCOMPARE(updatedName, name);
996 QCOMPARE(cm->contacts().size(), contactCount); // contact count should be the same, no new contacts
997
998 /* Test that adding a new detail doesn't cause unwanted side effects */
999 int detailCount = alice.details().size();
1000 QContactEmailAddress email;
1001 email.setEmailAddress("test@example.com");
1002 alice.saveDetail(detail: &email);
1003 QVERIFY(cm->saveContact(&alice));
1004 QCOMPARE(cm->contacts().size(), contactCount); // contact count shoudl be the same, no new contacts
1005
1006 // This test is dangerous, since backends can add timestamps etc...
1007 detailCount += 1;
1008 QCOMPARE(detailCount, alice.details().size()); // adding a detail should cause the detail count to increase by one.
1009 /* Test that removal of fields in a detail works */
1010 QContactPhoneNumber phn = alice.detail<QContactPhoneNumber>();
1011 phn.setNumber("1234567");
1012 phn.setContexts(QContactDetail::ContextHome);
1013 alice.saveDetail(detail: &phn);
1014 QVERIFY(cm->saveContact(&alice));
1015 alice = cm->contact(contactId: alice.id()); // force reload of (persisted) alice
1016 QVERIFY(alice.detail<QContactPhoneNumber>().contexts().contains(QContactDetail::ContextHome)); // check context saved.
1017 phn = alice.detail<QContactPhoneNumber>(); // reload the detail, since it's key could have changed
1018 phn.setContexts(QList<int> ()); // remove context field.
1019 alice.saveDetail(detail: &phn);
1020 QVERIFY(cm->saveContact(&alice));
1021 alice = cm->contact(contactId: alice.id()); // force reload of (persisted) alice
1022 QVERIFY(alice.detail<QContactPhoneNumber>().contexts().isEmpty()); // check context removed.
1023 QCOMPARE(cm->contacts().size(), contactCount); // removal of a field of a detail shouldn't affect the contact count
1024
1025 // This test is dangerous, since backends can add timestamps etc...
1026 QCOMPARE(detailCount, alice.details().size()); // removing a field from a detail should affect the detail count
1027
1028 /* Test that removal of details works */
1029 phn = alice.detail<QContactPhoneNumber>(); // reload the detail, since it's key could have changed
1030 alice.removeDetail(detail: &phn);
1031 QVERIFY(cm->saveContact(&alice));
1032 alice = cm->contact(contactId: alice.id()); // force reload of (persisted) alice
1033 QVERIFY(alice.details<QContactPhoneNumber>().isEmpty()); // no such detail.
1034 QCOMPARE(cm->contacts().size(), contactCount); // removal of a detail shouldn't affect the contact count
1035
1036 // This test is dangerous, since backends can add timestamps etc...
1037 //detailCount -= 1;
1038 //QCOMPARE(detailCount, alice.details().size()); // removing a detail should cause the detail count to decrease by one.
1039
1040 if (cm->supportedContactTypes().contains(t: QContactType::TypeGroup)) {
1041 // Try changing types - not allowed
1042 // from contact -> group
1043 alice.setType(QContactType::TypeGroup);
1044 QContactName na = alice.detail(type: QContactName::Type);
1045 alice.removeDetail(detail: &na);
1046 QVERIFY(!cm->saveContact(&alice));
1047 QVERIFY(cm->error() == QContactManager::AlreadyExistsError);
1048
1049 // from group -> contact
1050 QContact jabberwock = createContact(firstName: "", lastName: "", phoneNumber: "1234567890");
1051 jabberwock.setType(QContactType::TypeGroup);
1052 QVERIFY(cm->saveContact(&jabberwock));
1053 jabberwock.setType(QContactType::TypeContact);
1054 QVERIFY(!cm->saveContact(&jabberwock));
1055 QVERIFY(cm->error() == QContactManager::AlreadyExistsError);
1056 }
1057}
1058
1059void tst_QContactManager::remove()
1060{
1061 QFETCH(QString, uri);
1062 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
1063
1064 /* Save a new contact first */
1065 QContact alice = createContact(firstName: "Alice", lastName: "inWonderland", phoneNumber: "1234567");
1066 QVERIFY(cm->saveContact(&alice));
1067 QVERIFY(cm->error() == QContactManager::NoError);
1068 QVERIFY(alice.id() != QContactId());
1069
1070 /* Remove the created contact */
1071 const int contactCount = cm->contactIds().count();
1072 QVERIFY(cm->removeContact(alice.id()));
1073 QCOMPARE(cm->contactIds().count(), contactCount - 1);
1074 QVERIFY(cm->contact(alice.id()).isEmpty());
1075 QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
1076}
1077
1078void tst_QContactManager::addAndUpdate()
1079{
1080 QFETCH(QString, uri);
1081 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
1082 int originalCount = cm->contactIds().size();
1083 // save a few new contacts
1084 QList<QContact> saveList;
1085 QContactName nameDetail;
1086 for (int i=0; i<20; i++) {
1087 QContact testContact;
1088 nameDetail.setFirstName(QStringLiteral("Test Contact ") + QString::number(i));
1089 testContact.saveDetail(detail: &nameDetail);
1090 saveList << testContact;
1091 }
1092 QMap<int, QContactManager::Error> errorMap;
1093 cm->saveContacts(contacts: &saveList, errorMap: &errorMap);
1094 QCOMPARE(cm->contactIds().size(), originalCount + saveList.size());
1095 QCOMPARE(errorMap.size(), 0);
1096 // update previously saved contacts
1097 for (int i=0; i<saveList.size(); i++) {
1098 QContactPhoneNumber phn;
1099 phn.setNumber(QString::number(i));
1100 saveList[i].saveDetail(detail: &phn);
1101 }
1102 // add new contacts in front of the saveList list
1103 for (int i=20; i<40; i++) {
1104 QContact testContact;
1105 QContactName nameDetail;
1106 nameDetail.setFirstName(QStringLiteral("Test Contact ") + QString::number(i));
1107 testContact.saveDetail(detail: &nameDetail);
1108 saveList.insert(i: 0, t: testContact);
1109 }
1110 cm->saveContacts(contacts: &saveList, errorMap: &errorMap);
1111 QCOMPARE(cm->contactIds().size(), originalCount + saveList.size());
1112 QCOMPARE(errorMap.size(), 0);
1113 foreach (const QContact contact, saveList) {
1114 QVERIFY(cm->removeContact(contact.id()));
1115 }
1116}
1117
1118void tst_QContactManager::batch()
1119{
1120 QFETCH(QString, uri);
1121 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
1122
1123 /* First test null pointer operations */
1124 QVERIFY(!cm->saveContacts(NULL, NULL));
1125 QVERIFY(cm->error() == QContactManager::BadArgumentError);
1126
1127 QVERIFY(!cm->removeContacts(QList<QContactId>(), NULL));
1128 QVERIFY(cm->error() == QContactManager::BadArgumentError);
1129
1130 // Get supported name field
1131 int nameField = QContactName::FieldFirstName;
1132
1133 /* Now add 3 contacts, all valid */
1134 QContact a;
1135 QContactName na;
1136 na.setValue(field: nameField, value: "XXXXXX Albert");
1137 a.saveDetail(detail: &na);
1138
1139 QContact b;
1140 QContactName nb;
1141 nb.setValue(field: nameField, value: "XXXXXX Bob");
1142 b.saveDetail(detail: &nb);
1143
1144 QContact c;
1145 QContactName nc;
1146 nc.setValue(field: nameField, value: "XXXXXX Carol");
1147 c.saveDetail(detail: &nc);
1148
1149 QList<QContact> contacts;
1150 contacts << a << b << c;
1151
1152 QMap<int, QContactManager::Error> errorMap;
1153 // Add one dummy error to test if the errors are reset
1154 errorMap.insert(key: 0, value: QContactManager::NoError);
1155 QVERIFY(cm->saveContacts(&contacts, &errorMap));
1156 QVERIFY(cm->error() == QContactManager::NoError);
1157 QVERIFY(errorMap.count() == 0);
1158
1159 /* Make sure our contacts got updated too */
1160 QVERIFY(contacts.count() == 3);
1161 QVERIFY(contacts.at(0).id() != QContactId());
1162 QVERIFY(contacts.at(1).id() != QContactId());
1163 QVERIFY(contacts.at(2).id() != QContactId());
1164
1165 QVERIFY(contacts.at(0).detail(QContactName::Type) == na);
1166 QVERIFY(contacts.at(1).detail(QContactName::Type) == nb);
1167 QVERIFY(contacts.at(2).detail(QContactName::Type) == nc);
1168
1169 /* Retrieve again */
1170 a = cm->contact(contactId: contacts.at(i: 0).id());
1171 b = cm->contact(contactId: contacts.at(i: 1).id());
1172 c = cm->contact(contactId: contacts.at(i: 2).id());
1173 QVERIFY(contacts.at(0).detail(QContactName::Type) == na);
1174 QVERIFY(contacts.at(1).detail(QContactName::Type) == nb);
1175 QVERIFY(contacts.at(2).detail(QContactName::Type) == nc);
1176
1177 /* Save again, with a null error map */
1178 QVERIFY(cm->saveContacts(&contacts, NULL));
1179 QVERIFY(cm->error() == QContactManager::NoError);
1180
1181 /* Now make an update to them all */
1182 QContactPhoneNumber number;
1183 number.setNumber("1234567");
1184
1185 QVERIFY(contacts[0].saveDetail(&number));
1186 number.setNumber("234567");
1187 QVERIFY(contacts[1].saveDetail(&number));
1188 number.setNumber("34567");
1189 QVERIFY(contacts[2].saveDetail(&number));
1190
1191 QVERIFY(cm->saveContacts(&contacts, &errorMap));
1192 QVERIFY(cm->error() == QContactManager::NoError);
1193 QVERIFY(errorMap.count() == 0);
1194
1195 /* Retrieve them and check them again */
1196 a = cm->contact(contactId: contacts.at(i: 0).id());
1197 b = cm->contact(contactId: contacts.at(i: 1).id());
1198 c = cm->contact(contactId: contacts.at(i: 2).id());
1199 QVERIFY(contacts.at(0).detail(QContactName::Type) == na);
1200 QVERIFY(contacts.at(1).detail(QContactName::Type) == nb);
1201 QVERIFY(contacts.at(2).detail(QContactName::Type) == nc);
1202
1203 QVERIFY(a.details<QContactPhoneNumber>().count() == 1);
1204 QVERIFY(b.details<QContactPhoneNumber>().count() == 1);
1205 QVERIFY(c.details<QContactPhoneNumber>().count() == 1);
1206
1207 QVERIFY(a.details<QContactPhoneNumber>().at(0).number() == "1234567");
1208 QVERIFY(b.details<QContactPhoneNumber>().at(0).number() == "234567");
1209 QVERIFY(c.details<QContactPhoneNumber>().at(0).number() == "34567");
1210
1211 /* Retrieve them with the batch ID fetch API */
1212 QList<QContactId> batchIds;
1213 batchIds << a.id() << b.id() << c.id();
1214
1215 // Null error map first (doesn't crash)
1216 QList<QContact> batchFetch = cm->contacts(contactIds: batchIds, fetchHint: QContactFetchHint(), errorMap: 0);
1217 QVERIFY(cm->error() == QContactManager::NoError);
1218 QVERIFY(batchFetch.count() == 3);
1219 QVERIFY(batchFetch.at(0).detail(QContactName::Type) == na);
1220 QVERIFY(batchFetch.at(1).detail(QContactName::Type) == nb);
1221 QVERIFY(batchFetch.at(2).detail(QContactName::Type) == nc);
1222
1223 // With error map
1224 batchFetch = cm->contacts(contactIds: batchIds, fetchHint: QContactFetchHint(), errorMap: &errorMap);
1225 QVERIFY(cm->error() == QContactManager::NoError);
1226 QVERIFY(errorMap.count() == 0);
1227 QVERIFY(batchFetch.count() == 3);
1228 QVERIFY(batchFetch.at(0).detail(QContactName::Type) == na);
1229 QVERIFY(batchFetch.at(1).detail(QContactName::Type) == nb);
1230 QVERIFY(batchFetch.at(2).detail(QContactName::Type) == nc);
1231
1232 /* Now an empty id */
1233 batchIds.clear();
1234 batchIds << QContactId() << a.id() << b.id() << c.id();
1235 batchFetch = cm->contacts(contactIds: batchIds, fetchHint: QContactFetchHint(), errorMap: 0);
1236 QVERIFY(cm->error() != QContactManager::NoError);
1237 QVERIFY(batchFetch.count() == 4);
1238 QVERIFY(batchFetch.at(0).detail(QContactName::Type) == QContactDetail());
1239 QVERIFY(batchFetch.at(1).detail(QContactName::Type) == na);
1240 QVERIFY(batchFetch.at(2).detail(QContactName::Type) == nb);
1241 QVERIFY(batchFetch.at(3).detail(QContactName::Type) == nc);
1242
1243 batchFetch = cm->contacts(contactIds: batchIds, fetchHint: QContactFetchHint(), errorMap: &errorMap);
1244 QVERIFY(cm->error() != QContactManager::NoError);
1245 QVERIFY(batchFetch.count() == 4);
1246 QVERIFY(errorMap.count() == 1);
1247 QVERIFY(errorMap[0] == QContactManager::DoesNotExistError);
1248 QVERIFY(batchFetch.at(0).detail(QContactName::Type) == QContactDetail());
1249 QVERIFY(batchFetch.at(1).detail(QContactName::Type) == na);
1250 QVERIFY(batchFetch.at(2).detail(QContactName::Type) == nb);
1251 QVERIFY(batchFetch.at(3).detail(QContactName::Type) == nc);
1252
1253 /* Now multiple of the same contact */
1254 batchIds.clear();
1255 batchIds << c.id() << b.id() << c.id() << a.id() << a.id();
1256 batchFetch = cm->contacts(contactIds: batchIds, fetchHint: QContactFetchHint(), errorMap: &errorMap);
1257 QVERIFY(cm->error() == QContactManager::NoError);
1258 QVERIFY(batchFetch.count() == 5);
1259 QVERIFY(errorMap.count() == 0);
1260 QVERIFY(batchFetch.at(0).detail(QContactName::Type) == nc);
1261 QVERIFY(batchFetch.at(1).detail(QContactName::Type) == nb);
1262 QVERIFY(batchFetch.at(2).detail(QContactName::Type) == nc);
1263 QVERIFY(batchFetch.at(3).detail(QContactName::Type) == na);
1264 QVERIFY(batchFetch.at(4).detail(QContactName::Type) == na);
1265
1266 /* Now delete them all */
1267 QList<QContactId> ids;
1268 ids << a.id() << b.id() << c.id();
1269 QVERIFY(cm->removeContacts(ids, &errorMap));
1270 QVERIFY(errorMap.count() == 0);
1271 QVERIFY(cm->error() == QContactManager::NoError);
1272
1273 /* Make sure the contacts really don't exist any more */
1274 QVERIFY(cm->contact(a.id()).id() == QContactId());
1275 QVERIFY(cm->contact(a.id()).isEmpty());
1276 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
1277 QVERIFY(cm->contact(b.id()).id() == QContactId());
1278 QVERIFY(cm->contact(b.id()).isEmpty());
1279 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
1280 QVERIFY(cm->contact(c.id()).id() == QContactId());
1281 QVERIFY(cm->contact(c.id()).isEmpty());
1282 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
1283
1284 /* Now try removing with all invalid ids (e.g. the ones we just removed) */
1285 ids.clear();
1286 ids << a.id() << b.id() << c.id();
1287 QVERIFY(!cm->removeContacts(ids, &errorMap));
1288 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
1289 QVERIFY(errorMap.count() == 3);
1290 QVERIFY(errorMap.values().at(0) == QContactManager::DoesNotExistError);
1291 QVERIFY(errorMap.values().at(1) == QContactManager::DoesNotExistError);
1292 QVERIFY(errorMap.values().at(2) == QContactManager::DoesNotExistError);
1293
1294 /* And again with a null error map */
1295 QVERIFY(!cm->removeContacts(ids, NULL));
1296 QVERIFY(cm->error() == QContactManager::DoesNotExistError);
1297
1298 /* Try adding some new ones again, this time one with an error */
1299 contacts.clear();
1300 a.setId(QContactId());
1301 b.setId(QContactId());
1302 c.setId(QContactId());
1303
1304 /* Make B the bad guy */
1305 QContactDetail bad(static_cast<QContactDetail::DetailType>(123456));//does not exist and will break if you add it
1306 bad.setValue(field: 12345, value: "Very bad");
1307 b.saveDetail(detail: &bad);
1308
1309 contacts << a << b << c;
1310
1311 /* Fix up B and re save it */
1312 QVERIFY(contacts[1].removeDetail(&bad));
1313 QVERIFY(cm->saveContacts(&contacts, &errorMap));
1314 QVERIFY(errorMap.count() == 0);
1315 QVERIFY(cm->error() == QContactManager::NoError);
1316
1317 // Save and remove a fourth contact. Store the id.
1318 a.setId(QContactId());
1319 QVERIFY(cm->saveContact(&a));
1320 QContactId removedId = a.id();
1321 QVERIFY(cm->removeContact(removedId));
1322
1323 /* Now delete 3 items, but with one bad argument */
1324 ids.clear();
1325 ids << contacts.at(i: 0).id();
1326 ids << removedId;
1327 ids << contacts.at(i: 2).id();
1328
1329 QVERIFY(!cm->removeContacts(ids, &errorMap));
1330 QVERIFY(cm->error() != QContactManager::NoError);
1331
1332 /* Again, the backend has the choice of either removing the successful ones, or not */
1333 QVERIFY(errorMap.count() > 0);
1334 QVERIFY(errorMap.count() <= 3);
1335
1336 // A might have gone through
1337 if (errorMap.keys().contains(t: 0)) {
1338 QVERIFY(errorMap.value(0) != QContactManager::NoError);
1339 QVERIFY(contacts.at(0).id() == QContactId());
1340 } else {
1341 QVERIFY(contacts.at(0).id() != QContactId());
1342 }
1343
1344 /* B should definitely have failed */
1345 QVERIFY(errorMap.value(1) == QContactManager::DoesNotExistError);
1346 QVERIFY(ids.at(1) == removedId);
1347
1348 // A might have gone through
1349 if (errorMap.keys().contains(t: 2)) {
1350 QVERIFY(errorMap.value(2) != QContactManager::NoError);
1351 QVERIFY(contacts.at(2).id() == QContactId());
1352 } else {
1353 QVERIFY(contacts.at(2).id() != QContactId());
1354 }
1355}
1356
1357void tst_QContactManager::invalidManager()
1358{
1359 /* Create an invalid manager */
1360 QContactManager manager("this should never work");
1361 QVERIFY(manager.managerName() == "invalid");
1362 QVERIFY(manager.managerVersion() == 0);
1363
1364 /* also, test the other ctor behaviour is sane also */
1365 QContactManager anotherManager("this should never work", 15);
1366 QVERIFY(anotherManager.managerName() == "invalid");
1367 QVERIFY(anotherManager.managerVersion() == 0);
1368
1369 /* Now test that all the operations fail */
1370 QVERIFY(manager.contactIds().count() == 0);
1371 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1372
1373 QContact foo;
1374 QContactName nf;
1375 nf.setLastName("Lastname");
1376 foo.saveDetail(detail: &nf);
1377
1378 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1379
1380 QVERIFY(manager.saveContact(&foo) == false);
1381 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1382 QVERIFY(foo.id() == QContactId());
1383 QVERIFY(manager.contactIds().count() == 0);
1384
1385 QVERIFY(manager.contact(foo.id()).id() == QContactId());
1386 QVERIFY(manager.contact(foo.id()).isEmpty());
1387 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1388
1389 QVERIFY(manager.removeContact(foo.id()) == false);
1390 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1391
1392 QMap<int, QContactManager::Error> errorMap;
1393 errorMap.insert(key: 0, value: QContactManager::NoError);
1394 QVERIFY(!manager.saveContacts(0, &errorMap));
1395 QVERIFY(manager.errorMap().count() == 0);
1396 QVERIFY(errorMap.count() == 0);
1397 QVERIFY(manager.error() == QContactManager::BadArgumentError);
1398
1399 /* filters */
1400 QContactFilter f; // matches everything
1401 QContactDetailFilter df;
1402 df.setDetailType(type: QContactDisplayLabel::Type, field: QContactDisplayLabel::FieldLabel);
1403 QVERIFY(manager.contactIds(QContactFilter()).count() == 0);
1404 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1405 QVERIFY(manager.contactIds(df).count() == 0);
1406 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1407 QVERIFY(manager.contactIds(f | f).count() == 0);
1408 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1409 QVERIFY(manager.contactIds(df | df).count() == 0);
1410 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1411
1412 QVERIFY(manager.isFilterSupported(f) == false);
1413 QVERIFY(manager.isFilterSupported(df) == false);
1414
1415 QList<QContact> list;
1416 list << foo;
1417
1418 QVERIFY(!manager.saveContacts(&list, &errorMap));
1419 QVERIFY(errorMap.count() == 0);
1420 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1421
1422 QVERIFY(!manager.removeContacts(QList<QContactId>(), &errorMap));
1423 QVERIFY(errorMap.count() == 0);
1424 QVERIFY(manager.error() == QContactManager::BadArgumentError);
1425
1426 QList<QContactId> idlist;
1427 idlist << foo.id();
1428 QVERIFY(!manager.removeContacts(idlist, &errorMap));
1429 QVERIFY(errorMap.count() == 0);
1430 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1431
1432 /* Self contact id */
1433 QVERIFY(!manager.setSelfContactId(QContactId()));
1434 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1435 QVERIFY(manager.selfContactId() == QContactId());
1436 QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::DoesNotExistError);
1437
1438 /* Relationships */
1439 QContact one, two;
1440 QContactRelationship invalidRel;
1441 invalidRel.setFirst(one.id());
1442 invalidRel.setSecond(two.id());
1443 QList<QContactRelationship> invalidRelList;
1444 invalidRelList << invalidRel;
1445 QVERIFY(!manager.saveRelationship(&invalidRel));
1446 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1447 QVERIFY(manager.relationships().isEmpty());
1448 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1449 manager.saveRelationships(relationships: &invalidRelList, NULL);
1450 QVERIFY(manager.error() == QContactManager::NotSupportedError);
1451 manager.removeRelationships(relationships: invalidRelList, NULL);
1452 QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::DoesNotExistError);
1453
1454 /* Capabilities */
1455 QVERIFY(manager.supportedDataTypes().count() == 0);
1456}
1457
1458void tst_QContactManager::memoryManager()
1459{
1460 QMap<QString, QString> params;
1461 QContactManager m1("memory");
1462 params.insert(key: "random", value: "shouldNotBeUsed");
1463 QContactManager m2("memory", params);
1464 params.insert(key: "id", value: "shouldBeUsed");
1465 QContactManager m3("memory", params);
1466 QContactManager m4("memory", params);
1467 params.insert(key: "id", value: QString(""));
1468 QContactManager m5("memory", params); // should be another anonymous
1469
1470 // add a contact to each of m1, m2, m3
1471 QContact c;
1472 QContactName nc;
1473 nc.setFirstName("John");
1474 nc.setLastName("Civilian");
1475 c.saveDetail(detail: &nc);
1476 m1.saveContact(contact: &c);
1477
1478 // reset ids
1479 c.setId(QContactId());
1480 c.setCollectionId(QContactCollectionId());
1481
1482 QContact c2;
1483 QContactName nc2 = c2.detail(type: QContactName::Type);
1484 c2 = c;
1485 nc2.setMiddleName("Public");
1486 c2.saveDetail(detail: &nc2);
1487
1488 m2.saveContact(contact: &c2); // save c2 first; c will be given a higher id
1489 m2.saveContact(contact: &c); // save c to m2
1490
1491 // reset ids
1492 c.setId(QContactId());
1493 c.setCollectionId(QContactCollectionId());
1494 nc.setSuffix("MD");
1495 c.saveDetail(detail: &nc);
1496 m3.saveContact(contact: &c);
1497
1498 /* test that m1 != m2 != m3 and that m3 == m4 */
1499
1500 // check the counts are correct - especially note m4 and m3.
1501 QCOMPARE(m1.contactIds().count(), 1);
1502 QCOMPARE(m2.contactIds().count(), 2);
1503 QCOMPARE(m3.contactIds().count(), 1);
1504 QCOMPARE(m4.contactIds().count(), 1);
1505 QCOMPARE(m5.contactIds().count(), 0);
1506
1507 // remove c2 from m2 - ensure that this doesn't affect any other manager.
1508 m2.removeContact(contactId: c2.id());
1509 QCOMPARE(m1.contactIds().count(), 1);
1510 QCOMPARE(m2.contactIds().count(), 1);
1511 QCOMPARE(m3.contactIds().count(), 1);
1512 QCOMPARE(m4.contactIds().count(), 1);
1513 QCOMPARE(m5.contactIds().count(), 0);
1514
1515 // check that the contacts contained within are different.
1516 // note that in the m1->m2 case, only the id will be different!
1517 QVERIFY(m1.contact(m1.contactIds().at(0)) != m2.contact(m2.contactIds().at(0)));
1518 QVERIFY(m1.contact(m1.contactIds().at(0)) != m3.contact(m3.contactIds().at(0)));
1519 QVERIFY(m2.contact(m2.contactIds().at(0)) != m3.contact(m3.contactIds().at(0)));
1520 QVERIFY(m3.contact(m3.contactIds().at(0)) == m4.contact(m4.contactIds().at(0)));
1521
1522 // now, we should be able to remove from m4, and have m3 empty
1523 QVERIFY(m4.removeContact(c.id()));
1524 QCOMPARE(m3.contactIds().count(), 0);
1525 QCOMPARE(m4.contactIds().count(), 0);
1526 QCOMPARE(m5.contactIds().count(), 0);
1527}
1528
1529void tst_QContactManager::overrideManager()
1530{
1531 QString defaultStore = QContactManager::availableManagers().value(i: 0);
1532
1533 // preserve existing environment override
1534 QString overrideManager = qgetenv(varName: "QTCONTACTS_MANAGER_OVERRIDE");
1535
1536 // override with specific managers
1537 qputenv(varName: "QTCONTACTS_MANAGER_OVERRIDE", value: "memory");
1538 QContactManager m1;
1539 QCOMPARE(m1.managerName(), QString::fromLatin1("memory"));
1540
1541 qputenv(varName: "QTCONTACTS_MANAGER_OVERRIDE", value: "invalid");
1542 QContactManager m2;
1543 QCOMPARE(m2.managerName(), QString::fromLatin1("invalid"));
1544
1545 qputenv(varName: "QTCONTACTS_MANAGER_OVERRIDE", value: "");
1546 QContactManager m3;
1547 QCOMPARE(m3.managerName(), defaultStore);
1548
1549 qputenv(varName: "QTCONTACTS_MANAGER_OVERRIDE", value: overrideManager.toLatin1());
1550}
1551
1552void tst_QContactManager::nameSynthesis_data()
1553{
1554 QTest::addColumn<QString>(name: "expected");
1555
1556 QTest::addColumn<bool>(name: "addname");
1557 QTest::addColumn<QString>(name: "prefix");
1558 QTest::addColumn<QString>(name: "first");
1559 QTest::addColumn<QString>(name: "middle");
1560 QTest::addColumn<QString>(name: "last");
1561 QTest::addColumn<QString>(name: "suffix");
1562
1563 QTest::addColumn<bool>(name: "addcompany");
1564 QTest::addColumn<QString>(name: "company");
1565
1566 QTest::addColumn<bool>(name: "addname2");
1567 QTest::addColumn<QString>(name: "secondprefix");
1568 QTest::addColumn<QString>(name: "secondfirst");
1569 QTest::addColumn<QString>(name: "secondmiddle");
1570 QTest::addColumn<QString>(name: "secondlast");
1571 QTest::addColumn<QString>(name: "secondsuffix");
1572
1573 QTest::addColumn<bool>(name: "addcompany2");
1574 QTest::addColumn<QString>(name: "secondcompany");
1575
1576 QString e; // empty string.. gets a work out
1577
1578 /* Various empty ones */
1579 QTest::newRow(dataTag: "empty contact") << e
1580 << false << e << e << e << e << e
1581 << false << e
1582 << false << e << e << e << e << e
1583 << false << e;
1584 QTest::newRow(dataTag: "empty name") << e
1585 << true << e << e << e << e << e
1586 << false << e
1587 << false << e << e << e << e << e
1588 << false << e;
1589 QTest::newRow(dataTag: "empty names") << e
1590 << true << e << e << e << e << e
1591 << false << e
1592 << true << e << e << e << e << e
1593 << false << e;
1594 QTest::newRow(dataTag: "empty org") << e
1595 << false << e << e << e << e << e
1596 << true << e
1597 << false << e << e << e << e << e
1598 << true << e;
1599 QTest::newRow(dataTag: "empty orgs") << e
1600 << false << e << e << e << e << e
1601 << true << e
1602 << false << e << e << e << e << e
1603 << true << e;
1604 QTest::newRow(dataTag: "empty orgs and names") << e
1605 << true << e << e << e << e << e
1606 << true << e
1607 << true << e << e << e << e << e
1608 << true << e;
1609
1610 /* Single values */
1611 QTest::newRow(dataTag: "prefix") << "Prefix"
1612 << true << "Prefix" << e << e << e << e
1613 << false << e
1614 << false << e << e << e << e << e
1615 << false << e;
1616 QTest::newRow(dataTag: "first") << "First"
1617 << true << e << "First" << e << e << e
1618 << false << e
1619 << false << e << e << e << e << e
1620 << false << e;
1621 QTest::newRow(dataTag: "middle") << "Middle"
1622 << true << e << e << "Middle" << e << e
1623 << false << e
1624 << false << e << e << e << e << e
1625 << false << e;
1626 QTest::newRow(dataTag: "last") << "Last"
1627 << true << e << e << e << "Last" << e
1628 << false << e
1629 << false << e << e << e << e << e
1630 << false << e;
1631 QTest::newRow(dataTag: "suffix") << "Suffix"
1632 << true << e << e << e << e << "Suffix"
1633 << false << e
1634 << false << e << e << e << e << e
1635 << false << e;
1636
1637 /* Single values in the second name */
1638 QTest::newRow(dataTag: "prefix in second") << "Prefix"
1639 << false << "Prefix" << e << e << e << e
1640 << false << e
1641 << true << "Prefix" << e << e << e << e
1642 << false << e;
1643 QTest::newRow(dataTag: "first in second") << "First"
1644 << false << e << "First" << e << e << e
1645 << false << e
1646 << true << e << "First" << e << e << e
1647 << false << e;
1648 QTest::newRow(dataTag: "middle in second") << "Middle"
1649 << false << e << e << "Middle" << e << e
1650 << false << e
1651 << true << e << e << "Middle" << e << e
1652 << false << e;
1653 QTest::newRow(dataTag: "last in second") << "Last"
1654 << false << e << e << e << "Last" << e
1655 << false << e
1656 << true << e << e << e << "Last" << e
1657 << false << e;
1658 QTest::newRow(dataTag: "suffix in second") << "Suffix"
1659 << false << e << e << e << e << "Suffix"
1660 << false << e
1661 << true << e << e << e << e << "Suffix"
1662 << false << e;
1663
1664 /* Multiple name values */
1665 QTest::newRow(dataTag: "prefix first") << "Prefix First"
1666 << true << "Prefix" << "First" << e << e << e
1667 << false << e
1668 << false << e << e << e << e << e
1669 << false << e;
1670 QTest::newRow(dataTag: "prefix middle") << "Prefix Middle"
1671 << true << "Prefix" << e << "Middle" << e << e
1672 << false << e
1673 << false << e << e << e << e << e
1674 << false << e;
1675 QTest::newRow(dataTag: "prefix last") << "Prefix Last"
1676 << true << "Prefix" << e << e << "Last" << e
1677 << false << e
1678 << false << e << e << e << e << e
1679 << false << e;
1680 QTest::newRow(dataTag: "prefix suffix") << "Prefix Suffix"
1681 << true << "Prefix" << e << e << e << "Suffix"
1682 << false << e
1683 << false << e << e << e << e << e
1684 << false << e;
1685 QTest::newRow(dataTag: "first middle") << "First Middle"
1686 << true << e << "First" << "Middle" << e << e
1687 << false << e
1688 << false << e << e << e << e << e
1689 << false << e;
1690 QTest::newRow(dataTag: "first last") << "First Last"
1691 << true << e << "First" << e << "Last" << e
1692 << false << e
1693 << false << e << e << e << e << e
1694 << false << e;
1695 QTest::newRow(dataTag: "first suffix") << "First Suffix"
1696 << true << e << "First" << e << e << "Suffix"
1697 << false << e
1698 << false << e << e << e << e << e
1699 << false << e;
1700 QTest::newRow(dataTag: "middle last") << "Middle Last"
1701 << true << e << e << "Middle" << "Last" << e
1702 << false << e
1703 << false << e << e << e << e << e
1704 << false << e;
1705 QTest::newRow(dataTag: "middle suffix") << "Middle Suffix"
1706 << true << e << e << "Middle" << e << "Suffix"
1707 << false << e
1708 << false << e << e << e << e << e
1709 << false << e;
1710 QTest::newRow(dataTag: "last suffix") << "Last Suffix"
1711 << true << e << e << e << "Last" << "Suffix"
1712 << false << e
1713 << false << e << e << e << e << e
1714 << false << e;
1715
1716 /* Everything.. */
1717 QTest::newRow(dataTag: "all name") << "Prefix First Middle Last Suffix"
1718 << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
1719 << false << e
1720 << false << e << e << e << e << e
1721 << false << e;
1722 QTest::newRow(dataTag: "all name second") << "Prefix First Middle Last Suffix"
1723 << false << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
1724 << false << e
1725 << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
1726 << false << e;
1727
1728 /* Org */
1729 QTest::newRow(dataTag: "org") << "Company"
1730 << false << e << e << e << e << e
1731 << true << "Company"
1732 << false << e << e << e << e << e
1733 << false << e;
1734 QTest::newRow(dataTag: "second org") << "Company"
1735 << false << e << e << e << e << e
1736 << false << e
1737 << false << e << e << e << e << e
1738 << true << "Company";
1739
1740 /* Mix */
1741 QTest::newRow(dataTag: "org and empty name") << "Company"
1742 << true << e << e << e << e << e
1743 << true << "Company"
1744 << false << e << e << e << e << e
1745 << false << e;
1746
1747 QTest::newRow(dataTag: "name and empty org") << "Prefix First Middle Last Suffix"
1748 << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
1749 << false << e
1750 << false << e << e << e << e << e
1751 << false << e;
1752
1753 /* names are preferred to orgs */
1754 QTest::newRow(dataTag: "name and org") << "Prefix First Middle Last Suffix"
1755 << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
1756 << true << "Company"
1757 << false << e << e << e << e << e
1758 << false << e;
1759
1760}
1761
1762void tst_QContactManager::nameSynthesis()
1763{
1764 QContactManager cm("memory");
1765
1766 QFETCH(QString, expected);
1767
1768 QFETCH(QString, prefix);
1769 QFETCH(QString, first);
1770 QFETCH(QString, middle);
1771 QFETCH(QString, last);
1772 QFETCH(QString, suffix);
1773 QFETCH(QString, company);
1774
1775 QFETCH(QString, secondprefix);
1776 QFETCH(QString, secondfirst);
1777 QFETCH(QString, secondmiddle);
1778 QFETCH(QString, secondlast);
1779 QFETCH(QString, secondsuffix);
1780 QFETCH(QString, secondcompany);
1781
1782 QFETCH(bool, addname);
1783 QFETCH(bool, addname2);
1784 QFETCH(bool, addcompany);
1785 QFETCH(bool, addcompany2);
1786
1787 /* Test the default name synthesis code */
1788 QContact c;
1789
1790 QContactName name, name2;
1791 QContactOrganization org, org2;
1792
1793 name.setPrefix(prefix);
1794 name.setFirstName(first);
1795 name.setMiddleName(middle);
1796 name.setLastName(last);
1797 name.setSuffix(suffix);
1798
1799 name2.setPrefix(secondprefix);
1800 name2.setFirstName(secondfirst);
1801 name2.setMiddleName(secondmiddle);
1802 name2.setLastName(secondlast);
1803 name2.setSuffix(secondsuffix);
1804
1805 org.setName(company);
1806 org2.setName(secondcompany);
1807
1808 if (addname)
1809 c.saveDetail(detail: &name);
1810 if (addname2)
1811 c.saveDetail(detail: &name2);
1812 if (addcompany)
1813 c.saveDetail(detail: &org);
1814 if (addcompany2)
1815 c.saveDetail(detail: &org2);
1816}
1817
1818void tst_QContactManager::observerDeletion()
1819{
1820 QContactManager *manager = new QContactManager("memory");
1821 QContact c;
1822 QVERIFY(manager->saveContact(&c));
1823 QContactId id = c.id();
1824 QContactObserver *observer = new QContactObserver(manager, id);
1825 Q_UNUSED(observer)
1826 delete manager;
1827 delete observer;
1828 // Test for bug MOBILITY-2566 - that QContactObserver doesn't crash when it is
1829 // destroyed after the associated QContactManager
1830}
1831
1832void tst_QContactManager::signalEmission()
1833{
1834 QTest::qWait(ms: 500); // clear the signal queue
1835 QFETCH(QString, uri);
1836 QScopedPointer<QContactManager> m1(QContactManager::fromUri(uri));
1837
1838 qRegisterMetaType<QContactId>(typeName: "QContactId");
1839 qRegisterMetaType<QList<QContactId> >(typeName: "QList<QContactId>");
1840 qRegisterMetaType<QList<QContactDetail::DetailType> >(typeName: "QList<QContactDetail::DetailType>");
1841
1842 QSignalSpy spyCA(m1.data(), SIGNAL(contactsAdded(QList<QContactId>)));
1843 QSignalSpy spyCM(m1.data(), SIGNAL(contactsChanged(QList<QContactId>, QList<QContactDetail::DetailType>)));
1844 QSignalSpy spyCR(m1.data(), SIGNAL(contactsRemoved(QList<QContactId>)));
1845
1846 QTestSignalSink casink(m1.data(), SIGNAL(contactsAdded(QList<QContactId>)));
1847 QTestSignalSink cmsink(m1.data(), SIGNAL(contactsChanged(QList<QContactId>, QList<QContactDetail::DetailType>)));
1848 QTestSignalSink crsink(m1.data(), SIGNAL(contactsRemoved(QList<QContactId>)));
1849
1850
1851 QList<QVariant> args;
1852 QList<QContactId> arg;
1853 QList<QContactCollectionId> collectionIdList;
1854 QContact c;
1855 QList<QContact> batchAdd;
1856 QList<QContactId> batchRemove;
1857 int addSigCount = 0; // the expected signal counts.
1858 int modSigCount = 0;
1859 int remSigCount = 0;
1860
1861 // verify add emits signal added
1862 QContactName nc;
1863 saveContactName(contact: &c, contactName: &nc, name: "John");
1864 QVERIFY(m1->saveContact(&c));
1865 QContactId cid = c.id();
1866 addSigCount += 1;
1867 QTRY_COMPARE(spyCA.count(), addSigCount);
1868 args = spyCA.takeFirst();
1869 addSigCount -= 1;
1870 arg = args.first().value<QList<QContactId> >();
1871 QVERIFY(arg.count() == 1);
1872 QCOMPARE(QContactId(arg.at(0)), cid);
1873
1874 QScopedPointer<QContactObserver> c1Observer(new QContactObserver(m1.data(), cid));
1875 QScopedPointer<QSignalSpy> spyCOM1(new QSignalSpy(c1Observer.data(), SIGNAL(contactChanged(QList<QContactDetail::DetailType>))));
1876 QScopedPointer<QSignalSpy> spyCOR1(new QSignalSpy(c1Observer.data(), SIGNAL(contactRemoved())));
1877
1878 // verify save modified emits signal changed
1879 saveContactName(contact: &c, contactName: &nc, name: "Citizen");
1880 QVERIFY(m1->saveContact(&c));
1881 modSigCount += 1;
1882 QTRY_COMPARE(spyCM.count(), modSigCount);
1883 QTRY_COMPARE(spyCOM1->count(), 1);
1884 args = spyCM.takeFirst();
1885 modSigCount -= 1;
1886 QCOMPARE(args.count(), 2);
1887 arg = args.at(i: 0).value<QList<QContactId> >();
1888 QVERIFY(arg.count() == 1);
1889 QCOMPARE(QContactId(arg.at(0)), cid);
1890 QCOMPARE(args.at(1).userType(), qMetaTypeId<QList<QContactDetail::DetailType> >());
1891 args = spyCOM1->takeFirst();
1892 QCOMPARE(args.count(), 1);
1893 QCOMPARE(args.at(0).userType(), qMetaTypeId<QList<QContactDetail::DetailType> >());
1894
1895 // verify remove emits signal removed
1896 m1->removeContact(contactId: c.id());
1897 remSigCount += 1;
1898 QTRY_COMPARE(spyCR.count(), remSigCount);
1899 QTRY_COMPARE(spyCOR1->count(), 1);
1900 args = spyCR.takeFirst();
1901 remSigCount -= 1;
1902 arg = args.first().value<QList<QContactId> >();
1903 QVERIFY(arg.count() == 1);
1904 QCOMPARE(QContactId(arg.at(0)), cid);
1905
1906 // verify multiple adds works as advertised
1907 QContact c2, c3;
1908 QContactName nc2, nc3;
1909 saveContactName(contact: &c2, contactName: &nc2, name: "Mark");
1910 saveContactName(contact: &c3, contactName: &nc3, name: "Garry");
1911 QVERIFY(m1->saveContact(&c2));
1912 QVERIFY(m1->saveContact(&c3));
1913 QTRY_COMPARE(spyCM.count(), modSigCount);
1914 QTRY_VERIFY(spyCA.count() > addSigCount);
1915 addSigCount = spyCA.count();
1916
1917 spyCOM1->clear();
1918 spyCOR1->clear();
1919 QScopedPointer<QContactObserver> c2Observer(new QContactObserver(m1.data(), c2.id()));
1920 QScopedPointer<QContactObserver> c3Observer(new QContactObserver(m1.data(), c3.id()));
1921 QScopedPointer<QSignalSpy> spyCOM2(new QSignalSpy(c2Observer.data(), SIGNAL(contactChanged(QList<QContactDetail::DetailType>))));
1922 QScopedPointer<QSignalSpy> spyCOM3(new QSignalSpy(c3Observer.data(), SIGNAL(contactChanged(QList<QContactDetail::DetailType>))));
1923 QScopedPointer<QSignalSpy> spyCOR2(new QSignalSpy(c2Observer.data(), SIGNAL(contactRemoved())));
1924 QScopedPointer<QSignalSpy> spyCOR3(new QSignalSpy(c3Observer.data(), SIGNAL(contactRemoved())));
1925
1926 // verify multiple modifies works as advertised
1927 saveContactName(contact: &c2, contactName: &nc2, name: "M.");
1928 QVERIFY(m1->saveContact(&c2));
1929 saveContactName(contact: &c2, contactName: &nc2, name: "Mark");
1930 saveContactName(contact: &c3, contactName: &nc3, name: "G.");
1931 QVERIFY(m1->saveContact(&c2));
1932 QVERIFY(m1->saveContact(&c3));
1933 QTRY_VERIFY(spyCM.count() > modSigCount);
1934 modSigCount = spyCM.count();
1935 QTRY_VERIFY(spyCOM2->count() > 0);
1936 QTRY_VERIFY(spyCOM3->count() > 0);
1937 QCOMPARE(spyCOM1->count(), 0);
1938
1939 // verify multiple removes works as advertised
1940 m1->removeContact(contactId: c3.id());
1941 remSigCount += 1;
1942 m1->removeContact(contactId: c2.id());
1943 remSigCount += 1;
1944 QTRY_VERIFY(spyCOR2->count() > 0);
1945 QTRY_VERIFY(spyCOR3->count() > 0);
1946 QCOMPARE(spyCOR1->count(), 0);
1947
1948 /* Now test the batch equivalents */
1949 spyCA.clear();
1950 spyCM.clear();
1951 spyCR.clear();
1952
1953 /* Batch adds - set ids to zero so add succeeds. */
1954 c.setId(QContactId());
1955 c2.setId(QContactId());
1956 c3.setId(QContactId());
1957 batchAdd << c << c2 << c3;
1958 QMap<int, QContactManager::Error> errorMap;
1959 QVERIFY(m1->saveContacts(&batchAdd, &errorMap));
1960
1961 QVERIFY(batchAdd.count() == 3);
1962 c = batchAdd.at(i: 0);
1963 c2 = batchAdd.at(i: 1);
1964 c3 = batchAdd.at(i: 2);
1965
1966 // We want to see one contactsAdded signal listing id's for all three contacts.
1967 QTRY_COMPARE(spyCA.count(), 1);
1968 {
1969 QList<QContactId> sigids = spyCA.takeFirst().at(i: 0).value<QList<QContactId> >();
1970 QVERIFY(sigids.contains(c.id()));
1971 QVERIFY(sigids.contains(c2.id()));
1972 QVERIFY(sigids.contains(c3.id()));
1973 }
1974
1975 QTRY_COMPARE(spyCM.count(), 0);
1976
1977 c1Observer.reset(other: new QContactObserver(m1.data(), c.id()));
1978 c2Observer.reset(other: new QContactObserver(m1.data(), c2.id()));
1979 c3Observer.reset(other: new QContactObserver(m1.data(), c3.id()));
1980 spyCOM1.reset(other: new QSignalSpy(c1Observer.data(), SIGNAL(contactChanged(QList<QContactDetail::DetailType>))));
1981 spyCOM2.reset(other: new QSignalSpy(c2Observer.data(), SIGNAL(contactChanged(QList<QContactDetail::DetailType>))));
1982 spyCOM3.reset(other: new QSignalSpy(c3Observer.data(), SIGNAL(contactChanged(QList<QContactDetail::DetailType>))));
1983 spyCOR1.reset(other: new QSignalSpy(c1Observer.data(), SIGNAL(contactRemoved())));
1984 spyCOR2.reset(other: new QSignalSpy(c2Observer.data(), SIGNAL(contactRemoved())));
1985 spyCOR3.reset(other: new QSignalSpy(c3Observer.data(), SIGNAL(contactRemoved())));
1986 QTRY_COMPARE(spyCR.count(), 0);
1987
1988 /* Batch modifies */
1989 QContactName modifiedName = c.detail(type: QContactName::Type);
1990 saveContactName(contact: &c, contactName: &modifiedName, name: "Modified number 1");
1991 modifiedName = c2.detail(type: QContactName::Type);
1992 saveContactName(contact: &c2, contactName: &modifiedName, name: "Modified number 2");
1993 modifiedName = c3.detail(type: QContactName::Type);
1994 saveContactName(contact: &c3, contactName: &modifiedName, name: "Modified number 3");
1995
1996 batchAdd.clear();
1997 batchAdd << c << c2 << c3;
1998 QVERIFY(m1->saveContacts(&batchAdd, &errorMap));
1999
2000 // We want to see one contactsChanged signal listing id's for all three contacts.
2001 QTRY_COMPARE(spyCM.count(), 1);
2002 {
2003 QList<QContactId> sigids = spyCM.takeFirst().at(i: 0).value<QList<QContactId> >();
2004 QVERIFY(sigids.contains(c.id()));
2005 QVERIFY(sigids.contains(c2.id()));
2006 QVERIFY(sigids.contains(c3.id()));
2007 }
2008 QTRY_COMPARE(spyCOM1->count(), 1);
2009 QTRY_COMPARE(spyCOM2->count(), 1);
2010 QTRY_COMPARE(spyCOM3->count(), 1);
2011
2012 /* Batch removes */
2013 batchRemove << c.id() << c2.id() << c3.id();
2014 QVERIFY(m1->removeContacts(batchRemove, &errorMap));
2015
2016 // We want to see one contactsRemoved signal listing id's for all three contacts.
2017 QTRY_COMPARE(spyCR.count(), 1);
2018 {
2019 QList<QContactId> sigids = spyCR.takeFirst().at(i: 0).value<QList<QContactId> >();
2020 QVERIFY(sigids.contains(c.id()));
2021 QVERIFY(sigids.contains(c2.id()));
2022 QVERIFY(sigids.contains(c3.id()));
2023 }
2024 QTRY_COMPARE(spyCOR1->count(), 1);
2025 QTRY_COMPARE(spyCOR2->count(), 1);
2026 QTRY_COMPARE(spyCOR3->count(), 1);
2027
2028 QTRY_COMPARE(spyCA.count(), 0);
2029 QTRY_COMPARE(spyCM.count(), 0);
2030
2031 QScopedPointer<QContactManager> m2(QContactManager::fromUri(uri));
2032}
2033
2034void tst_QContactManager::errorStayingPut()
2035{
2036 /* Make sure that when we clone a manager, we don't clone the error */
2037 QMap<QString, QString> params;
2038 params.insert(key: "id", value: "error isolation test");
2039 QContactManager m1("memory",params);
2040
2041 QVERIFY(m1.error() == QContactManager::NoError);
2042
2043 /* Remove an invalid contact to get an error */
2044 QVERIFY(m1.removeContact(QContactId()) == false);
2045 QVERIFY(m1.error() == QContactManager::DoesNotExistError);
2046
2047 /* Create a new manager with hopefully the same backend */
2048 QContactManager m2("memory", params);
2049
2050 QVERIFY(m1.error() == QContactManager::DoesNotExistError);
2051 QVERIFY(m2.error() == QContactManager::NoError);
2052
2053 /* Cause an error on the other ones and check the first is not affected */
2054 m2.saveContacts(contacts: 0, errorMap: 0);
2055 QVERIFY(m1.error() == QContactManager::DoesNotExistError);
2056 QVERIFY(m2.error() == QContactManager::BadArgumentError);
2057
2058 QContact c;
2059 int unknown = 12345;
2060 QContactDetail::DetailType unknownType = static_cast<QContactDetail::DetailType>(unknown);
2061 QContactDetail d(unknownType);
2062 d.setValue(field: unknown, value: 5);
2063 c.saveDetail(detail: &d);
2064
2065 QVERIFY(m1.saveContact(&c) == false);
2066 QVERIFY(m1.error() == QContactManager::InvalidDetailError);
2067 QVERIFY(m2.error() == QContactManager::BadArgumentError);
2068}
2069
2070void tst_QContactManager::actionPreferences()
2071{
2072 QFETCH(QString, uri);
2073 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
2074
2075 // create a sample contact
2076 QContactAvatar a;
2077 a.setImageUrl(QUrl("test.png"));
2078 QContactPhoneNumber p1;
2079 p1.setNumber("12345");
2080 QContactPhoneNumber p2;
2081 p2.setNumber("34567");
2082 QContactPhoneNumber p3;
2083 p3.setNumber("56789");
2084 QContactUrl u;
2085 u.setUrl("http://test.nokia.com");
2086 QContactName n;
2087 QContact c;
2088 saveContactName(contact: &c, contactName: &n, name: "TestContact");
2089 c.saveDetail(detail: &a);
2090 c.saveDetail(detail: &p1);
2091 c.saveDetail(detail: &p2);
2092 c.saveDetail(detail: &p3);
2093 c.saveDetail(detail: &u);
2094
2095 // set a preference for dialing a particular saved phonenumber.
2096 c.setPreferredDetail(actionName: "Dial", preferredDetail: p2);
2097
2098 QVERIFY(cm->saveContact(&c)); // save the contact
2099 QContact loaded = cm->contact(contactId: c.id()); // reload the contact
2100
2101 // test that the preference was saved correctly.
2102 QContactDetail pref = loaded.preferredDetail(actionName: "Dial");
2103 QVERIFY(pref == p2);
2104
2105 cm->removeContact(contactId: c.id());
2106}
2107
2108void tst_QContactManager::changeSet()
2109{
2110 QContactId id = makeId(managerName: "a", id: 1);
2111 QContactChangeSet changeSet;
2112 QVERIFY(changeSet.addedContacts().isEmpty());
2113 QVERIFY(changeSet.changedContacts().isEmpty());
2114 QVERIFY(changeSet.removedContacts().isEmpty());
2115
2116 changeSet.insertAddedContact(addedContactId: id);
2117 QVERIFY(!changeSet.addedContacts().isEmpty());
2118 QVERIFY(changeSet.changedContacts().isEmpty());
2119 QVERIFY(changeSet.removedContacts().isEmpty());
2120 QVERIFY(changeSet.addedContacts().contains(id));
2121
2122 changeSet.insertChangedContact(addedContactId: id, typesChanged: QList<QContactDetail::DetailType>());
2123 changeSet.insertChangedContacts(addedContactIds: QList<QContactId>() << id, typesChanged: QList<QContactDetail::DetailType>());
2124 QCOMPARE(changeSet.changedContacts().size(), 1); // set, should only be added once.
2125 QCOMPARE(changeSet.changedContacts().first().second.size(), 1); // only one changed contact ID
2126 QVERIFY(!changeSet.addedContacts().isEmpty());
2127 QVERIFY(!changeSet.changedContacts().isEmpty());
2128 QVERIFY(changeSet.removedContacts().isEmpty());
2129
2130 changeSet.clearChangedContacts();
2131 changeSet.insertChangedContacts(addedContactIds: QList<QContactId>() << id, typesChanged: QList<QContactDetail::DetailType>() << QContactName::Type);
2132 changeSet.insertChangedContacts(addedContactIds: QList<QContactId>() << id, typesChanged: QList<QContactDetail::DetailType>() << QContactBirthday::Type);
2133 QCOMPARE(changeSet.changedContacts().size(), 2); // should be added twice with differing change types
2134 QVERIFY(!changeSet.addedContacts().isEmpty());
2135 QVERIFY(!changeSet.changedContacts().isEmpty());
2136 QVERIFY(changeSet.removedContacts().isEmpty());
2137 QSet<QContactId> changedIds;
2138 QSet<QContactDetail::DetailType> changedTypes;
2139 foreach (const QContactChangeSet::ContactChangeList &changes, changeSet.changedContacts()) {
2140 changedIds |= changes.second.toSet();
2141 if (changes.second.contains(t: id)) {
2142 changedTypes |= changes.first.toSet();
2143 }
2144 }
2145 QCOMPARE(changedIds, (QList<QContactId>() << id).toSet());
2146 QCOMPARE(changedTypes, (QList<QContactDetail::DetailType>() << QContactName::Type << QContactBirthday::Type).toSet());
2147 changeSet.clearChangedContacts();
2148 QVERIFY(changeSet.changedContacts().isEmpty());
2149
2150 QList<QContactId> l1, l2;
2151 foreach (int n, QList<int>() << 1 << 1 << 1 << 2 << 2 << 3 << 3 << 4 << 4 << 4 << 5 << 10 << 9 << 8 << 8 << 8 << 7 << 7 << 6) {
2152 ((qrand() % 2) ? l1 : l2).append(t: makeId(managerName: "a", id: n));
2153 }
2154 changeSet.clearChangedContacts();
2155 changeSet.insertChangedContacts(addedContactIds: l1, typesChanged: QList<QContactDetail::DetailType>() << QContactName::Type << QContactBirthday::Type);
2156 changeSet.insertChangedContacts(addedContactIds: l2, typesChanged: QList<QContactDetail::DetailType>() << QContactBirthday::Type << QContactName::Type << QContactBirthday::Type);
2157 QCOMPARE(changeSet.changedContacts().size(), 1);
2158 QList<QContactId> expected((l1.toSet() | l2.toSet()).toList());
2159 qSort(c&: expected);
2160 QCOMPARE(changeSet.changedContacts().first().second, expected);
2161
2162 changeSet.insertRemovedContacts(addedContactIds: QList<QContactId>() << id);
2163 QVERIFY(changeSet.removedContacts().contains(id));
2164 changeSet.clearRemovedContacts();
2165 QVERIFY(changeSet.removedContacts().isEmpty());
2166
2167 QVERIFY(changeSet.dataChanged() == false);
2168 QContactChangeSet changeSet2;
2169 changeSet2 = changeSet;
2170 QVERIFY(changeSet.addedContacts() == changeSet2.addedContacts());
2171 changeSet.emitSignals(engine: 0);
2172
2173 changeSet2.clearAddedContacts();
2174 QVERIFY(changeSet2.addedContacts().isEmpty());
2175 changeSet2.insertAddedContacts(addedContactIds: changeSet.addedContacts().toList());
2176 QVERIFY(changeSet.addedContacts() == changeSet2.addedContacts());
2177
2178 changeSet2.clearAll();
2179 QVERIFY(changeSet.addedContacts() != changeSet2.addedContacts());
2180
2181 QContactChangeSet changeSet3(changeSet2);
2182 QVERIFY(changeSet.addedContacts() != changeSet3.addedContacts());
2183 QVERIFY(changeSet2.addedContacts() == changeSet3.addedContacts());
2184
2185 changeSet.setDataChanged(true);
2186 QVERIFY(changeSet.dataChanged() == true);
2187 QVERIFY(changeSet.dataChanged() != changeSet2.dataChanged());
2188 QVERIFY(changeSet.dataChanged() != changeSet3.dataChanged());
2189 changeSet.emitSignals(engine: 0);
2190
2191 changeSet.addedRelationshipsContacts().insert(value: id);
2192 changeSet.insertAddedRelationshipsContacts(affectedContactIds: QList<QContactId>() << id);
2193 QVERIFY(changeSet.addedRelationshipsContacts().contains(id));
2194 changeSet.clearAddedRelationshipsContacts();
2195 QVERIFY(changeSet.addedRelationshipsContacts().isEmpty());
2196 changeSet.insertRemovedRelationshipsContacts(affectedContactIds: QList<QContactId>() << id);
2197 QVERIFY(changeSet.removedRelationshipsContacts().contains(id));
2198 changeSet.clearRemovedRelationshipsContacts();
2199 QVERIFY(changeSet.removedRelationshipsContacts().isEmpty());
2200 changeSet.emitSignals(engine: 0);
2201 changeSet.removedRelationshipsContacts().insert(value: id);
2202 changeSet.emitSignals(engine: 0);
2203
2204 changeSet.setOldAndNewSelfContactId(QPair<QContactId, QContactId>(QContactId(), id));
2205 changeSet2 = changeSet;
2206 QVERIFY(changeSet2.addedRelationshipsContacts() == changeSet.addedRelationshipsContacts());
2207 QVERIFY(changeSet2.removedRelationshipsContacts() == changeSet.removedRelationshipsContacts());
2208 QVERIFY(changeSet2.oldAndNewSelfContactId() == changeSet.oldAndNewSelfContactId());
2209 changeSet.emitSignals(engine: 0);
2210 changeSet.setOldAndNewSelfContactId(QPair<QContactId, QContactId>(id, QContactId()));
2211 QVERIFY(changeSet2.oldAndNewSelfContactId() != changeSet.oldAndNewSelfContactId());
2212 changeSet.setDataChanged(true);
2213 changeSet.emitSignals(engine: 0);
2214}
2215
2216void tst_QContactManager::fetchHint()
2217{
2218 // This just tests the accessors and mutators (API).
2219 // See tst_qcontactmanagerfiltering for the "backend support" test.
2220 QContactFetchHint hint;
2221 hint.setOptimizationHints(QContactFetchHint::NoBinaryBlobs);
2222 QCOMPARE(hint.optimizationHints(), QContactFetchHint::NoBinaryBlobs);
2223 QStringList rels;
2224 rels << QContactRelationship::HasMember();
2225 hint.setRelationshipTypesHint(rels);
2226 QCOMPARE(hint.relationshipTypesHint(), rels);
2227 QList<QContactDetail::DetailType> types;
2228 types << QContactName::Type
2229 << QContactPhoneNumber::Type;
2230 hint.setDetailTypesHint(types);
2231 QCOMPARE(hint.detailTypesHint(), types);
2232 QSize prefImageSize(33, 33);
2233 hint.setPreferredImageSize(prefImageSize);
2234 QCOMPARE(hint.preferredImageSize(), prefImageSize);
2235 int limit = 15;
2236 hint.setMaxCountHint(limit);
2237 QCOMPARE(hint.maxCountHint(), limit);
2238}
2239
2240void tst_QContactManager::selfContactId()
2241{
2242 QFETCH(QString, uri);
2243 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
2244
2245 // early out if the manager doesn't support self contact id saving
2246 QContactId selfContact = cm->selfContactId();
2247
2248 // create a new "self" contact and retrieve its Id
2249 QVERIFY(cm->error() == QContactManager::NoError || cm->error() == QContactManager::DoesNotExistError);
2250 QContact self;
2251 QContactPhoneNumber selfPhn;
2252 selfPhn.setNumber("12345");
2253 self.saveDetail(detail: &selfPhn);
2254 if (!cm->saveContact(contact: &self)) {
2255 QSKIP("Unable to save the generated self contact");
2256 }
2257 QContactId newSelfContact = self.id();
2258
2259 // Setup signal spy
2260 qRegisterMetaType<QContactId>(typeName: "QContactId");
2261 QSignalSpy spy(cm.data(), SIGNAL(selfContactIdChanged(QContactId,QContactId)));
2262 QTestSignalSink sink(cm.data(), SIGNAL(selfContactIdChanged(QContactId,QContactId)));
2263
2264 // Set new self contact
2265 QVERIFY(cm->setSelfContactId(newSelfContact));
2266 QVERIFY(cm->error() == QContactManager::NoError);
2267 QTRY_VERIFY(spy.count() == 1);
2268 QVERIFY(spy.at(0).count() == 2);
2269 // note: for some reason qvariant_cast<QContactId>(spy.at(0).at(0)) returns always zero
2270 // because the type is not recognized. Hence the ugly casting below.
2271 QVERIFY(*((const QContactId*) spy.at(0).at(0).constData()) == selfContact);
2272 QVERIFY(*((const QContactId*) spy.at(0).at(1).constData()) == newSelfContact);
2273 QVERIFY(cm->selfContactId() == newSelfContact);
2274
2275 // Remove self contact
2276 if (!cm->removeContact(contactId: self.id())) {
2277 QSKIP("Unable to remove self contact");
2278 }
2279 QTRY_VERIFY(spy.count() == 2);
2280 QVERIFY(spy.at(1).count() == 2);
2281 QVERIFY(*((const QContactId*) spy.at(1).at(0).constData()) == newSelfContact);
2282 QVERIFY(*((const QContactId*) spy.at(1).at(1).constData()) == QContactId());
2283 QVERIFY(cm->selfContactId() == QContactId()); // ensure reset after removed.
2284
2285 // reset to original state.
2286 cm->setSelfContactId(selfContact);
2287}
2288
2289QList<QContactDetail> tst_QContactManager::removeAllDefaultDetails(const QList<QContactDetail>& details)
2290{
2291 QList<QContactDetail> newlist;
2292 foreach (const QContactDetail d, details) {
2293 if (d.type() != QContactType::Type && d.type() != QContactTimestamp::Type) {
2294 newlist << d;
2295 }
2296 }
2297 return newlist;
2298}
2299
2300void tst_QContactManager::detailOrders()
2301{
2302 QFETCH(QString, uri);
2303 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
2304
2305 if (cm->managerName() == "memory")
2306 QSKIP("Skipping: This manager does not support detail ordering!");
2307
2308 QContact a;
2309 //phone numbers
2310
2311 QContactPhoneNumber number1, number2, number3;
2312
2313 number1.setNumber("11111111");
2314 number1.setContexts(QContactPhoneNumber::ContextHome);
2315
2316 number2.setNumber("22222222");
2317 number2.setContexts(QContactPhoneNumber::ContextWork);
2318
2319 number3.setNumber("33333333");
2320 number3.setContexts(QContactPhoneNumber::ContextOther);
2321
2322 a.saveDetail(detail: &number1);
2323 a.saveDetail(detail: &number2);
2324 a.saveDetail(detail: &number3);
2325
2326 QVERIFY(cm->saveContact(&a));
2327 a = cm->contact(contactId: a.id());
2328
2329 QList<QContactDetail> details = a.details(type: QContactPhoneNumber::Type);
2330 QVERIFY(details.count() == 3);
2331 QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
2332 QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextWork);
2333 QVERIFY(details.at(2).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextOther);
2334
2335 number2 = details.at(i: 1);
2336 QVERIFY(a.removeDetail(&number2));
2337 QVERIFY(cm->saveContact(&a));
2338 a = cm->contact(contactId: a.id());
2339 details = a.details(type: QContactPhoneNumber::Type);
2340 QVERIFY(details.count() == 2);
2341 QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
2342 QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextOther);
2343
2344 a.saveDetail(detail: &number2);
2345 QVERIFY(cm->saveContact(&a));
2346 a = cm->contact(contactId: a.id());
2347
2348 details = a.details(type: QContactPhoneNumber::Type);
2349 QVERIFY(details.count() == 3);
2350 QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
2351 QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextOther);
2352 QVERIFY(details.at(2).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextWork);
2353
2354 //addresses
2355 QContactAddress address1, address2, address3;
2356
2357 address1.setStreet("Brandl St");
2358 address1.setRegion("Brisbane");
2359 address3 = address2 = address1;
2360
2361 address1.setContexts(QContactAddress::ContextHome);
2362 address2.setContexts(QContactAddress::ContextWork);
2363 address3.setContexts(QContactAddress::ContextOther);
2364
2365 QVERIFY(a.saveDetail(&address1));
2366 QVERIFY(a.saveDetail(&address2));
2367 QVERIFY(a.saveDetail(&address3));
2368
2369 QVERIFY(cm->saveContact(&a));
2370 a = cm->contact(contactId: a.id());
2371 details = a.details(type: QContactAddress::Type);
2372 QCOMPARE(details.count(), 3); // 1 location - they're unique
2373
2374 // Detail keys for the moment are not persistent through an contact save / fetch
2375 address3 = details.at(i: 0);
2376
2377 QVERIFY(a.removeDetail(&address3)); // remove the most recent.
2378 address2 = details.at(i: 1); // It is necessary to re-load the detail to ensure that its key is correct
2379 QVERIFY(a.removeDetail(&address2));
2380 QVERIFY(cm->saveContact(&a));
2381 a = cm->contact(contactId: a.id());
2382 details = a.details(type: QContactAddress::Type);
2383 QVERIFY(details.count() == 0); // unique, remove one means none left.
2384
2385 a.saveDetail(detail: &address2);
2386 QVERIFY(cm->saveContact(&a));
2387 a = cm->contact(contactId: a.id());
2388
2389 details = a.details(type: QContactAddress::Type);
2390 QVERIFY(details.count() == 1); // add one back.
2391
2392
2393 //emails
2394 QContactEmailAddress email1, email2, email3;
2395
2396 email1.setEmailAddress("aaron@example.com");
2397 email3 = email2 = email1;
2398 email1.setContexts(QContactEmailAddress::ContextHome);
2399 email2.setContexts(QContactEmailAddress::ContextWork);
2400 email3.setContexts(QContactEmailAddress::ContextOther);
2401
2402 a.saveDetail(detail: &email1);
2403 a.saveDetail(detail: &email2);
2404 a.saveDetail(detail: &email3);
2405
2406 QVERIFY(cm->saveContact(&a));
2407 a = cm->contact(contactId: a.id());
2408
2409 details = a.details(type: QContactEmailAddress::Type);
2410 QVERIFY(details.count() == 1);
2411 // Detail keys for the moment are not persistent through an contact save / fetch
2412 email3 = details.at(i: 0);
2413
2414 QVERIFY(a.removeDetail(&email3)); // remove the most recent.
2415 email2 = details.at(i: 1); // It is necessary to re-load the detail to ensure that its key is correct
2416 QVERIFY(a.removeDetail(&email2));
2417 QVERIFY(cm->saveContact(&a));
2418 a = cm->contact(contactId: a.id());
2419 details = a.details(type: QContactEmailAddress::Type);
2420 QVERIFY(details.count() == 0); // unique, remove one means none left.
2421
2422 a.saveDetail(detail: &email2);
2423 QVERIFY(cm->saveContact(&a));
2424 a = cm->contact(contactId: a.id());
2425
2426 details = a.details(type: QContactEmailAddress::Type);
2427 QVERIFY(details.count() == 1); // add one back.
2428
2429 QVERIFY(cm->removeContact(a.id()));
2430 QVERIFY(cm->error() == QContactManager::NoError);
2431}
2432
2433void tst_QContactManager::relationships()
2434{
2435 QFETCH(QString, uri);
2436 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
2437
2438 // save some contacts
2439 QContact source;
2440 QContact dest1, dest2, dest3, dest4;
2441 QContactPhoneNumber n1, n2, n3, n4;
2442 n1.setNumber("1");
2443 n2.setNumber("2");
2444 n3.setNumber("3");
2445 n4.setNumber("4");
2446
2447 dest1.saveDetail(detail: &n1);
2448 dest2.saveDetail(detail: &n2);
2449 dest3.saveDetail(detail: &n3);
2450 dest4.saveDetail(detail: &n4);
2451
2452 cm->saveContact(contact: &source);
2453 cm->saveContact(contact: &dest1);
2454 cm->saveContact(contact: &dest2);
2455 cm->saveContact(contact: &dest3);
2456 cm->saveContact(contact: &dest4);
2457
2458 // check if manager supports relationships
2459
2460 if (!cm->isRelationshipTypeSupported(relationshipType: QContactRelationship::HasManager())) {
2461 // ensure that the operations all fail as required.
2462 QContactRelationship r1, r2, r3;
2463 r1.setFirst(source.id());
2464 r1.setSecond(dest1.id());
2465 r1.setRelationshipType(QContactRelationship::HasManager());
2466 r2.setFirst(source.id());
2467 r2.setSecond(dest2.id());
2468 r2.setRelationshipType(QContactRelationship::HasManager());
2469 r3.setFirst(source.id());
2470 r3.setSecond(dest3.id());
2471 r3.setRelationshipType(QContactRelationship::HasManager());
2472
2473 QList<QContactRelationship> batchList;
2474 batchList << r2 << r3;
2475
2476 // test save and remove
2477 QVERIFY(!cm->saveRelationship(&r1));
2478 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2479 QVERIFY(!cm->removeRelationship(r1));
2480 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2481 cm->saveRelationships(relationships: &batchList, NULL);
2482 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2483
2484 // test retrieval
2485 QList<QContactRelationship> retrieveList;
2486 retrieveList = cm->relationships(participantId: source.id(), role: QContactRelationship::First);
2487 QVERIFY(retrieveList.isEmpty());
2488 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2489 retrieveList = cm->relationships(participantId: source.id(), role: QContactRelationship::Second);
2490 QVERIFY(retrieveList.isEmpty());
2491 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2492 retrieveList = cm->relationships(participantId: source.id(), role: QContactRelationship::Either); // Either
2493 QVERIFY(retrieveList.isEmpty());
2494 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2495
2496
2497 retrieveList = cm->relationships(relationshipType: QContactRelationship::HasManager(), participantId: source.id(), role: QContactRelationship::First);
2498 QVERIFY(retrieveList.isEmpty());
2499 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2500 retrieveList = cm->relationships(relationshipType: QContactRelationship::HasManager(), participantId: source.id(), role: QContactRelationship::Second);
2501 QVERIFY(retrieveList.isEmpty());
2502 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2503 retrieveList = cm->relationships(relationshipType: QContactRelationship::HasManager(), participantId: source.id(), role: QContactRelationship::Either);
2504 QVERIFY(retrieveList.isEmpty());
2505 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2506 retrieveList = cm->relationships(relationshipType: QContactRelationship::HasManager(), participantId: source.id());
2507 QVERIFY(retrieveList.isEmpty());
2508 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2509 retrieveList = cm->relationships(relationshipType: QContactRelationship::HasManager());
2510 QVERIFY(retrieveList.isEmpty());
2511 QVERIFY(cm->error() == QContactManager::NotSupportedError);
2512 return;
2513 }
2514
2515 // Get supported relationship types
2516 QStringList availableRelationshipTypes;
2517 if (cm->isRelationshipTypeSupported(relationshipType: QContactRelationship::HasMember()))
2518 availableRelationshipTypes << QContactRelationship::HasMember();
2519 if (cm->isRelationshipTypeSupported(relationshipType: QContactRelationship::HasAssistant()))
2520 availableRelationshipTypes << QContactRelationship::HasAssistant();
2521 if (cm->isRelationshipTypeSupported(relationshipType: QContactRelationship::HasManager()))
2522 availableRelationshipTypes << QContactRelationship::HasManager();
2523 if (cm->isRelationshipTypeSupported(relationshipType: QContactRelationship::HasSpouse()))
2524 availableRelationshipTypes << QContactRelationship::HasSpouse();
2525 if (cm->isRelationshipTypeSupported(relationshipType: QContactRelationship::IsSameAs()))
2526 availableRelationshipTypes << QContactRelationship::IsSameAs();
2527
2528 // add some arbitrary type for testing
2529 if (availableRelationshipTypes.count())
2530 availableRelationshipTypes.insert(i: 0, t: "test-arbitrary-relationship-type");
2531 else {
2532 availableRelationshipTypes.append(t: "test-arbitrary-relationship-type");
2533 availableRelationshipTypes.append(t: QContactRelationship::HasMember());
2534 availableRelationshipTypes.append(t: QContactRelationship::HasAssistant());
2535 }
2536
2537 // Verify that we have relationship types. If there are none then the manager
2538 // is saying it supports relationships but does not actually implement any
2539 // relationship type.
2540 QVERIFY(!availableRelationshipTypes.isEmpty());
2541
2542 // Some backends (eg. symbian) require that when type is "HasMember"
2543 // then "first" contact must be a group.
2544 if (availableRelationshipTypes.at(i: 0) == QContactRelationship::HasMember()) {
2545 cm->removeContact(contactId: source.id());
2546 source.setId(QContactId());
2547 source.setType(QContactType::TypeGroup);
2548 cm->saveContact(contact: &source);
2549 }
2550
2551 // build our relationship - source is the manager all of the dest contacts.
2552 QContactRelationship customRelationshipOne;
2553 customRelationshipOne.setFirst(source.id());
2554 customRelationshipOne.setSecond(dest1.id());
2555 customRelationshipOne.setRelationshipType(availableRelationshipTypes.at(i: 0));
2556 QCOMPARE(customRelationshipOne.first(), source.id());
2557 QCOMPARE(customRelationshipOne.second(), dest1.id());
2558 QVERIFY(customRelationshipOne.relationshipType() == availableRelationshipTypes.at(0));
2559
2560 // save the relationship
2561 int managerRelationshipsCount = cm->relationships(relationshipType: availableRelationshipTypes.at(i: 0)).count();
2562 QVERIFY(cm->saveRelationship(&customRelationshipOne));
2563
2564 // test our accessors.
2565 QCOMPARE(cm->relationships(availableRelationshipTypes.at(0)).count(), (managerRelationshipsCount + 1));
2566 QVERIFY(cm->relationships(availableRelationshipTypes.at(0), source.id()).count() == 1);
2567
2568 // remove the dest1 contact, relationship should be removed.
2569 cm->removeContact(contactId: dest1.id());
2570 QCOMPARE(cm->relationships(availableRelationshipTypes.at(0), dest1.id(), QContactRelationship::Second).count(), 0);
2571
2572 // modify and save the relationship
2573 customRelationshipOne.setSecond(dest2.id());
2574 QVERIFY(cm->saveRelationship(&customRelationshipOne));
2575
2576 // attempt to save the relationship again. XXX TODO: what should the result be? currently succeeds (overwrites)
2577 int relationshipsCount = cm->relationships().count();
2578 QVERIFY(cm->saveRelationship(&customRelationshipOne)); // succeeds, but just overwrites
2579 QCOMPARE(relationshipsCount, cm->relationships().count()); // shouldn't change; save should have overwritten.
2580
2581 // removing the source contact should result in removal of the relationship.
2582 QVERIFY(cm->removeContact(source.id()));
2583 QCOMPARE(cm->relationships().count(), relationshipsCount - 1); // the relationship should have been removed.
2584
2585 // now ensure that qcontact relationship caching works as required - perhaps this should be in tst_QContact?
2586 source.setId(QContactId()); // reset id so we can resave
2587 QVERIFY(cm->saveContact(&source)); // save source again.
2588 customRelationshipOne.setFirst(source.id());
2589 customRelationshipOne.setSecond(dest2.id());
2590 QVERIFY(cm->saveRelationship(&customRelationshipOne));
2591
2592 // Add a second relationship
2593 QContactRelationship customRelationshipTwo;
2594 customRelationshipTwo.setFirst(source.id());
2595 if (availableRelationshipTypes.count() > 1)
2596 customRelationshipTwo.setRelationshipType(availableRelationshipTypes.at(i: 1));
2597 else
2598 customRelationshipTwo.setRelationshipType(availableRelationshipTypes.at(i: 0));
2599 customRelationshipTwo.setSecond(dest3.id());
2600 QVERIFY(cm->saveRelationship(&customRelationshipTwo));
2601
2602 // currently, the contacts are "stale" - no cached relationships
2603 QVERIFY(dest3.relatedContacts().isEmpty());
2604 QVERIFY(dest3.relationships().isEmpty());
2605 QVERIFY(dest2.relatedContacts().isEmpty());
2606 QVERIFY(dest2.relationships().isEmpty());
2607
2608 // now refresh the contacts
2609 dest3 = cm->contact(contactId: dest3.id());
2610 dest2 = cm->contact(contactId: dest2.id());
2611 source = cm->contact(contactId: source.id());
2612
2613 // and test again.
2614 QVERIFY(source.relatedContacts(QString(), QContactRelationship::First).isEmpty()); // source is always the first, so this should be empty.
2615 QVERIFY(source.relatedContacts(QString(), QContactRelationship::Second).contains(dest2.id()));
2616 QVERIFY(source.relatedContacts(QString(), QContactRelationship::Either).contains(dest2.id()));
2617 QVERIFY(source.relatedContacts(QString(), QContactRelationship::Second).contains(dest3.id()));
2618 QVERIFY(source.relatedContacts(QString(), QContactRelationship::Either).contains(dest3.id()));
2619 QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).contains(dest2.id()));
2620 QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::First).isEmpty());
2621
2622 QVERIFY(dest2.relatedContacts().contains(source.id()));
2623 QVERIFY(dest2.relationships().contains(customRelationshipOne));
2624 QVERIFY(!dest2.relationships().contains(customRelationshipTwo));
2625 QVERIFY(dest2.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipOne));
2626 QVERIFY(!dest2.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipTwo));
2627 QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0)).contains(source.id()));
2628 QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::First).contains(source.id()));
2629 QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).isEmpty());
2630 QVERIFY(!dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).contains(source.id()));
2631
2632 QVERIFY(dest3.relatedContacts().contains(source.id()));
2633 QVERIFY(!dest3.relationships().contains(customRelationshipOne));
2634 QVERIFY(dest3.relationships().contains(customRelationshipTwo));
2635 QVERIFY(!dest3.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipOne));
2636
2637 // Test iteration
2638 QList<QContactRelationship> relats = source.relationships();
2639 QList<QContactRelationship>::iterator it = relats.begin();
2640
2641 while (it != relats.end()) {
2642 QContactId firstContactId = it->first();
2643 QVERIFY(firstContactId == source.id());
2644 QVERIFY(it->second() == dest2.id() || it->second() == dest3.id());
2645 it++;
2646 }
2647
2648 if (availableRelationshipTypes.count() > 1) {
2649 QVERIFY(source.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::Second).contains(dest3.id()));
2650 QVERIFY(source.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::First).isEmpty());
2651
2652 QVERIFY(dest2.relationships(availableRelationshipTypes.at(1)).isEmpty());
2653
2654 QVERIFY(!dest3.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipTwo));
2655 QVERIFY(dest3.relationships(availableRelationshipTypes.at(1)).contains(customRelationshipTwo));
2656 QVERIFY(!dest3.relationships(availableRelationshipTypes.at(1)).contains(customRelationshipOne));
2657 QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1)).contains(source.id()));
2658 QVERIFY(!dest3.relatedContacts(availableRelationshipTypes.at(0)).contains(source.id()));
2659 QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1)).contains(source.id())); // role = either
2660 QVERIFY(!dest3.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::Second).contains(source.id()));
2661 QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::First).contains(source.id()));
2662 QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(1)).isEmpty());
2663 } else {
2664 QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).contains(dest3.id()));
2665 }
2666
2667 // Cleanup a bit
2668 QMap<int, QContactManager::Error> errorMap;
2669 QList<QContactRelationship> moreRels;
2670
2671 moreRels << customRelationshipOne << customRelationshipTwo;
2672 errorMap.insert(key: 5, value: QContactManager::BadArgumentError);
2673 QVERIFY(cm->removeRelationships(moreRels, &errorMap));
2674 QVERIFY(errorMap.count() == 0);
2675
2676 // test batch API and ordering in contacts
2677 QList<QContactRelationship> currentRelationships = cm->relationships(participantId: source.id(), role: QContactRelationship::First);
2678 QList<QContactRelationship> batchList;
2679 QContactRelationship br1, br2, br3;
2680 br1.setFirst(source.id());
2681 br1.setSecond(dest2.id());
2682 br1.setRelationshipType(availableRelationshipTypes.at(i: 0));
2683 br2.setFirst(source.id());
2684 br2.setSecond(dest3.id());
2685 br2.setRelationshipType(availableRelationshipTypes.at(i: 0));
2686 if (availableRelationshipTypes.count() > 1) {
2687 br3.setFirst(source.id());
2688 br3.setSecond(dest3.id());
2689 br3.setRelationshipType(availableRelationshipTypes.at(i: 1));
2690 } else {
2691 br3.setFirst(source.id());
2692 br3.setSecond(dest4.id());
2693 br3.setRelationshipType(availableRelationshipTypes.at(i: 0));
2694 }
2695 batchList << br1 << br2 << br3;
2696
2697 // ensure that the batch save works properly
2698 cm->saveRelationships(relationships: &batchList, NULL);
2699 QCOMPARE(cm->error(), QContactManager::NoError);
2700 QList<QContactRelationship> batchRetrieve = cm->relationships(participantId: source.id(), role: QContactRelationship::First);
2701 QVERIFY(batchRetrieve.contains(br1));
2702 QVERIFY(batchRetrieve.contains(br2));
2703 QVERIFY(batchRetrieve.contains(br3));
2704
2705 // remove a single relationship
2706 QVERIFY(cm->removeRelationship(br3));
2707 batchRetrieve = cm->relationships(participantId: source.id(), role: QContactRelationship::First);
2708 QVERIFY(batchRetrieve.contains(br1));
2709 QVERIFY(batchRetrieve.contains(br2));
2710 QVERIFY(!batchRetrieve.contains(br3)); // has already been removed.
2711
2712 // now ensure that the batch remove works and we get returned to the original state.
2713 batchList.removeOne(t: br3);
2714 cm->removeRelationships(relationships: batchList, NULL);
2715 QVERIFY(cm->error() == QContactManager::NoError);
2716 QCOMPARE(cm->relationships(source.id(), QContactRelationship::First), currentRelationships);
2717
2718 // attempt to save relationships between an existing source but non-existent destination
2719 QContact nonexistentDest;
2720 quint32 idSeed = 0x5544;
2721 QContactId nonexistentLocalId = QContactId::fromString(idString: QString::number(idSeed));
2722 while (true) {
2723 nonexistentLocalId = cm->contact(contactId: nonexistentLocalId).id();
2724 if (nonexistentLocalId == QContactId()) {
2725 // found a "spare" local id (no contact with that id)
2726 break;
2727 }
2728
2729 // keep looking...
2730 idSeed += 1;
2731 nonexistentLocalId = QContactId::fromString(idString: QString::number(idSeed));
2732 QVERIFY(nonexistentLocalId != QContactId()); // integer overflow check.
2733 }
2734// nonexistentDest.id().setLocalId(nonexistentLocalId);
2735
2736 QContactRelationship maliciousRel;
2737 maliciousRel.setFirst(source.id());
2738 maliciousRel.setSecond(nonexistentDest.id());
2739 maliciousRel.setRelationshipType("nokia-test-invalid-relationship-type");
2740 QVERIFY(!cm->saveRelationship(&maliciousRel));
2741
2742 // attempt to save a circular relationship - should fail!
2743 maliciousRel.setFirst(source.id());
2744 maliciousRel.setSecond(source.id());
2745 maliciousRel.setRelationshipType(availableRelationshipTypes.at(i: 0));
2746 QVERIFY(!cm->saveRelationship(&maliciousRel));
2747
2748 // more negative testing, but force manager to recognise the empty URI
2749 QContact circularContact = source;
2750 maliciousRel.setFirst(circularContact.id());
2751 maliciousRel.setSecond(circularContact.id());
2752 maliciousRel.setRelationshipType(availableRelationshipTypes.at(i: 0));
2753 QVERIFY(!cm->saveRelationship(&maliciousRel));
2754 maliciousRel.setFirst(source.id());
2755 maliciousRel.setSecond(circularContact.id());
2756 maliciousRel.setRelationshipType(availableRelationshipTypes.at(i: 0));
2757 QVERIFY(!cm->saveRelationship(&maliciousRel));
2758 maliciousRel.setFirst(circularContact.id());
2759 maliciousRel.setSecond(source.id());
2760 maliciousRel.setRelationshipType(availableRelationshipTypes.at(i: 0));
2761 QVERIFY(!cm->saveRelationship(&maliciousRel));
2762
2763 // attempt to save a relationship where the source contact comes from another manager
2764 QContactId invalidId;
2765 circularContact.setId(invalidId);
2766 maliciousRel.setFirst(circularContact.id()); // an invalid source contact
2767 maliciousRel.setSecond(dest2.id()); // a valid destination contact
2768 maliciousRel.setRelationshipType(availableRelationshipTypes.at(i: 0));
2769 QVERIFY(!cm->saveRelationship(&maliciousRel));
2770
2771 // remove the nonexistent relationship
2772 relationshipsCount = cm->relationships().count();
2773 QVERIFY(!cm->removeRelationship(maliciousRel)); // does not exist; fail remove.
2774 QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
2775 QCOMPARE(cm->relationships().count(), relationshipsCount); // should be unchanged.
2776
2777 // now we want to ensure that a relationship is removed if one of the contacts is removed.
2778 customRelationshipOne.setFirst(source.id());
2779 customRelationshipOne.setSecond(dest2.id());
2780 customRelationshipOne.setRelationshipType(availableRelationshipTypes.at(i: 0));
2781
2782 // Test batch save with an error map
2783 moreRels.clear();
2784 moreRels << customRelationshipOne;
2785 errorMap.insert(key: 0, value: QContactManager::BadArgumentError);
2786 QVERIFY(cm->saveRelationships(&moreRels, &errorMap));
2787 QVERIFY(cm->error() == QContactManager::NoError);
2788 QVERIFY(errorMap.count() == 0); // should be reset
2789 source = cm->contact(contactId: source.id());
2790 dest2 = cm->contact(contactId: dest2.id());
2791 QVERIFY(cm->removeContact(dest2.id())); // remove dest2, the relationship should be removed
2792 QVERIFY(cm->relationships(availableRelationshipTypes.at(0), dest2.id(), QContactRelationship::Second).isEmpty());
2793 source = cm->contact(contactId: source.id());
2794 QVERIFY(!source.relatedContacts().contains(dest2.id())); // and it shouldn't appear in cache.
2795
2796 // now clean up and remove our dests.
2797 QVERIFY(cm->removeContact(source.id()));
2798 QVERIFY(cm->removeContact(dest3.id()));
2799
2800 // attempt to save relationships with nonexistent contacts
2801 QVERIFY(!cm->saveRelationship(&br1));
2802 QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
2803 cm->saveRelationships(relationships: &batchList, NULL);
2804 QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
2805 QVERIFY(!cm->removeRelationship(br1));
2806 QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
2807 cm->removeRelationships(relationships: batchList, NULL);
2808 QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
2809}
2810
2811void tst_QContactManager::contactType()
2812{
2813 QFETCH(QString, uri);
2814 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
2815
2816 if (!cm->supportedContactTypes().contains(t: QContactType::TypeGroup))
2817 QSKIP("Skipping: This manager does not support group contacts!");
2818
2819 QContact g1, g2, c;
2820
2821 g1.setType(QContactType::TypeGroup);
2822 g2.setType(QContactType::TypeGroup);
2823
2824 QContactPhoneNumber g1p, g2p, cp;
2825 g1p.setNumber("22222");
2826 g2p.setNumber("11111");
2827 cp.setNumber("33333");
2828
2829 g1.saveDetail(detail: &g1p);
2830 g2.saveDetail(detail: &g2p);
2831 c.saveDetail(detail: &cp);
2832
2833 QVERIFY(cm->saveContact(&g1));
2834 QVERIFY(cm->saveContact(&g2));
2835 QVERIFY(cm->saveContact(&c));
2836
2837 // test that the accessing by type works properly
2838 QContactDetailFilter groupFilter;
2839 groupFilter.setDetailType(type: QContactType::Type, field: QContactType::FieldType);
2840 groupFilter.setValue(QContactType::TypeGroup);
2841 QVERIFY(cm->contactIds(groupFilter).contains(g1.id()));
2842 QVERIFY(cm->contactIds(groupFilter).contains(g2.id()));
2843 QVERIFY(!cm->contactIds(groupFilter).contains(c.id()));
2844
2845 QList<QContactSortOrder> sortOrders;
2846 QContactSortOrder byPhoneNumber;
2847 byPhoneNumber.setDetailType(type: QContactPhoneNumber::Type, field: QContactPhoneNumber::FieldNumber);
2848 sortOrders.append(t: byPhoneNumber);
2849
2850 // and ensure that sorting works properly with typed contacts also
2851 QList<QContactId> sortedIds = cm->contactIds(filter: groupFilter, sortOrders);
2852 QVERIFY(sortedIds.indexOf(g2.id()) < sortedIds.indexOf(g1.id()));
2853
2854 cm->removeContact(contactId: g1.id());
2855 cm->removeContact(contactId: g2.id());
2856 cm->removeContact(contactId: c.id());
2857}
2858
2859#if defined(USE_VERSIT_PLZ)
2860void tst_QContactManager::partialSave()
2861{
2862 QFETCH(QString, uri);
2863 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
2864
2865 QVersitContactImporter imp;
2866 QVersitReader reader(QByteArray(
2867 "BEGIN:VCARD\r\nFN:Alice\r\nN:Alice\r\nTEL:12345\r\nEND:VCARD\r\n"
2868 "BEGIN:VCARD\r\nFN:Bob\r\nN:Bob\r\nTEL:5678\r\nEND:VCARD\r\n"
2869 "BEGIN:VCARD\r\nFN:Carol\r\nN:Carol\r\nEMAIL:carol@example.com\r\nEND:VCARD\r\n"
2870 "BEGIN:VCARD\r\nFN:David\r\nN:David\r\nORG:DavidCorp\r\nEND:VCARD\r\n"));
2871 reader.startReading();
2872 reader.waitForFinished();
2873 QCOMPARE(reader.error(), QVersitReader::NoError);
2874
2875 QCOMPARE(reader.results().count(), 4);
2876 QVERIFY(imp.importDocuments(reader.results()));
2877 QCOMPARE(imp.contacts().count(), 4);
2878 QVERIFY(imp.contacts()[0].displayLabel() == QStringLiteral("Alice"));
2879 QVERIFY(imp.contacts()[1].displayLabel() == QStringLiteral("Bob"));
2880 QVERIFY(imp.contacts()[2].displayLabel() == QStringLiteral("Carol"));
2881 QVERIFY(imp.contacts()[3].displayLabel() == QStringLiteral("David"));
2882
2883 QList<QContact> contacts = imp.contacts();
2884 QMap<int, QContactManager::Error> errorMap;
2885
2886 // First save these contacts
2887 QVERIFY(cm->saveContacts(&contacts, &errorMap));
2888 QList<QContact> originalContacts = contacts;
2889
2890 // Now try some partial save operations
2891 // 0) empty mask == full save
2892 // 1) Ignore an added phonenumber
2893 // 2) Only save a modified phonenumber, not a modified email
2894 // 3) Remove an email address & phone, mask out phone
2895 // 4) new contact, no details in the mask
2896 // 5) new contact, some details in the mask
2897 // 6) Have a bad manager uri in the middle
2898 // 7) Have a non existing contact in the middle
2899 // 8) A list entirely of new contacts
2900
2901 QContactPhoneNumber pn;
2902 pn.setNumber("111111");
2903 contacts[0].saveDetail(&pn);
2904
2905 // 0) empty mask
2906 QVERIFY(cm->saveContacts(&contacts, QStringList(), &errorMap));
2907
2908 // That should have updated everything
2909 QContact a = cm->contact(originalContacts[0].id());
2910 QVERIFY(a.details<QContactPhoneNumber>().count() == 2);
2911
2912 // 1) Add a phone number to b, mask it out
2913 contacts[1].saveDetail(&pn);
2914 QVERIFY(cm->saveContacts(&contacts, QStringList(QContactEmailAddress::Type), &errorMap));
2915 QVERIFY(errorMap.isEmpty());
2916
2917 QContact b = cm->contact(originalContacts[1].id());
2918 QVERIFY(b.details<QContactPhoneNumber>().count() == 1);
2919
2920 // 2) save a modified detail in the mask
2921 QContactEmailAddress e;
2922 e.setEmailAddress("example@example.com");
2923 contacts[1].saveDetail(&e); // contacts[1] should have both phone and email
2924
2925 QVERIFY(cm->saveContacts(&contacts, QStringList(QContactEmailAddress::Type), &errorMap));
2926 QVERIFY(errorMap.isEmpty());
2927 b = cm->contact(originalContacts[1].id());
2928 QVERIFY(b.details<QContactPhoneNumber>().count() == 1);
2929 QVERIFY(b.details<QContactEmailAddress>().count() == 1);
2930
2931 // 3) Remove an email address and a phone number
2932 QVERIFY(contacts[1].removeDetail(&e));
2933 QVERIFY(contacts[1].removeDetail(&pn));
2934 QVERIFY(contacts[1].details<QContactEmailAddress>().count() == 0);
2935 QVERIFY(contacts[1].details<QContactPhoneNumber>().count() == 1);
2936 QVERIFY(cm->saveContacts(&contacts, QStringList(QContactEmailAddress::Type), &errorMap));
2937 QVERIFY(errorMap.isEmpty());
2938 b = cm->contact(originalContacts[1].id());
2939 QVERIFY(b.details<QContactPhoneNumber>().count() == 1);
2940 QVERIFY(b.details<QContactEmailAddress>().count() == 0);
2941
2942 // 4 - New contact, no details in the mask
2943 QContact newContact = originalContacts[3];
2944 newContact.setId(QContactId());
2945
2946 contacts.append(newContact);
2947 QVERIFY(cm->saveContacts(&contacts, QStringList(QContactEmailAddress::Type), &errorMap));
2948 QVERIFY(errorMap.isEmpty());
2949 QVERIFY(contacts[4].id() != 0); // Saved
2950 b = cm->contact(contacts[4].id());
2951 QVERIFY(b.details<QContactOrganization>().count() == 0); // not saved
2952 QVERIFY(b.details<QContactName>().count() == 0); // not saved
2953
2954 // 5 - New contact, some details in the mask
2955 newContact = originalContacts[2];
2956 newContact.setId(QContactId());
2957 contacts.append(newContact);
2958 QVERIFY(cm->saveContacts(&contacts, QStringList(QContactEmailAddress::Type), &errorMap));
2959 QVERIFY(errorMap.isEmpty());
2960 QVERIFY(contacts[5].id() != 0); // Saved
2961 b = cm->contact(contacts[5].id());
2962 QVERIFY(b.details<QContactEmailAddress>().count() == 1);
2963 QVERIFY(b.details<QContactName>().count() == 0); // not saved
2964
2965 // 6) Have a bad manager uri in the middle followed by a save error
2966 QContactId id4(contacts[4].id());
2967 QContactId badId(id4);
2968 badId.setManagerUri(QString());
2969 contacts[4].setId(badId);
2970 QContactDetail badDetail("BadDetail");
2971 badDetail.setValue("BadField", "BadValue");
2972 contacts[5].saveDetail(&badDetail);
2973 QVERIFY(!cm->saveContacts(&contacts, QStringList("BadDetail"), &errorMap));
2974 QCOMPARE(errorMap.count(), 2);
2975 QCOMPARE(errorMap[4], QContactManager::DoesNotExistError);
2976 QCOMPARE(errorMap[5], QContactManager::InvalidDetailError);
2977
2978 // 7) Have a non existing contact in the middle followed by a save error
2979 badId = id4;
2980 badId.setLocalId("987234"); // something nonexistent
2981 contacts[4].setId(badId);
2982 QVERIFY(!cm->saveContacts(&contacts, QStringList("BadDetail"), &errorMap));
2983 QCOMPARE(errorMap.count(), 2);
2984 QCOMPARE(errorMap[4], QContactManager::DoesNotExistError);
2985 QCOMPARE(errorMap[5], QContactManager::InvalidDetailError);
2986
2987 // 8 - New contact, no details in the mask
2988 newContact = originalContacts[3];
2989 QCOMPARE(newContact.details<QContactOrganization>().count(), 1);
2990 QCOMPARE(newContact.details<QContactName>().count(), 1);
2991 newContact.setId(QContactId());
2992 QList<QContact> contacts2;
2993 contacts2.append(newContact);
2994 QVERIFY(cm->saveContacts(&contacts2, QStringList(QContactEmailAddress::Type), &errorMap));
2995 QVERIFY(errorMap.isEmpty());
2996 QVERIFY(contacts2[0].id() != 0); // Saved
2997 b = cm->contact(contacts2[0].id());
2998 QVERIFY(b.details<QContactOrganization>().count() == 0); // not saved
2999 QVERIFY(b.details<QContactName>().count() == 0); // not saved
3000
3001 // 9 - A list with only a new contact, with some details in the mask
3002 newContact = originalContacts[2];
3003 newContact.setId(QContactId());
3004 contacts2.clear();
3005 contacts2.append(newContact);
3006 QVERIFY(cm->saveContacts(&contacts2, QStringList(QContactEmailAddress::Type), &errorMap));
3007 QVERIFY(errorMap.isEmpty());
3008 QVERIFY(contacts2[0].id() != 0); // Saved
3009 b = cm->contact(contacts2[0].id());
3010 QVERIFY(b.details<QContactEmailAddress>().count() == 1);
3011 QVERIFY(b.details<QContactName>().count() == 0); // not saved
3012
3013 // 10 - A list with new a contact for the wrong manager, followed by a new contact with an
3014 // invalid detail
3015 newContact = originalContacts[2];
3016 newContact.setId(QContactId());
3017 contacts2.clear();
3018 contacts2.append(newContact);
3019 contacts2.append(newContact);
3020 contacts2[0].setId(badId);
3021 contacts2[1].saveDetail(&badDetail);
3022 QVERIFY(!cm->saveContacts(&contacts2, QStringList("BadDetail"), &errorMap));
3023 QCOMPARE(errorMap.count(), 2);
3024 QCOMPARE(errorMap[0], QContactManager::DoesNotExistError);
3025 QCOMPARE(errorMap[1], QContactManager::InvalidDetailError);
3026}
3027#endif
3028
3029void tst_QContactManager::lateDeletion()
3030{
3031 // Create some engines, but make them get deleted at shutdown
3032 QFETCH(QString, uri);
3033 QContactManager* cm = QContactManager::fromUri(uri);
3034
3035 cm->setParent(qApp); // now do nothing
3036}
3037
3038void tst_QContactManager::lazyConnections()
3039{
3040 QSKIP("Skipping: Lazy manager engine does not currently work with new plugin system!");
3041 //TODO: adapt lazy manager engine to new plugin system
3042 QMap<QString, QString> parameters;
3043 parameters["version"] = QString("1");
3044 QContactManager lazy1("testlazy", parameters);
3045 QContactManager lazy2("testlazy");
3046
3047 QCOMPARE(lazy1.managerName(), QString("lazy"));
3048 QCOMPARE(lazy2.managerName(), QString("lazy2"));
3049
3050 // Make sure the initial connection counts are empty
3051 QCOMPARE(QContactLazyEngine::connectionCounts.count(), 0);
3052 QCOMPARE(QContactLazyEngine2::connectionCounts.count(), 0);
3053
3054 // Lazy 1 first
3055 {
3056 QTestSignalSink casink(&lazy1, SIGNAL(contactsAdded(QList<QContactId>)));
3057
3058 // See if we got one connection
3059 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsAdded)), 1);
3060 QCOMPARE(QContactLazyEngine::connectionCounts.count(), 1);
3061
3062 // Go out of scope, and see if disconnect is called
3063 }
3064 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsAdded)), 0);
3065 QCOMPARE(QContactLazyEngine::connectionCounts.count(), 1);
3066
3067 // Lazy2 second
3068 {
3069 QTestSignalSink casink(&lazy2, SIGNAL(contactsAdded(QList<QContactId>)));
3070
3071 // See if we got one connection
3072 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsAdded)), 1);
3073 QCOMPARE(QContactLazyEngine2::connectionCounts.count(), 1);
3074
3075 // Go out of scope, and see if disconnect is called
3076 }
3077 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsAdded)), 0);
3078 QCOMPARE(QContactLazyEngine2::connectionCounts.count(), 1);
3079
3080 // Just make sure all the signals get connected correctly
3081 {
3082 QTestSignalSink casink(&lazy1, SIGNAL(contactsAdded(QList<QContactId>)));
3083 QTestSignalSink crsink(&lazy1, SIGNAL(contactsRemoved(QList<QContactId>)));
3084 QTestSignalSink cmsink(&lazy1, SIGNAL(contactsChanged(QList<QContactId>, QList<QContactDetail::DetailType>)));
3085 QTestSignalSink dcsink(&lazy1, SIGNAL(dataChanged()));
3086 QTestSignalSink rasink(&lazy1, SIGNAL(relationshipsAdded(QList<QContactId>)));
3087 QTestSignalSink rrsink(&lazy1, SIGNAL(relationshipsRemoved(QList<QContactId>)));
3088 QTestSignalSink scsink(&lazy1, SIGNAL(selfContactIdChanged(QContactId,QContactId)));
3089
3090 // See if we got all the connections
3091 QCOMPARE(QContactLazyEngine::connectionCounts.count(), 7);
3092 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsAdded)), 1);
3093 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsChanged)), 1);
3094 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsRemoved)), 1);
3095 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::dataChanged)), 1);
3096 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::relationshipsAdded)), 1);
3097 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::relationshipsRemoved)), 1);
3098 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::selfContactIdChanged)), 1);
3099 }
3100 QCOMPARE(QContactLazyEngine::connectionCounts.count(), 7);
3101 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsAdded)), 0);
3102 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsChanged)), 0);
3103 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::contactsRemoved)), 0);
3104 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::dataChanged)), 0);
3105 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::relationshipsAdded)), 0);
3106 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::relationshipsRemoved)), 0);
3107 QCOMPARE(QContactLazyEngine::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine::selfContactIdChanged)), 0);
3108
3109 // and for lazy2
3110 {
3111 QTestSignalSink casink(&lazy2, SIGNAL(contactsAdded(QList<QContactId>)));
3112 QTestSignalSink crsink(&lazy2, SIGNAL(contactsRemoved(QList<QContactId>)));
3113 QTestSignalSink cmsink(&lazy2, SIGNAL(contactsChanged(QList<QContactId>, QList<QContactDetail::DetailType>)));
3114 QTestSignalSink dcsink(&lazy2, SIGNAL(dataChanged()));
3115 QTestSignalSink rasink(&lazy2, SIGNAL(relationshipsAdded(QList<QContactId>)));
3116 QTestSignalSink rrsink(&lazy2, SIGNAL(relationshipsRemoved(QList<QContactId>)));
3117 QTestSignalSink scsink(&lazy2, SIGNAL(selfContactIdChanged(QContactId,QContactId)));
3118
3119 // See if we got all the connections
3120 QCOMPARE(QContactLazyEngine2::connectionCounts.count(), 7);
3121 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsAdded)), 1);
3122 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsChanged)), 1);
3123 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsRemoved)), 1);
3124 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::dataChanged)), 1);
3125 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::relationshipsAdded)), 1);
3126 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::relationshipsRemoved)), 1);
3127 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::selfContactIdChanged)), 1);
3128 }
3129 QCOMPARE(QContactLazyEngine2::connectionCounts.count(), 7);
3130 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsAdded)), 0);
3131 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsChanged)), 0);
3132 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::contactsRemoved)), 0);
3133 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::dataChanged)), 0);
3134 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::relationshipsAdded)), 0);
3135 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::relationshipsRemoved)), 0);
3136 QCOMPARE(QContactLazyEngine2::connectionCounts.value(QMetaMethod::fromSignal(&QContactLazyEngine2::selfContactIdChanged)), 0);
3137}
3138
3139void tst_QContactManager::compareVariant()
3140{
3141 // Exercise this function a bit
3142 QFETCH(QVariant, a);
3143 QFETCH(QVariant, b);
3144 QFETCH(Qt::CaseSensitivity, cs);
3145 QFETCH(int, expected);
3146
3147 int comparison = QContactManagerEngine::compareVariant(first: a, second: b, sensitivity: cs);
3148 // Since compareVariant is a little imprecise (just sign matters)
3149 // convert that here.
3150 if (comparison < 0)
3151 comparison = -1;
3152 else if (comparison > 0)
3153 comparison = 1;
3154
3155 QCOMPARE(comparison, expected);
3156
3157 comparison = QContactManagerEngine::compareVariant(first: b, second: a, sensitivity: cs);
3158 if (comparison < 0)
3159 comparison = -1;
3160 else if (comparison > 0)
3161 comparison = 1;
3162
3163 // The sign should be flipped now
3164 QVERIFY((comparison + expected) == 0);
3165}
3166
3167void tst_QContactManager::createCollection()
3168{
3169 QFETCH(QString, uri);
3170 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
3171
3172 qRegisterMetaType<QList<QContactCollectionId> >(typeName: "QList<QContactCollectionId>");
3173 QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
3174 QByteArray collectionName = QUuid::createUuid().toByteArray();
3175
3176 // create collection
3177 {
3178 QContactCollection col;
3179 col.setMetaData(key: QContactCollection::KeyName, value: collectionName);
3180 QVERIFY(cm->saveCollection(&col));
3181 }
3182
3183 // check "collectionsAdded" signal
3184 QCOMPARE(collectionsAddedSpy.count(), 1);
3185 QList<QContactCollectionId> ids = collectionsAddedSpy.takeFirst().at(i: 0).value<QList<QContactCollectionId> >();
3186 QCOMPARE(ids.count(), 1);
3187
3188 // query for new collection
3189 {
3190 QContactCollection col = cm->collection(collectionId: ids.at(i: 0));
3191 QVERIFY(!col.id().isNull());
3192 QCOMPARE(col.id().toString(), ids.at(0).toString());
3193 QCOMPARE(col.metaData(QContactCollection::KeyName).toByteArray(), collectionName);
3194 }
3195}
3196
3197void tst_QContactManager::modifyCollection()
3198{
3199 QFETCH(QString, uri);
3200 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
3201
3202 qRegisterMetaType<QList<QContactCollectionId> >(typeName: "QList<QContactCollectionId>");
3203 QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
3204 QSignalSpy collectionsChangedSpy(cm.data(), SIGNAL(collectionsChanged(QList<QContactCollectionId>)));
3205
3206 QContactCollectionId colId;
3207 QByteArray collectionName = QUuid::createUuid().toByteArray();
3208
3209 // save a new collection
3210 {
3211 QContactCollection col;
3212 col.setMetaData(key: QContactCollection::KeyName, value: collectionName);
3213 QVERIFY(cm->saveCollection(&col));
3214 QTRY_COMPARE(collectionsAddedSpy.count(), 1);
3215 colId = col.id();
3216 QVERIFY(!colId.isNull());
3217 }
3218
3219 // edit collection
3220 {
3221 QCOMPARE(collectionsChangedSpy.count(), 0);
3222 QContactCollection col = cm->collection(collectionId: colId);
3223 QByteArray newCollectionName = QUuid::createUuid().toByteArray();
3224 col.setMetaData(key: QContactCollection::KeyName, value: newCollectionName);
3225 QVERIFY(cm->saveCollection(&col));
3226
3227 // check signal "collectionsChanged" fired contains the collection id
3228 QTRY_COMPARE(collectionsChangedSpy.count(), 1);
3229 QList<QContactCollectionId> ids = collectionsChangedSpy.takeFirst().at(i: 0).value<QList<QContactCollectionId> >();
3230 QCOMPARE(ids.at(0).toString(), colId.toString());
3231
3232 // check if the collection name was updated
3233 QContactCollection col2 = cm->collection(collectionId: colId);
3234 QCOMPARE(col2.metaData(QContactCollection::KeyName).toByteArray(), newCollectionName);
3235 }
3236}
3237
3238void tst_QContactManager::removeCollection()
3239{
3240 QFETCH(QString, uri);
3241 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
3242
3243 qRegisterMetaType<QList<QContactCollectionId> >(typeName: "QList<QContactCollectionId>");
3244 QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
3245 QSignalSpy collectionsRemovedSpy(cm.data(), SIGNAL(collectionsRemoved(QList<QContactCollectionId>)));
3246
3247 QContactCollectionId colId;
3248
3249 // save a new collection
3250 {
3251 QContactCollection col;
3252 QByteArray collectionName = QUuid::createUuid().toByteArray();
3253 col.setMetaData(key: QContactCollection::KeyName, value: collectionName);
3254 QVERIFY(cm->saveCollection(&col));
3255 QTRY_COMPARE(collectionsAddedSpy.count(), 1);
3256 colId = col.id();
3257 }
3258 QList<QContactCollection> collections = cm->collections();
3259
3260 // remove collection
3261 cm->removeCollection(collectionId: colId);
3262
3263 // check "collectionsRemoved" signal
3264 QTRY_COMPARE(collectionsRemovedSpy.count(), 1);
3265 QList<QContactCollectionId> ids = collectionsRemovedSpy.takeFirst().at(i: 0).value<QList<QContactCollectionId> >();
3266 QCOMPARE(ids.at(0).toString(), colId.toString());
3267
3268
3269 // check if the correct collection was removed
3270 QList<QContactCollection> collectionsAfterRemoval = cm->collections();
3271 QCOMPARE(collections.count() - 1, collectionsAfterRemoval.count());
3272 Q_FOREACH (const QContactCollection &col, collectionsAfterRemoval) {
3273 collections.removeAll(t: col);
3274 }
3275 QCOMPARE(collections.count(), 1);
3276 QCOMPARE(collections.at(0).id().toString(), colId.toString());
3277}
3278
3279void tst_QContactManager::saveContactIntoCollections()
3280{
3281 QFETCH(QString, uri);
3282 QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
3283
3284 qRegisterMetaType<QList<QContactCollectionId> >(typeName: "QList<QContactCollectionId>");
3285 QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
3286 QByteArray collectionName = QUuid::createUuid().toByteArray();
3287 QContactCollectionId colId;
3288 QContactId cId;
3289
3290 // create collection
3291 {
3292 QContactCollection col;
3293 col.setMetaData(key: QContactCollection::KeyName, value: collectionName);
3294 QVERIFY(cm->saveCollection(&col));
3295 QTRY_COMPARE(collectionsAddedSpy.count(), 1);
3296 colId = col.id();
3297 }
3298
3299 // create contact
3300 {
3301 QContact c = createContact(firstName: "Alice", lastName: "Last", phoneNumber: "12345");
3302 c.setCollectionId(colId);
3303 cm->saveContact(contact: &c);
3304 cId = c.id();
3305 }
3306
3307 // query new contact and check for collection
3308 {
3309 QContact c = cm->contact(contactId: cId);
3310 QCOMPARE(c.collectionId().toString(), colId.toString());
3311 }
3312}
3313
3314void tst_QContactManager::compareVariant_data()
3315{
3316 QTest::addColumn<QVariant>(name: "a");
3317 QTest::addColumn<QVariant>(name: "b");
3318
3319 QTest::addColumn<Qt::CaseSensitivity>(name: "cs");
3320 QTest::addColumn<int>(name: "expected");
3321
3322 // bool
3323 QTest::newRow(dataTag: "bool <") << QVariant(false) << QVariant(true) << Qt::CaseInsensitive << -1;
3324 QTest::newRow(dataTag: "bool =") << QVariant(false) << QVariant(false) << Qt::CaseInsensitive << -0;
3325 QTest::newRow(dataTag: "bool >") << QVariant(true) << QVariant(false) << Qt::CaseInsensitive << 1;
3326
3327 // char (who uses these??)
3328 QTest::newRow(dataTag: "char <") << QVariant(QChar('a')) << QVariant(QChar('b')) << Qt::CaseInsensitive << -1;
3329 QTest::newRow(dataTag: "char < ci") << QVariant(QChar('A')) << QVariant(QChar('b')) << Qt::CaseInsensitive << -1;
3330 QTest::newRow(dataTag: "char < ci 2") << QVariant(QChar('a')) << QVariant(QChar('B')) << Qt::CaseInsensitive << -1;
3331 QTest::newRow(dataTag: "char < cs") << QVariant(QChar('a')) << QVariant(QChar('b')) << Qt::CaseSensitive << -1;
3332 QTest::newRow(dataTag: "char < cs") << QVariant(QChar('A')) << QVariant(QChar('b')) << Qt::CaseSensitive << -1;
3333
3334 QTest::newRow(dataTag: "char = ci") << QVariant(QChar('a')) << QVariant(QChar('a')) << Qt::CaseInsensitive << 0;
3335 QTest::newRow(dataTag: "char = ci 2") << QVariant(QChar('a')) << QVariant(QChar('A')) << Qt::CaseInsensitive << 0;
3336 QTest::newRow(dataTag: "char = ci 3") << QVariant(QChar('A')) << QVariant(QChar('a')) << Qt::CaseInsensitive << 0;
3337 QTest::newRow(dataTag: "char = ci 4") << QVariant(QChar('A')) << QVariant(QChar('A')) << Qt::CaseInsensitive << 0;
3338 QTest::newRow(dataTag: "char = cs") << QVariant(QChar('a')) << QVariant(QChar('a')) << Qt::CaseSensitive << 0;
3339 QTest::newRow(dataTag: "char = cs 2") << QVariant(QChar('A')) << QVariant(QChar('A')) << Qt::CaseSensitive << 0;
3340
3341 QTest::newRow(dataTag: "char >") << QVariant(QChar('b')) << QVariant(QChar('a')) << Qt::CaseInsensitive << 1;
3342 QTest::newRow(dataTag: "char > ci") << QVariant(QChar('b')) << QVariant(QChar('A')) << Qt::CaseInsensitive << 1;
3343 QTest::newRow(dataTag: "char > ci 2") << QVariant(QChar('B')) << QVariant(QChar('a')) << Qt::CaseInsensitive << 1;
3344 QTest::newRow(dataTag: "char > cs") << QVariant(QChar('b')) << QVariant(QChar('a')) << Qt::CaseSensitive << 1;
3345 QTest::newRow(dataTag: "char > cs") << QVariant(QChar('b')) << QVariant(QChar('A')) << Qt::CaseSensitive << 1;
3346
3347 // Some numeric types
3348 // uint
3349 QTest::newRow(dataTag: "uint < boundary") << QVariant(uint(1)) << QVariant(uint(-1)) << Qt::CaseInsensitive << -1;
3350 QTest::newRow(dataTag: "uint <") << QVariant(uint(1)) << QVariant(uint(2)) << Qt::CaseInsensitive << -1;
3351 QTest::newRow(dataTag: "uint =") << QVariant(uint(2)) << QVariant(uint(2)) << Qt::CaseInsensitive << 0;
3352 QTest::newRow(dataTag: "uint = 0") << QVariant(uint(0)) << QVariant(uint(0)) << Qt::CaseInsensitive << 0;
3353 QTest::newRow(dataTag: "uint = boundary") << QVariant(uint(-1)) << QVariant(uint(-1)) << Qt::CaseInsensitive << 0;
3354 QTest::newRow(dataTag: "uint >") << QVariant(uint(5)) << QVariant(uint(2)) << Qt::CaseInsensitive << 1;
3355 QTest::newRow(dataTag: "uint > boundary") << QVariant(uint(-1)) << QVariant(uint(2)) << Qt::CaseInsensitive << 1; // boundary
3356
3357 // int (hmm, signed 32 bit assumed)
3358 QTest::newRow(dataTag: "int < boundary") << QVariant(int(0x80000000)) << QVariant(int(0x7fffffff)) << Qt::CaseInsensitive << -1;
3359 QTest::newRow(dataTag: "int <") << QVariant(int(1)) << QVariant(int(2)) << Qt::CaseInsensitive << -1;
3360 QTest::newRow(dataTag: "int =") << QVariant(int(2)) << QVariant(int(2)) << Qt::CaseInsensitive << 0;
3361 QTest::newRow(dataTag: "int = 0") << QVariant(int(0)) << QVariant(int(0)) << Qt::CaseInsensitive << 0;
3362 QTest::newRow(dataTag: "int = boundary") << QVariant(int(0x80000000)) << QVariant(int(0x80000000)) << Qt::CaseInsensitive << 0;
3363 QTest::newRow(dataTag: "int >") << QVariant(int(5)) << QVariant(int(2)) << Qt::CaseInsensitive << 1;
3364 QTest::newRow(dataTag: "int > boundary") << QVariant(int(0x7fffffff)) << QVariant(int(0x80000000)) << Qt::CaseInsensitive << 1; // boundary
3365
3366 // ulonglong
3367 QTest::newRow(dataTag: "ulonglong < boundary") << QVariant(qulonglong(1)) << QVariant(qulonglong(-1)) << Qt::CaseInsensitive << -1;
3368 QTest::newRow(dataTag: "ulonglong <") << QVariant(qulonglong(1)) << QVariant(qulonglong(2)) << Qt::CaseInsensitive << -1;
3369 QTest::newRow(dataTag: "ulonglong =") << QVariant(qulonglong(2)) << QVariant(qulonglong(2)) << Qt::CaseInsensitive << 0;
3370 QTest::newRow(dataTag: "ulonglong = 0") << QVariant(qulonglong(0)) << QVariant(qulonglong(0)) << Qt::CaseInsensitive << 0;
3371 QTest::newRow(dataTag: "ulonglong = boundary") << QVariant(qulonglong(-1)) << QVariant(qulonglong(-1)) << Qt::CaseInsensitive << 0;
3372 QTest::newRow(dataTag: "ulonglong >") << QVariant(qulonglong(5)) << QVariant(qulonglong(2)) << Qt::CaseInsensitive << 1;
3373 QTest::newRow(dataTag: "ulonglong > boundary") << QVariant(qulonglong(-1)) << QVariant(qulonglong(2)) << Qt::CaseInsensitive << 1; // boundary
3374
3375 // longlong
3376 QTest::newRow(dataTag: "longlong < boundary") << QVariant(qlonglong(0x8000000000000000LL)) << QVariant(qlonglong(0x7fffffffffffffffLL)) << Qt::CaseInsensitive << -1;
3377 QTest::newRow(dataTag: "longlong <") << QVariant(qlonglong(1)) << QVariant(qlonglong(2)) << Qt::CaseInsensitive << -1;
3378 QTest::newRow(dataTag: "longlong =") << QVariant(qlonglong(2)) << QVariant(qlonglong(2)) << Qt::CaseInsensitive << 0;
3379 QTest::newRow(dataTag: "longlong = 0") << QVariant(qlonglong(0)) << QVariant(qlonglong(0)) << Qt::CaseInsensitive << 0;
3380 QTest::newRow(dataTag: "longlong = boundary") << QVariant(qlonglong(0x8000000000000000LL)) << QVariant(qlonglong(0x8000000000000000LL)) << Qt::CaseInsensitive << 0;
3381 QTest::newRow(dataTag: "longlong >") << QVariant(qlonglong(5)) << QVariant(qlonglong(2)) << Qt::CaseInsensitive << 1;
3382 QTest::newRow(dataTag: "longlong > boundary") << QVariant(qlonglong(0x7fffffffffffffffLL)) << QVariant(qlonglong(0x8000000000000000LL)) << Qt::CaseInsensitive << 1; // boundary
3383
3384 // double (hmm, skips NaNs etc)
3385 QTest::newRow(dataTag: "double < inf 2") << QVariant(-qInf()) << QVariant(qInf()) << Qt::CaseInsensitive << -1;
3386 QTest::newRow(dataTag: "double < inf") << QVariant(1.0) << QVariant(qInf()) << Qt::CaseInsensitive << -1;
3387 QTest::newRow(dataTag: "double <") << QVariant(1.0) << QVariant(2.0) << Qt::CaseInsensitive << -1;
3388 QTest::newRow(dataTag: "double =") << QVariant(2.0) << QVariant(2.0) << Qt::CaseInsensitive << 0;
3389 QTest::newRow(dataTag: "double = 0") << QVariant(0.0) << QVariant(0.0) << Qt::CaseInsensitive << 0;
3390 QTest::newRow(dataTag: "double = inf") << QVariant(qInf()) << QVariant(qInf()) << Qt::CaseInsensitive << 0;
3391 QTest::newRow(dataTag: "double >") << QVariant(5.0) << QVariant(2.0) << Qt::CaseInsensitive << 1;
3392 QTest::newRow(dataTag: "double > inf") << QVariant(qInf()) << QVariant(5.0) << Qt::CaseInsensitive << 1;
3393 QTest::newRow(dataTag: "double > inf 2") << QVariant(0.0) << QVariant(-qInf()) << Qt::CaseInsensitive << 1;
3394 QTest::newRow(dataTag: "double > inf 3") << QVariant(qInf()) << QVariant(-qInf()) << Qt::CaseInsensitive << 1;
3395
3396 // strings
3397 QTest::newRow(dataTag: "string <") << QVariant(QString("a")) << QVariant(QString("b")) << Qt::CaseInsensitive << -1;
3398 QTest::newRow(dataTag: "string <") << QVariant(QString("a")) << QVariant(QString("B")) << Qt::CaseInsensitive << -1;
3399 QTest::newRow(dataTag: "string <") << QVariant(QString("A")) << QVariant(QString("b")) << Qt::CaseInsensitive << -1;
3400 QTest::newRow(dataTag: "string <") << QVariant(QString("A")) << QVariant(QString("B")) << Qt::CaseInsensitive << -1;
3401 QTest::newRow(dataTag: "string < cs") << QVariant(QString("a")) << QVariant(QString("b")) << Qt::CaseSensitive << -1;
3402 QTest::newRow(dataTag: "string < cs 2") << QVariant(QString("A")) << QVariant(QString("b")) << Qt::CaseSensitive << -1;
3403
3404 QTest::newRow(dataTag: "string < length") << QVariant(QString("a")) << QVariant(QString("aa")) << Qt::CaseInsensitive << -1;
3405 QTest::newRow(dataTag: "string < length cs") << QVariant(QString("a")) << QVariant(QString("aa")) << Qt::CaseSensitive << -1;
3406 QTest::newRow(dataTag: "string < length 2") << QVariant(QString("a")) << QVariant(QString("ba")) << Qt::CaseInsensitive << -1;
3407 QTest::newRow(dataTag: "string < length cs 2") << QVariant(QString("a")) << QVariant(QString("ba")) << Qt::CaseSensitive << -1;
3408
3409 QTest::newRow(dataTag: "string aa < b") << QVariant(QString("aa")) << QVariant(QString("b")) << Qt::CaseInsensitive << -1;
3410 QTest::newRow(dataTag: "string aa < b cs") << QVariant(QString("aa")) << QVariant(QString("b")) << Qt::CaseSensitive << -1;
3411
3412 QTest::newRow(dataTag: "string '' < a") << QVariant(QString("")) << QVariant(QString("aa")) << Qt::CaseInsensitive << -1;
3413 QTest::newRow(dataTag: "string '' < aa cs") << QVariant(QString("")) << QVariant(QString("aa")) << Qt::CaseSensitive << -1;
3414 QTest::newRow(dataTag: "string 0 < a") << QVariant(QString()) << QVariant(QString("aa")) << Qt::CaseInsensitive << -1;
3415 QTest::newRow(dataTag: "string 0 < aa cs") << QVariant(QString()) << QVariant(QString("aa")) << Qt::CaseSensitive << -1;
3416
3417 QTest::newRow(dataTag: "string '' = ''") << QVariant(QString("")) << QVariant(QString("")) << Qt::CaseInsensitive << 0;
3418 QTest::newRow(dataTag: "string '' = '' cs") << QVariant(QString("")) << QVariant(QString("")) << Qt::CaseSensitive << 0;
3419 QTest::newRow(dataTag: "string 0 = 0") << QVariant(QString()) << QVariant(QString()) << Qt::CaseInsensitive << 0;
3420 QTest::newRow(dataTag: "string 0 = 0 cs") << QVariant(QString()) << QVariant(QString()) << Qt::CaseSensitive << 0;
3421 QTest::newRow(dataTag: "string a = a") << QVariant(QString("a")) << QVariant(QString("a")) << Qt::CaseInsensitive << 0;
3422 QTest::newRow(dataTag: "string a = a cs") << QVariant(QString("a")) << QVariant(QString("a")) << Qt::CaseSensitive << 0;
3423
3424 // Stringlists
3425 // {} < {"a"} < {"aa"} < {"aa","bb"} < {"aa", "cc"} < {"bb"}
3426
3427 QStringList empty;
3428 QStringList listA("a");
3429 QStringList listAA("aa");
3430 QStringList listAABB;
3431 listAABB << "aa" << "bb";
3432 QStringList listAACC;
3433 listAACC << "aa" << "cc";
3434 QStringList listBB;
3435 listBB << "bb";
3436 QStringList listCCAA;
3437 listCCAA << "cc" << "aa";
3438 QStringList listA2("A");
3439 QStringList listAA2("AA");
3440
3441 QTest::newRow(dataTag: "stringlist {} < {a}") << QVariant(empty) << QVariant(listA) << Qt::CaseInsensitive << -1;
3442 QTest::newRow(dataTag: "stringlist {} < {a} cs") << QVariant(empty) << QVariant(listA) << Qt::CaseSensitive << -1;
3443 QTest::newRow(dataTag: "stringlist {} < {A}") << QVariant(empty) << QVariant(listA2) << Qt::CaseInsensitive << -1;
3444 QTest::newRow(dataTag: "stringlist {} < {A} cs") << QVariant(empty) << QVariant(listA2) << Qt::CaseSensitive << -1;
3445
3446 QTest::newRow(dataTag: "stringlist {a} < {aa}") << QVariant(listA) << QVariant(listAA) << Qt::CaseInsensitive << -1;
3447 QTest::newRow(dataTag: "stringlist {a} < {aa} cs") << QVariant(listA) << QVariant(listAA) << Qt::CaseSensitive << -1;
3448 QTest::newRow(dataTag: "stringlist {a} < {AA}") << QVariant(listA) << QVariant(listAA2) << Qt::CaseInsensitive << -1;
3449 QTest::newRow(dataTag: "stringlist {a} < {AA} cs") << QVariant(listA) << QVariant(listAA2) << Qt::CaseSensitive << -1;
3450
3451 QTest::newRow(dataTag: "stringlist {A} < {aa,bb}") << QVariant(listA2) << QVariant(listAABB) << Qt::CaseInsensitive << -1;
3452 QTest::newRow(dataTag: "stringlist {A} < {aa,bb} cs") << QVariant(listA2) << QVariant(listAABB) << Qt::CaseSensitive << -1;
3453 QTest::newRow(dataTag: "stringlist {aa} < {aa,bb}") << QVariant(listAA) << QVariant(listAABB) << Qt::CaseInsensitive << -1;
3454 QTest::newRow(dataTag: "stringlist {aa} < {aa,bb} cs") << QVariant(listAA) << QVariant(listAABB) << Qt::CaseSensitive << -1;
3455
3456 QTest::newRow(dataTag: "stringlist {aa,bb} < {aa,cc}") << QVariant(listAABB) << QVariant(listAACC) << Qt::CaseInsensitive << -1;
3457 QTest::newRow(dataTag: "stringlist {aa,bb} < {aa,cc} cs") << QVariant(listAABB) << QVariant(listAACC) << Qt::CaseSensitive << -1;
3458
3459 QTest::newRow(dataTag: "stringlist {aa,cc} < {bb}") << QVariant(listAACC) << QVariant(listBB) << Qt::CaseInsensitive << -1;
3460 QTest::newRow(dataTag: "stringlist {aa,cc} < {bb} cs") << QVariant(listAACC) << QVariant(listBB) << Qt::CaseSensitive << -1;
3461
3462 // equality
3463 QTest::newRow(dataTag: "stringlist {} = {}") << QVariant(empty) << QVariant(empty) << Qt::CaseInsensitive << 0;
3464 QTest::newRow(dataTag: "stringlist {} = {} cs") << QVariant(empty) << QVariant(empty) << Qt::CaseSensitive << 0;
3465 QTest::newRow(dataTag: "stringlist {aa} = {aa}") << QVariant(listAA) << QVariant(listAA) << Qt::CaseInsensitive << 0;
3466 QTest::newRow(dataTag: "stringlist {aa} = {AA}") << QVariant(listAA) << QVariant(listAA2) << Qt::CaseInsensitive << 0;
3467 QTest::newRow(dataTag: "stringlist {aa} = {aa} cs") << QVariant(listAA) << QVariant(listAA) << Qt::CaseSensitive << 0;
3468
3469 // Times
3470 QTime t0;
3471 QTime t1(0,0,0,0);
3472 QTime t2(0,59,0,0);
3473 QTime t3(1,0,0,0);
3474 QTime t4(23,59,59,999);
3475
3476 QTest::newRow(dataTag: "times t0 < t1") << QVariant(t0) << QVariant(t1) << Qt::CaseInsensitive << -1;
3477 QTest::newRow(dataTag: "times t1 < t2") << QVariant(t1) << QVariant(t2) << Qt::CaseInsensitive << -1;
3478 QTest::newRow(dataTag: "times t2 < t3") << QVariant(t2) << QVariant(t3) << Qt::CaseInsensitive << -1;
3479 QTest::newRow(dataTag: "times t3 < t4") << QVariant(t3) << QVariant(t4) << Qt::CaseInsensitive << -1;
3480 QTest::newRow(dataTag: "times t0 = t0") << QVariant(t0) << QVariant(t0) << Qt::CaseInsensitive << 0;
3481 QTest::newRow(dataTag: "times t4 = t4") << QVariant(t4) << QVariant(t4) << Qt::CaseInsensitive << 0;
3482
3483 // Dates
3484 QDate d0;
3485 QDate d1 = QDate::fromJulianDay(jd_: 1);
3486 QDate d2(1,1,1);
3487 QDate d3(2011,6,9);
3488 QDate d4 = QDate::fromJulianDay(jd_: 0x7fffffff);
3489 QDate d5 = QDate::fromJulianDay(jd_: 0x80000000);
3490 QDate d6 = QDate::fromJulianDay(jd_: 0xffffffff);
3491
3492 QTest::newRow(dataTag: "dates d0 < d1") << QVariant(d0) << QVariant(d1) << Qt::CaseInsensitive << -1;
3493 QTest::newRow(dataTag: "dates d1 < d2") << QVariant(d1) << QVariant(d2) << Qt::CaseInsensitive << -1;
3494 QTest::newRow(dataTag: "dates d2 < d3") << QVariant(d2) << QVariant(d3) << Qt::CaseInsensitive << -1;
3495 QTest::newRow(dataTag: "dates d3 < d4") << QVariant(d3) << QVariant(d4) << Qt::CaseInsensitive << -1;
3496 QTest::newRow(dataTag: "dates d4 < d5") << QVariant(d4) << QVariant(d5) << Qt::CaseInsensitive << -1;
3497 QTest::newRow(dataTag: "dates d5 < d6") << QVariant(d5) << QVariant(d6) << Qt::CaseInsensitive << -1;
3498 QTest::newRow(dataTag: "dates d0 < d6") << QVariant(d0) << QVariant(d6) << Qt::CaseInsensitive << -1;
3499 QTest::newRow(dataTag: "dates d1 < d6") << QVariant(d1) << QVariant(d6) << Qt::CaseInsensitive << -1;
3500 QTest::newRow(dataTag: "dates d0 = d0") << QVariant(d0) << QVariant(d0) << Qt::CaseInsensitive << 0;
3501 QTest::newRow(dataTag: "dates d1 = d1") << QVariant(d1) << QVariant(d1) << Qt::CaseInsensitive << 0;
3502 QTest::newRow(dataTag: "dates d2 = d2") << QVariant(d2) << QVariant(d2) << Qt::CaseInsensitive << 0;
3503 QTest::newRow(dataTag: "dates d3 = d3") << QVariant(d3) << QVariant(d3) << Qt::CaseInsensitive << 0;
3504 QTest::newRow(dataTag: "dates d4 = d4") << QVariant(d4) << QVariant(d4) << Qt::CaseInsensitive << 0;
3505 QTest::newRow(dataTag: "dates d5 = d5") << QVariant(d5) << QVariant(d5) << Qt::CaseInsensitive << 0;
3506 QTest::newRow(dataTag: "dates d6 = d6") << QVariant(d6) << QVariant(d6) << Qt::CaseInsensitive << 0;
3507
3508 // DateTimes
3509 // Somewhat limited testing here
3510 QDateTime dt0;
3511 QDateTime dt1(d1, t1);
3512 QDateTime dt2(d1, t2);
3513 QDateTime dt3(d4, t4);
3514 QDateTime dt4(d5, t1);
3515 QDateTime dt5(d6, t4); // end of the universe
3516
3517 // Note: this test used to verify that null QDateTime compared less than a non-null date prior to 1AD
3518 // The current Qt behavior is to compare null as the UNIX epoch, so we will follow that
3519 QTest::newRow(dataTag: "datetimes dt0 > dt1") << QVariant(dt0) << QVariant(dt1) << Qt::CaseInsensitive << 1;
3520 QTest::newRow(dataTag: "datetimes dt1 < dt2") << QVariant(dt1) << QVariant(dt2) << Qt::CaseInsensitive << -1;
3521 QTest::newRow(dataTag: "datetimes dt2 < dt3") << QVariant(dt2) << QVariant(dt3) << Qt::CaseInsensitive << -1;
3522 QTest::newRow(dataTag: "datetimes dt3 < dt4") << QVariant(dt3) << QVariant(dt4) << Qt::CaseInsensitive << -1;
3523 QTest::newRow(dataTag: "datetimes dt4 < dt5") << QVariant(dt4) << QVariant(dt5) << Qt::CaseInsensitive << -1;
3524 QTest::newRow(dataTag: "datetimes dt0 < dt5") << QVariant(dt0) << QVariant(dt5) << Qt::CaseInsensitive << -1;
3525 QTest::newRow(dataTag: "datetimes dt1 < dt5") << QVariant(dt1) << QVariant(dt5) << Qt::CaseInsensitive << -1;
3526 QTest::newRow(dataTag: "datetimes dt0 = dt0") << QVariant(dt0) << QVariant(dt0) << Qt::CaseInsensitive << 0;
3527 QTest::newRow(dataTag: "datetimes dt1 = dt1") << QVariant(dt1) << QVariant(dt1) << Qt::CaseInsensitive << 0;
3528 QTest::newRow(dataTag: "datetimes dt2 = dt2") << QVariant(dt2) << QVariant(dt2) << Qt::CaseInsensitive << 0;
3529 QTest::newRow(dataTag: "datetimes dt3 = dt3") << QVariant(dt3) << QVariant(dt3) << Qt::CaseInsensitive << 0;
3530 QTest::newRow(dataTag: "datetimes dt4 = dt4") << QVariant(dt4) << QVariant(dt4) << Qt::CaseInsensitive << 0;
3531 QTest::newRow(dataTag: "datetimes dt5 = dt5") << QVariant(dt5) << QVariant(dt5) << Qt::CaseInsensitive << 0;
3532}
3533
3534QTEST_MAIN(tst_QContactManager)
3535#include "tst_qcontactmanager.moc"
3536

source code of qtpim/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp