tests/auto/qcontactmanager/tst_qcontactmanager.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtTest/QtTest>
       
    43 
       
    44 #include "qtcontacts.h"
       
    45 #include "qcontactchangeset.h"
       
    46 #include "qcontactmanagerdataholder.h"
       
    47 
       
    48 QTM_USE_NAMESPACE
       
    49 // Eventually these will make it into qtestcase.h
       
    50 // but we might need to tweak the timeout values here.
       
    51 #ifndef QTRY_COMPARE
       
    52 #define QTRY_COMPARE(__expr, __expected) \
       
    53     do { \
       
    54         const int __step = 50; \
       
    55         const int __timeout = 5000; \
       
    56         if ((__expr) != (__expected)) { \
       
    57             QTest::qWait(0); \
       
    58         } \
       
    59         for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
       
    60             QTest::qWait(__step); \
       
    61         } \
       
    62         QCOMPARE(__expr, __expected); \
       
    63     } while(0)
       
    64 #endif
       
    65 
       
    66 #ifndef QTRY_VERIFY
       
    67 #define QTRY_VERIFY(__expr) \
       
    68         do { \
       
    69         const int __step = 50; \
       
    70         const int __timeout = 5000; \
       
    71         if (!(__expr)) { \
       
    72             QTest::qWait(0); \
       
    73         } \
       
    74         for (int __i = 0; __i < __timeout && !(__expr); __i+=__step) { \
       
    75             QTest::qWait(__step); \
       
    76         } \
       
    77         QVERIFY(__expr); \
       
    78     } while(0)
       
    79 #endif
       
    80 
       
    81 
       
    82 #define QTRY_WAIT(code, __expr) \
       
    83         do { \
       
    84         const int __step = 50; \
       
    85         const int __timeout = 5000; \
       
    86         if (!(__expr)) { \
       
    87             QTest::qWait(0); \
       
    88         } \
       
    89         for (int __i = 0; __i < __timeout && !(__expr); __i+=__step) { \
       
    90             do { code } while(0); \
       
    91             QTest::qWait(__step); \
       
    92         } \
       
    93     } while(0)
       
    94 
       
    95 #define QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(params)  params.remove(QString::fromAscii(QTCONTACTS_VERSION_NAME)); \
       
    96                                                           params.remove(QString::fromAscii(QTCONTACTS_IMPLEMENTATION_VERSION_NAME))
       
    97 
       
    98 //TESTED_CLASS=
       
    99 //TESTED_FILES=
       
   100 
       
   101 // to get QFETCH to work with the template expression...
       
   102 typedef QMap<QString,QString> tst_QContactManager_QStringMap;
       
   103 Q_DECLARE_METATYPE(tst_QContactManager_QStringMap)
       
   104 Q_DECLARE_METATYPE(QList<QContactLocalId>)
       
   105 
       
   106 /* A class that no backend can support */
       
   107 class UnsupportedMetatype {
       
   108     int foo;
       
   109 };
       
   110 Q_DECLARE_METATYPE(UnsupportedMetatype)
       
   111 Q_DECLARE_METATYPE(QContact)
       
   112 Q_DECLARE_METATYPE(QContactManager::Error)
       
   113 
       
   114 class tst_QContactManager : public QObject
       
   115 {
       
   116 Q_OBJECT
       
   117 
       
   118 public:
       
   119     tst_QContactManager();
       
   120     virtual ~tst_QContactManager();
       
   121 
       
   122 private:
       
   123     void dumpContactDifferences(const QContact& a, const QContact& b);
       
   124     void dumpContact(const QContact &c);
       
   125     void dumpContacts(QContactManager *cm);
       
   126     bool isSuperset(const QContact& ca, const QContact& cb);
       
   127     QList<QContactDetail> removeAllDefaultDetails(const QList<QContactDetail>& details);
       
   128     void addManagers(); // add standard managers to the data
       
   129     QContact createContact(QContactDetailDefinition nameDef, QString firstName, QString lastName, QString phoneNumber);
       
   130     void saveContactName(QContact *contact, QContactDetailDefinition nameDef, QContactName *contactName, const QString &name) const;
       
   131 
       
   132     QScopedPointer<QContactManagerDataHolder> managerDataHolder;
       
   133 
       
   134 public slots:
       
   135     void initTestCase();
       
   136     void cleanupTestCase();
       
   137 private slots:
       
   138 
       
   139     void doDump();
       
   140     void doDump_data() {addManagers();}
       
   141 
       
   142     void doDumpSchema();
       
   143     void doDumpSchema_data() {addManagers();}
       
   144 
       
   145     /* Special test with special data */
       
   146     void uriParsing();
       
   147     void nameSynthesis();
       
   148     void compatibleContact();
       
   149 
       
   150     /* Tests that are run on all managers */
       
   151     void metadata();
       
   152     void nullIdOperations();
       
   153     void add();
       
   154     void update();
       
   155     void remove();
       
   156     void batch();
       
   157     void signalEmission();
       
   158     void detailDefinitions();
       
   159     void displayName();
       
   160     void actionPreferences();
       
   161     void selfContactId();
       
   162     void detailOrders();
       
   163     void relationships();
       
   164     void contactType();
       
   165 
       
   166     /* Tests that take no data */
       
   167     void contactValidation();
       
   168     void errorStayingPut();
       
   169     void ctors();
       
   170     void invalidManager();
       
   171     void memoryManager();
       
   172     void changeSet();
       
   173     void fetchHint();
       
   174 
       
   175     /* Special test with special data */
       
   176     void uriParsing_data();
       
   177     void nameSynthesis_data();
       
   178     void compatibleContact_data();
       
   179     /* Tests that are run on all managers */
       
   180     void metadata_data() {addManagers();}
       
   181     void nullIdOperations_data() {addManagers();}
       
   182     void add_data() {addManagers();}
       
   183     void update_data() {addManagers();}
       
   184     void remove_data() {addManagers();}
       
   185     void batch_data() {addManagers();}
       
   186     void signalEmission_data() {addManagers();}
       
   187     void detailDefinitions_data() {addManagers();}
       
   188     void displayName_data() {addManagers();}
       
   189     void actionPreferences_data() {addManagers();}
       
   190     void selfContactId_data() {addManagers();}
       
   191     void detailOrders_data() {addManagers();}
       
   192     void relationships_data() {addManagers();}
       
   193     void contactType_data() {addManagers();}
       
   194 };
       
   195 
       
   196 tst_QContactManager::tst_QContactManager()
       
   197 {
       
   198 }
       
   199 
       
   200 tst_QContactManager::~tst_QContactManager()
       
   201 {
       
   202 }
       
   203 
       
   204 void tst_QContactManager::initTestCase()
       
   205 {
       
   206     managerDataHolder.reset(new QContactManagerDataHolder());
       
   207 
       
   208     /* Make sure these other test plugins are NOT loaded by default */
       
   209     // These are now removed from the list of managers in addManagers()
       
   210     //QVERIFY(!QContactManager::availableManagers().contains("testdummy"));
       
   211     //QVERIFY(!QContactManager::availableManagers().contains("teststaticdummy"));
       
   212     //QVERIFY(!QContactManager::availableManagers().contains("maliciousplugin"));
       
   213 }
       
   214 
       
   215 void tst_QContactManager::cleanupTestCase()
       
   216 {
       
   217     managerDataHolder.reset(0);
       
   218 }
       
   219 
       
   220 void tst_QContactManager::dumpContactDifferences(const QContact& ca, const QContact& cb)
       
   221 {
       
   222     // Try to narrow down the differences
       
   223     QContact a(ca);
       
   224     QContact b(cb);
       
   225 
       
   226     QContactName n1 = a.detail(QContactName::DefinitionName);
       
   227     QContactName n2 = b.detail(QContactName::DefinitionName);
       
   228 
       
   229     // Check the name components in more detail
       
   230     QCOMPARE(n1.firstName(), n2.firstName());
       
   231     QCOMPARE(n1.middleName(), n2.middleName());
       
   232     QCOMPARE(n1.lastName(), n2.lastName());
       
   233     QCOMPARE(n1.prefix(), n2.prefix());
       
   234     QCOMPARE(n1.suffix(), n2.suffix());
       
   235     QCOMPARE(n1.customLabel(), n2.customLabel());
       
   236 
       
   237     // Check the display label
       
   238     QCOMPARE(a.displayLabel(), b.displayLabel());
       
   239 
       
   240     // Now look at the rest
       
   241     QList<QContactDetail> aDetails = a.details();
       
   242     QList<QContactDetail> bDetails = b.details();
       
   243 
       
   244     // They can be in any order, so loop
       
   245     // First remove any matches
       
   246     foreach(QContactDetail d, aDetails) {
       
   247         foreach(QContactDetail d2, bDetails) {
       
   248             if(d == d2) {
       
   249                 a.removeDetail(&d);
       
   250                 b.removeDetail(&d2);
       
   251                 break;
       
   252             }
       
   253         }
       
   254     }
       
   255 
       
   256     // Now dump the extra details that were unmatched in A (note that DisplayLabel and Type are always present).
       
   257     aDetails = a.details();
       
   258     bDetails = b.details();
       
   259     foreach(QContactDetail d, aDetails) {
       
   260         if (d.definitionName() != QContactDisplayLabel::DefinitionName && d.definitionName() != QContactType::DefinitionName)
       
   261             qDebug() << "A contact had extra detail:" << d.definitionName() << d.variantValues();
       
   262     }
       
   263     // and same for B
       
   264     foreach(QContactDetail d, bDetails) {
       
   265         if (d.definitionName() != QContactDisplayLabel::DefinitionName && d.definitionName() != QContactType::DefinitionName)
       
   266             qDebug() << "B contact had extra detail:" << d.definitionName() << d.variantValues();
       
   267     }
       
   268 
       
   269     // now test specifically the display label and the type
       
   270     if (a.displayLabel() != b.displayLabel()) {
       
   271         qDebug() << "A contact display label =" << a.displayLabel();
       
   272         qDebug() << "B contact display label =" << b.displayLabel();
       
   273     }
       
   274     if (a.type() != b.type()) {
       
   275         qDebug() << "A contact type =" << a.type();
       
   276         qDebug() << "B contact type =" << b.type();
       
   277     }
       
   278 }
       
   279 
       
   280 bool tst_QContactManager::isSuperset(const QContact& ca, const QContact& cb)
       
   281 {
       
   282     // returns true if contact ca is a superset of contact cb
       
   283     // we use this test instead of equality because dynamic information
       
   284     // such as presence/location, and synthesised information such as
       
   285     // display label and (possibly) type, may differ between a contact
       
   286     // in memory and the contact in the managed store.
       
   287 
       
   288     QContact a(ca);
       
   289     QContact b(cb);
       
   290     QList<QContactDetail> aDetails = a.details();
       
   291     QList<QContactDetail> bDetails = b.details();
       
   292 
       
   293     // They can be in any order, so loop
       
   294     // First remove any matches
       
   295     foreach(QContactDetail d, aDetails) {
       
   296         foreach(QContactDetail d2, bDetails) {
       
   297             if(d == d2) {
       
   298                 a.removeDetail(&d);
       
   299                 b.removeDetail(&d2);
       
   300                 break;
       
   301             }
       
   302         }
       
   303     }
       
   304 
       
   305     // Second remove any superset matches (eg, backend adds a field)
       
   306     aDetails = a.details();
       
   307     bDetails = b.details();
       
   308     foreach (QContactDetail d, aDetails) {
       
   309         foreach (QContactDetail d2, bDetails) {
       
   310             if (d.definitionName() == d2.definitionName()) {
       
   311                 bool canRemove = true;
       
   312                 QMap<QString, QVariant> d2map = d2.variantValues();
       
   313                 foreach (QString key, d2map.keys()) {
       
   314                     if (d.value(key) != d2.value(key)) {
       
   315                         // d can have _more_ keys than d2,
       
   316                         // but not _less_; and it cannot
       
   317                         // change the value.
       
   318                         canRemove = false;
       
   319                     }
       
   320                 }
       
   321 
       
   322                 if (canRemove) {
       
   323                     // if we get to here, we can remove the details.
       
   324                     a.removeDetail(&d);
       
   325                     b.removeDetail(&d2);
       
   326                     break;
       
   327                 }
       
   328             }
       
   329         }
       
   330     }
       
   331 
       
   332     // check for contact type updates
       
   333     if (!a.type().isEmpty())
       
   334         if (!b.type().isEmpty())
       
   335             if (a.type() != b.type())
       
   336                 return false; // nonempty type is different.
       
   337 
       
   338     // Now check to see if b has any details remaining; if so, a is not a superset.
       
   339     // Note that the DisplayLabel and Type can never be removed.
       
   340     if (b.details().size() > 2
       
   341             || (b.details().size() == 2 && (b.details().value(0).definitionName() != QContactDisplayLabel::DefinitionName
       
   342                                             || b.details().value(1).definitionName() != QContactType::DefinitionName)))
       
   343         return false;
       
   344     return true;
       
   345 }
       
   346 
       
   347 void tst_QContactManager::dumpContact(const QContact& contact)
       
   348 {
       
   349     QContactManager m;
       
   350     qDebug() << "Contact: " << contact.id().localId() << "(" << m.synthesizedContactDisplayLabel(contact) << ")";
       
   351     QList<QContactDetail> details = contact.details();
       
   352     foreach(QContactDetail d, details) {
       
   353         qDebug() << "  " << d.definitionName() << ":";
       
   354         qDebug() << "    Vals:" << d.variantValues();
       
   355     }
       
   356 }
       
   357 
       
   358 void tst_QContactManager::dumpContacts(QContactManager *cm)
       
   359 {
       
   360     QList<QContactLocalId> ids = cm->contactIds();
       
   361 
       
   362     qDebug() << "There are" << ids.count() << "contacts in" << cm->managerUri();
       
   363 
       
   364     foreach(QContactLocalId id, ids) {
       
   365         QContact c = cm->contact(id);
       
   366         dumpContact(c);
       
   367     }
       
   368 }
       
   369 
       
   370 void tst_QContactManager::uriParsing_data()
       
   371 {
       
   372     QTest::addColumn<QString>("uri");
       
   373     QTest::addColumn<bool>("good"); // is this a good uri or not
       
   374     QTest::addColumn<QString>("manager");
       
   375     QTest::addColumn<QMap<QString, QString> >("parameters");
       
   376 
       
   377     QMap<QString, QString> inparameters;
       
   378     inparameters.insert("foo", "bar");
       
   379     inparameters.insert("bazflag", QString());
       
   380     inparameters.insert("bar", "glob");
       
   381 
       
   382     QMap<QString, QString> inparameters2;
       
   383     inparameters2.insert("this has spaces", QString());
       
   384     inparameters2.insert("and& an", " &amp;");
       
   385     inparameters2.insert("and an ", "=quals");
       
   386 
       
   387     QTest::newRow("built") << QContactManager::buildUri("manager", inparameters) << true << "manager" << inparameters;
       
   388     QTest::newRow("built with escaped parameters") << QContactManager::buildUri("manager", inparameters2) << true << "manager" << inparameters2;
       
   389     QTest::newRow("no scheme") << "this should not split" << false << QString() << tst_QContactManager_QStringMap();
       
   390     QTest::newRow("wrong scheme") << "invalidscheme:foo bar" << false << QString() << tst_QContactManager_QStringMap();
       
   391     QTest::newRow("right scheme, no colon") << "qtcontacts" << false << QString() << tst_QContactManager_QStringMap();
       
   392     QTest::newRow("no manager, colon, no params") << "qtcontacts::" << false  << "manager" << tst_QContactManager_QStringMap();
       
   393     QTest::newRow("yes manager, no colon, no params") << "qtcontacts:manager" << true << "manager" << tst_QContactManager_QStringMap();
       
   394     QTest::newRow("yes manager, yes colon, no params") << "qtcontacts:manager:" << true << "manager"<< tst_QContactManager_QStringMap();
       
   395     QTest::newRow("yes params") << "qtcontacts:manager:foo=bar&bazflag=&bar=glob" << true << "manager" << inparameters;
       
   396     QTest::newRow("yes params but misformed") << "qtcontacts:manager:foo=bar&=gloo&bar=glob" << false << "manager" << inparameters;
       
   397     QTest::newRow("yes params but misformed 2") << "qtcontacts:manager:=&=gloo&bar=glob" << false << "manager" << inparameters;
       
   398     QTest::newRow("yes params but misformed 3") << "qtcontacts:manager:==" << false << "manager" << inparameters;
       
   399     QTest::newRow("yes params but misformed 4") << "qtcontacts:manager:&&" << false << "manager" << inparameters;
       
   400     QTest::newRow("yes params but misformed 5") << "qtcontacts:manager:&goo=bar" << false << "manager" << inparameters;
       
   401     QTest::newRow("yes params but misformed 6") << "qtcontacts:manager:goo&bar" << false << "manager" << inparameters;
       
   402     QTest::newRow("yes params but misformed 7") << "qtcontacts:manager:goo&bar&gob" << false << "manager" << inparameters;
       
   403     QTest::newRow("yes params but misformed 8") << "qtcontacts:manager:==&&==&goo=bar" << false << "manager" << inparameters;
       
   404     QTest::newRow("yes params but misformed 9") << "qtcontacts:manager:foo=bar=baz" << false << "manager" << inparameters;
       
   405     QTest::newRow("yes params but misformed 10") << "qtcontacts:manager:foo=bar=baz=glob" << false << "manager" << inparameters;
       
   406     QTest::newRow("no manager but yes params") << "qtcontacts::foo=bar&bazflag=&bar=glob" << false << QString() << inparameters;
       
   407     QTest::newRow("no manager or params") << "qtcontacts::" << false << QString() << inparameters;
       
   408     QTest::newRow("no manager or params or colon") << "qtcontacts:" << false << QString() << inparameters;
       
   409 }
       
   410 
       
   411 void tst_QContactManager::addManagers()
       
   412 {
       
   413     QTest::addColumn<QString>("uri");
       
   414 
       
   415     QStringList managers = QContactManager::availableManagers();
       
   416 
       
   417     /* Known one that will not pass */
       
   418     managers.removeAll("invalid");
       
   419     managers.removeAll("testdummy");
       
   420     managers.removeAll("teststaticdummy");
       
   421     managers.removeAll("maliciousplugin");
       
   422 
       
   423     foreach(QString mgr, managers) {
       
   424         QMap<QString, QString> params;
       
   425         QTest::newRow(QString("mgr='%1'").arg(mgr).toLatin1().constData()) << QContactManager::buildUri(mgr, params);
       
   426         if (mgr == "memory") {
       
   427             params.insert("id", "tst_QContactManager");
       
   428             QTest::newRow(QString("mgr='%1', params").arg(mgr).toLatin1().constData()) << QContactManager::buildUri(mgr, params);
       
   429         }
       
   430     }
       
   431 }
       
   432 
       
   433 /*
       
   434  * Helper method for creating a QContact instance with name and phone number
       
   435  * details. Name is generated according to the detail definition assuming that
       
   436  * either first and last name or custom label is supported.
       
   437  */
       
   438 QContact tst_QContactManager::createContact(
       
   439     QContactDetailDefinition nameDef,
       
   440     QString firstName,
       
   441     QString lastName,
       
   442     QString phoneNumber)
       
   443 {
       
   444     QContact contact;
       
   445 
       
   446     if(!firstName.isEmpty() || !lastName.isEmpty()) {
       
   447         QContactName n;
       
   448 
       
   449         if(nameDef.fields().contains(QContactName::FieldFirstName)
       
   450             && nameDef.fields().contains(QContactName::FieldFirstName)) {
       
   451             n.setFirstName(firstName);
       
   452             n.setLastName(lastName);
       
   453         } else if(nameDef.fields().contains(QContactName::FieldCustomLabel)) {
       
   454             n.setCustomLabel(firstName + " " + lastName);
       
   455         } else {
       
   456             // assume that either first and last name or custom label is supported
       
   457             QTest::qWarn("Neither custom label nor first name/last name supported!");
       
   458             return QContact();
       
   459         }
       
   460         contact.saveDetail(&n);
       
   461     }
       
   462 
       
   463     if (!phoneNumber.isEmpty()) {
       
   464         QContactPhoneNumber ph;
       
   465         ph.setNumber(phoneNumber);
       
   466         contact.saveDetail(&ph);
       
   467     }
       
   468 
       
   469     return contact;
       
   470 }
       
   471 
       
   472 void tst_QContactManager::saveContactName(QContact *contact, QContactDetailDefinition nameDef, QContactName *contactName, const QString &name) const
       
   473 {
       
   474     // check which name fields are supported in the following order:
       
   475     // 1. custom label, 2. first name, 3. last name
       
   476     if(nameDef.fields().contains(QContactName::FieldCustomLabel)) {
       
   477         contactName->setCustomLabel(name);
       
   478     } else if(nameDef.fields().contains(QContactName::FieldFirstName)) {
       
   479         contactName->setFirstName(name);
       
   480     } else if(nameDef.fields().contains(QContactName::FieldLastName)) {
       
   481         contactName->setLastName(name);
       
   482     } else {
       
   483         // Assume that at least one of the above name fields is supported by the backend
       
   484         QVERIFY(false);
       
   485     }
       
   486     contact->saveDetail(contactName);
       
   487 }
       
   488 
       
   489 void tst_QContactManager::metadata()
       
   490 {
       
   491     // ensure that the backend is publishing its metadata (name / parameters / uri) correctly
       
   492     QFETCH(QString, uri);
       
   493     QScopedPointer<QContactManager> cm(new QContactManager("memory"));
       
   494     QVERIFY(QContactManager::buildUri(cm->managerName(), cm->managerParameters()) == cm->managerUri());
       
   495 }
       
   496 
       
   497 
       
   498 void tst_QContactManager::nullIdOperations()
       
   499 {
       
   500     QFETCH(QString, uri);
       
   501     QScopedPointer<QContactManager> cm(new QContactManager("memory"));
       
   502     QVERIFY(!cm->removeContact(QContactLocalId()));
       
   503     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
   504 
       
   505 
       
   506     QContact c = cm->contact(QContactLocalId());
       
   507     QVERIFY(c.id() == QContactId());
       
   508     QVERIFY(c.isEmpty());
       
   509     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
   510 }
       
   511 
       
   512 void tst_QContactManager::uriParsing()
       
   513 {
       
   514     QFETCH(QString, uri);
       
   515     QFETCH(bool, good);
       
   516     QFETCH(QString, manager);
       
   517     QFETCH(tst_QContactManager_QStringMap, parameters);
       
   518 
       
   519     QString outmanager;
       
   520     QMap<QString, QString> outparameters;
       
   521 
       
   522     if (good) {
       
   523         /* Good split */
       
   524         /* Test splitting */
       
   525         QVERIFY(QContactManager::parseUri(uri, 0, 0)); // no out parms
       
   526 
       
   527         // 1 out param
       
   528         QVERIFY(QContactManager::parseUri(uri, &outmanager, 0));
       
   529         QCOMPARE(manager, outmanager);
       
   530         QVERIFY(QContactManager::parseUri(uri, 0, &outparameters));
       
   531 
       
   532         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   533 
       
   534         QCOMPARE(parameters, outparameters);
       
   535 
       
   536         outmanager.clear();
       
   537         outparameters.clear();
       
   538         QVERIFY(QContactManager::parseUri(uri, &outmanager, &outparameters));
       
   539 
       
   540         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   541 
       
   542         QCOMPARE(manager, outmanager);
       
   543         QCOMPARE(parameters, outparameters);
       
   544     } else {
       
   545         /* bad splitting */
       
   546         outmanager.clear();
       
   547         outparameters.clear();
       
   548         QVERIFY(QContactManager::parseUri(uri, 0, 0) == false);
       
   549         QVERIFY(QContactManager::parseUri(uri, &outmanager, 0) == false);
       
   550         QVERIFY(outmanager.isEmpty());
       
   551         QVERIFY(QContactManager::parseUri(uri, 0, &outparameters) == false);
       
   552         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   553         QVERIFY(outparameters.isEmpty());
       
   554 
       
   555         /* make sure the in parameters don't change with a bad split */
       
   556         outmanager = manager;
       
   557         outparameters = parameters;
       
   558         QVERIFY(QContactManager::parseUri(uri, &outmanager, 0) == false);
       
   559         QCOMPARE(manager, outmanager);
       
   560         QVERIFY(QContactManager::parseUri(uri, 0, &outparameters) == false);
       
   561         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   562         QCOMPARE(parameters, outparameters);
       
   563     }
       
   564 }
       
   565 
       
   566 void tst_QContactManager::ctors()
       
   567 {
       
   568     /* test the different ctors to make sure we end up with the same uri */
       
   569     QVERIFY(QContactManager::availableManagers().count() > 1); // invalid + something else
       
   570     QVERIFY(QContactManager::availableManagers().contains("invalid"));
       
   571     QString defaultStore = QContactManager::availableManagers().value(0);
       
   572     QVERIFY(defaultStore != "invalid");
       
   573 
       
   574     qDebug() << "Available managers:" << QContactManager::availableManagers();
       
   575 
       
   576     QMap<QString, QString> randomParameters;
       
   577     randomParameters.insert("something", "old");
       
   578     randomParameters.insert("something...", "new");
       
   579     randomParameters.insert("something ", "borrowed");
       
   580     randomParameters.insert(" something", "blue");
       
   581 
       
   582     QObject parent;
       
   583 
       
   584     QContactManager cm; // default
       
   585     QContactManager cm2(defaultStore);
       
   586     QContactManager cm3(defaultStore, QMap<QString, QString>());
       
   587     QContactManager cm4(cm.managerUri()); // should fail
       
   588 
       
   589     QScopedPointer<QContactManager> cm5(QContactManager::fromUri(QContactManager::buildUri(defaultStore, QMap<QString, QString>())));
       
   590     QScopedPointer<QContactManager> cm6(QContactManager::fromUri(cm.managerUri())); // uri is not a name; should fail.
       
   591     QScopedPointer<QContactManager> cm9(QContactManager::fromUri(QString(), &parent));
       
   592 
       
   593     QVERIFY(cm9->parent() == &parent);
       
   594 
       
   595     /* OLD TEST WAS THIS: */
       
   596     //QCOMPARE(cm.managerUri(), cm2.managerUri());
       
   597     //QCOMPARE(cm.managerUri(), cm3.managerUri());
       
   598     //QCOMPARE(cm.managerUri(), cm5->managerUri());
       
   599     //QCOMPARE(cm.managerUri(), cm6->managerUri());
       
   600     //QCOMPARE(cm.managerUri(), cm9->managerUri());
       
   601     /* NEW TEST IS THIS: Test that the names of the managers are the same */
       
   602     QCOMPARE(cm.managerName(), cm2.managerName());
       
   603     QCOMPARE(cm.managerName(), cm3.managerName());
       
   604     QCOMPARE(cm.managerName(), cm5->managerName());
       
   605     QCOMPARE(cm.managerName(), cm6->managerName());
       
   606     QCOMPARE(cm.managerName(), cm9->managerName());
       
   607 
       
   608     QVERIFY(cm.managerUri() != cm4.managerUri()); // don't pass a uri to the ctor
       
   609 
       
   610     /* Test that we get invalid stores when we do silly things */
       
   611     QContactManager em("non existent");
       
   612     QContactManager em2("non existent", QMap<QString, QString>());
       
   613     QContactManager em3("memory", randomParameters);
       
   614 
       
   615     /* Also invalid, since we don't have one of these anyway */
       
   616     QScopedPointer<QContactManager> em4(QContactManager::fromUri("invalid uri"));
       
   617     QScopedPointer<QContactManager> em5(QContactManager::fromUri(QContactManager::buildUri("nonexistent", QMap<QString, QString>())));
       
   618     QScopedPointer<QContactManager> em6(QContactManager::fromUri(em3.managerUri()));
       
   619 
       
   620 
       
   621     /*
       
   622      * Sets of stores that should be equivalent:
       
   623      * - 1, 2, 4, 5
       
   624      * - 3, 6
       
   625      */
       
   626 
       
   627     /* First some URI testing for equivalent stores */
       
   628     QVERIFY(em.managerUri() == em2.managerUri());
       
   629     QVERIFY(em.managerUri() == em5->managerUri());
       
   630     QVERIFY(em.managerUri() == em4->managerUri());
       
   631     QVERIFY(em2.managerUri() == em4->managerUri());
       
   632     QVERIFY(em2.managerUri() == em5->managerUri());
       
   633     QVERIFY(em4->managerUri() == em5->managerUri());
       
   634 
       
   635     QVERIFY(em3.managerUri() == em6->managerUri());
       
   636 
       
   637     /* Test the stores that should not be the same */
       
   638     QVERIFY(em.managerUri() != em3.managerUri());
       
   639     QVERIFY(em.managerUri() != em6->managerUri());
       
   640 
       
   641     /* now the components */
       
   642     QCOMPARE(em.managerName(), QString("invalid"));
       
   643     QCOMPARE(em2.managerName(), QString("invalid"));
       
   644     QCOMPARE(em3.managerName(), QString("memory"));
       
   645     QCOMPARE(em4->managerName(), QString("invalid"));
       
   646     QCOMPARE(em5->managerName(), QString("invalid"));
       
   647     QCOMPARE(em6->managerName(), QString("memory"));
       
   648     QCOMPARE(em.managerParameters(), tst_QContactManager_QStringMap());
       
   649     QCOMPARE(em2.managerParameters(), tst_QContactManager_QStringMap());
       
   650     QCOMPARE(em4->managerParameters(), tst_QContactManager_QStringMap());
       
   651     QCOMPARE(em5->managerParameters(), tst_QContactManager_QStringMap());
       
   652     QCOMPARE(em3.managerParameters(), em6->managerParameters()); // memory engine discards the given params, replaces with id.
       
   653 
       
   654 
       
   655     // Finally test the platform specific engines are actually the defaults
       
   656 #if defined(Q_OS_SYMBIAN)
       
   657     QCOMPARE(defaultStore, QString("symbian"));
       
   658 #elif defined(Q_WS_MAEMO_6)
       
   659     QCOMPARE(defaultStore, QString("tracker"));
       
   660 #elif defined(Q_WS_MAEMO_5)
       
   661     QCOMPARE(defaultStore, QString("maemo5"));
       
   662 #elif defined(Q_OS_WINCE)
       
   663     QCOMPARE(defaultStore, QString("wince"));
       
   664 #else
       
   665     QCOMPARE(defaultStore, QString("memory"));
       
   666 #endif
       
   667 }
       
   668 
       
   669 void tst_QContactManager::doDump()
       
   670 {
       
   671     // Only do this if it has been explicitly selected
       
   672     if (QCoreApplication::arguments().contains("doDump")) {
       
   673         QFETCH(QString, uri);
       
   674         QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   675 
       
   676         dumpContacts(cm.data());
       
   677     }
       
   678 }
       
   679 
       
   680 Q_DECLARE_METATYPE(QVariant)
       
   681 
       
   682 void tst_QContactManager::doDumpSchema()
       
   683 {
       
   684     // Only do this if it has been explicitly selected
       
   685     if (QCoreApplication::arguments().contains("doDumpSchema")) {
       
   686         QFETCH(QString, uri);
       
   687         QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   688 
       
   689         // Get the schema for each supported type
       
   690         foreach(QString type, cm->supportedContactTypes()) {
       
   691             QMap<QString, QContactDetailDefinition> defs = cm->detailDefinitions(type);
       
   692 
       
   693             foreach(QContactDetailDefinition def, defs.values()) {
       
   694                 if (def.isUnique())
       
   695                     qDebug() << QString("%2::%1 (Unique) {").arg(def.name()).arg(type).toAscii().constData();
       
   696                 else
       
   697                     qDebug() << QString("%2::%1 {").arg(def.name()).arg(type).toAscii().constData();
       
   698                 QMap<QString, QContactDetailFieldDefinition> fields = def.fields();
       
   699 
       
   700                 foreach(QString fname, fields.keys()) {
       
   701                     QContactDetailFieldDefinition field = fields.value(fname);
       
   702 
       
   703                     if (field.allowableValues().count() > 0) {
       
   704                         // Make some pretty output
       
   705                         QStringList allowedList;
       
   706                         foreach(QVariant var, field.allowableValues()) {
       
   707                             QString allowed;
       
   708                             if (var.type() == QVariant::String)
       
   709                                 allowed = QString("'%1'").arg(var.toString());
       
   710                             else if (var.type() == QVariant::StringList)
       
   711                                 allowed = QString("'%1'").arg(var.toStringList().join(","));
       
   712                             else {
       
   713                                 // use the textstream <<
       
   714                                 QDebug dbg(&allowed);
       
   715                                 dbg << var;
       
   716                             }
       
   717                             allowedList.append(allowed);
       
   718                         }
       
   719 
       
   720                         qDebug() << QString("   %2 %1 {%3}").arg(fname).arg(QMetaType::typeName(field.dataType())).arg(allowedList.join(",")).toAscii().constData();
       
   721                     } else
       
   722                         qDebug() << QString("   %2 %1").arg(fname).arg(QMetaType::typeName(field.dataType())).toAscii().constData();
       
   723                 }
       
   724 
       
   725                 qDebug() << "}";
       
   726             }
       
   727         }
       
   728     }
       
   729 }
       
   730 
       
   731 void tst_QContactManager::add()
       
   732 {
       
   733     QFETCH(QString, uri);
       
   734     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   735 
       
   736     QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
   737     QContact alice = createContact(nameDef, "Alice", "inWonderland", "1234567");
       
   738     int currCount = cm->contactIds().count();
       
   739     QVERIFY(cm->saveContact(&alice));
       
   740     QVERIFY(cm->error() == QContactManager::NoError);
       
   741 
       
   742     QVERIFY(!alice.id().managerUri().isEmpty());
       
   743     QVERIFY(alice.id().localId() != 0);
       
   744     QCOMPARE(cm->contactIds().count(), currCount+1);
       
   745 
       
   746     QContact added = cm->contact(alice.id().localId());
       
   747     QVERIFY(added.id() == alice.id());
       
   748     
       
   749     if (!isSuperset(added, alice)) {
       
   750         dumpContacts(cm.data());
       
   751         dumpContactDifferences(added, alice);
       
   752         QCOMPARE(added, alice);
       
   753     }
       
   754 
       
   755     // now try adding a contact that does not exist in the database with non-zero id
       
   756     if (cm->managerName() == "symbiansim") {
       
   757         // TODO: symbiansim backend fails this test currently. Will be fixed later.
       
   758         QWARN("This manager has a known issue with saving a non-zero id contact. Skipping this test step.");
       
   759     } else {
       
   760         QContact nonexistent = createContact(nameDef, "nonexistent", "contact", "");
       
   761         QVERIFY(cm->saveContact(&nonexistent));       // should work
       
   762         QVERIFY(cm->removeContact(nonexistent.id().localId())); // now nonexistent has an id which does not exist
       
   763         QVERIFY(!cm->saveContact(&nonexistent));      // hence, should fail
       
   764         QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
       
   765         nonexistent.setId(QContactId());
       
   766         QVERIFY(cm->saveContact(&nonexistent));       // after setting id to zero, should save
       
   767         QVERIFY(cm->removeContact(nonexistent.id().localId()));
       
   768     }
       
   769 
       
   770     // now try adding a "megacontact"
       
   771     // - get list of all definitions supported by the manager
       
   772     // - add one detail of each definition to a contact
       
   773     // - save the contact
       
   774     // - read it back
       
   775     // - ensure that it's the same.
       
   776     QContact megacontact;
       
   777     QMap<QString, QContactDetailDefinition> defmap = cm->detailDefinitions();
       
   778     QList<QContactDetailDefinition> defs = defmap.values();
       
   779     foreach (const QContactDetailDefinition def, defs) {
       
   780 
       
   781         // Leave these warnings here - might need an API for this
       
   782         // XXX FIXME: access constraint reporting as moved to the detail itself
       
   783         //if (def.accessConstraint() == QContactDetailDefinition::ReadOnly) {
       
   784         //    continue;
       
   785         //}
       
   786 
       
   787         if (cm->managerName() == "maemo5") {
       
   788             // The maemo5 backend only supports reading of Guid and QCOA
       
   789             if (def.name() == QContactGuid::DefinitionName)
       
   790                 continue;
       
   791             if (def.name() == QContactOnlineAccount::DefinitionName)
       
   792                 continue;
       
   793 	    if (def.name() == QContactPresence::DefinitionName)
       
   794                 continue;
       
   795         }
       
   796 
       
   797         // This is probably read-only
       
   798         if (def.name() == QContactTimestamp::DefinitionName)
       
   799             continue;
       
   800 
       
   801         // otherwise, create a new detail of the given type and save it to the contact
       
   802         QContactDetail det(def.name());
       
   803         QMap<QString, QContactDetailFieldDefinition> fieldmap = def.fields();
       
   804         QStringList fieldKeys = fieldmap.keys();
       
   805         foreach (const QString& fieldKey, fieldKeys) {
       
   806             // get the field, and check to see that it's not constrained.
       
   807             QContactDetailFieldDefinition currentField = fieldmap.value(fieldKey);
       
   808             
       
   809             // Don't test detail uris as these are manager specific
       
   810             if (fieldKey == QContactDetail::FieldDetailUri)
       
   811                 continue;
       
   812 
       
   813             // Special case: phone number.
       
   814             if (def.name() == QContactPhoneNumber::DefinitionName &&
       
   815                 fieldKey == QContactPhoneNumber::FieldNumber) {
       
   816                 det.setValue(fieldKey, "+3581234567890");
       
   817                 continue;
       
   818             }
       
   819 
       
   820             // Attempt to create a worthy value
       
   821             if (!currentField.allowableValues().isEmpty()) {
       
   822                 // we want to save a value that will be accepted.
       
   823                 if (currentField.dataType() == QVariant::StringList)
       
   824                     det.setValue(fieldKey, QStringList() << currentField.allowableValues().first().toString());
       
   825                 else if (currentField.dataType() == QVariant::List)
       
   826                     det.setValue(fieldKey, QVariantList() << currentField.allowableValues().first());
       
   827                 else
       
   828                     det.setValue(fieldKey, currentField.allowableValues().first());
       
   829             } else {
       
   830                 // any value of the correct type will be accepted
       
   831                 bool savedSuccessfully = false;
       
   832                 QVariant dummyValue = QVariant(fieldKey); // try to get some unique string data
       
   833                 if (dummyValue.canConvert(currentField.dataType())) {
       
   834                     savedSuccessfully = dummyValue.convert(currentField.dataType());
       
   835                     if (savedSuccessfully) {
       
   836                         // we have successfully created a (supposedly) valid field for this detail.
       
   837                         det.setValue(fieldKey, dummyValue);
       
   838                         continue;
       
   839                     }
       
   840                 }
       
   841 
       
   842                 // nope, couldn't save the string value (test); try a date.
       
   843                 dummyValue = QVariant(QDate::currentDate());
       
   844                 if (dummyValue.canConvert(currentField.dataType())) {
       
   845                     savedSuccessfully = dummyValue.convert(currentField.dataType());
       
   846                     if (savedSuccessfully) {
       
   847                         // we have successfully created a (supposedly) valid field for this detail.
       
   848                         det.setValue(fieldKey, dummyValue);
       
   849                         continue;
       
   850                     }
       
   851                 }
       
   852 
       
   853                 // nope, couldn't convert a string or a date - try the integer value (42)
       
   854                 dummyValue = QVariant(42);
       
   855                 if (dummyValue.canConvert(currentField.dataType())) {
       
   856                     savedSuccessfully = dummyValue.convert(currentField.dataType());
       
   857                     if (savedSuccessfully) {
       
   858                         // we have successfully created a (supposedly) valid field for this detail.
       
   859                         det.setValue(fieldKey, dummyValue);
       
   860                         continue;
       
   861                     }
       
   862                 }
       
   863 
       
   864                 // if we get here, we don't know what sort of value can be saved...
       
   865             }
       
   866         }
       
   867         if (!det.isEmpty())
       
   868             megacontact.saveDetail(&det);
       
   869     }
       
   870 
       
   871     QVERIFY(cm->saveContact(&megacontact)); // must be able to save since built from definitions.
       
   872     QContact retrievedMegacontact = cm->contact(megacontact.id().localId());
       
   873     if (!isSuperset(retrievedMegacontact, megacontact)) {
       
   874         dumpContactDifferences(megacontact, retrievedMegacontact);
       
   875         QEXPECT_FAIL("mgr='wince'", "Address Display Label mismatch", Continue);
       
   876         QCOMPARE(megacontact, retrievedMegacontact);
       
   877     }
       
   878 
       
   879     // now a contact with many details of a particular definition
       
   880     // if the detail is not unique it should then support minumum of two of the same kind
       
   881     const int nrOfdetails = 2;
       
   882     QContact veryContactable = createContact(nameDef, "Very", "Contactable", "");
       
   883     for (int i = 0; i < nrOfdetails; i++) {
       
   884         QString phnStr = QString::number(i);
       
   885         QContactPhoneNumber vcphn;
       
   886         vcphn.setNumber(phnStr);
       
   887         QVERIFY(veryContactable.saveDetail(&vcphn));
       
   888     }
       
   889 
       
   890     // check that all the numbers were added successfully
       
   891     QVERIFY(veryContactable.details(QContactPhoneNumber::DefinitionName).size() == nrOfdetails);
       
   892     
       
   893     // check if it can be saved
       
   894     QContactDetailDefinition def = cm->detailDefinition(QContactPhoneNumber::DefinitionName);
       
   895     if (def.isUnique()) {    
       
   896         QVERIFY(!cm->saveContact(&veryContactable));
       
   897     }
       
   898     else {
       
   899         QVERIFY(cm->saveContact(&veryContactable));
       
   900         
       
   901         // verify save
       
   902         QContact retrievedContactable = cm->contact(veryContactable.id().localId());
       
   903         if (!isSuperset(retrievedContactable, veryContactable)) {
       
   904             dumpContactDifferences(veryContactable, retrievedContactable);
       
   905             QEXPECT_FAIL("mgr='wince'", "Number of phones supported mismatch", Continue);
       
   906             QCOMPARE(veryContactable, retrievedContactable);
       
   907         }
       
   908     }
       
   909 }
       
   910 
       
   911 void tst_QContactManager::update()
       
   912 {
       
   913     QFETCH(QString, uri);
       
   914     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   915 
       
   916     if (cm->managerName() == QString(QLatin1String("maemo5"))) {
       
   917         // we specifically want to test the update semantics of the maemo5 backend
       
   918         // since there are various complexities relating to roster contacts.
       
   919         QContact mt;
       
   920         QContactName mtn;
       
   921         mtn.setFirstName("test");
       
   922         mtn.setLastName("maemo");
       
   923         QContactPhoneNumber pn;
       
   924         pn.setNumber("12345");
       
   925 
       
   926         mt.saveDetail(&mtn);
       
   927         cm->saveContact(&mt);
       
   928         mt = cm->contact(mt.localId()); // force reload of (persisted) contact
       
   929         QVERIFY(mt.details<QContactPhoneNumber>().count() == 0);
       
   930 
       
   931         // now save a single phonenumber
       
   932         mt.saveDetail(&pn);
       
   933         cm->saveContact(&mt);
       
   934         mt = cm->contact(mt.localId()); // force reload of (persisted) contact
       
   935         QVERIFY(mt.details<QContactPhoneNumber>().count() == 1);
       
   936 
       
   937         // edit some other existing detail and save (shouldn't duplicate the phone number)
       
   938         mtn.setMiddleName("middle");
       
   939         mt.saveDetail(&mtn);
       
   940         cm->saveContact(&mt);
       
   941         mt = cm->contact(mt.localId()); // force reload of (persisted) contact
       
   942         QCOMPARE(mt.details<QContactPhoneNumber>().count(), 1);
       
   943 
       
   944         // add some other detail and save (shouldn't duplicate the phone number)
       
   945         QContactEmailAddress mte;
       
   946         mte.setEmailAddress("test@test.com");
       
   947         mt.saveDetail(&mte);
       
   948         cm->saveContact(&mt);
       
   949         mt = cm->contact(mt.localId()); // force reload of (persisted) contact
       
   950         QCOMPARE(mt.details<QContactPhoneNumber>().count(), 1);
       
   951 
       
   952         // add another phone number detail and save (should create a single other phone number)
       
   953         QContactPhoneNumber pn2;
       
   954         pn2.setNumber("98765");
       
   955         mt.saveDetail(&pn2);
       
   956         cm->saveContact(&mt);
       
   957         mt = cm->contact(mt.localId()); // force reload of (persisted) contact
       
   958         QCOMPARE(mt.details<QContactPhoneNumber>().count(), 2);
       
   959 
       
   960         // here we do something tricky: we save one of the previously saved phone numbers
       
   961         // in a _different_ contact, and see if that causes problems with the overwrite vs new detail code.
       
   962         QContactPhoneNumber pn2Copy = pn2;
       
   963         QContact mt2;
       
   964         QContactName mt2n;
       
   965         mt2n.setFirstName("test2");
       
   966         mt2.saveDetail(&mt2n);
       
   967         QContactPhoneNumber shouldBeNew = pn;
       
   968         mt2.saveDetail(&shouldBeNew);
       
   969         QVERIFY(cm->saveContact(&mt2));
       
   970         mt2 = cm->contact(mt2.localId());
       
   971         QCOMPARE(mt2.details<QContactPhoneNumber>().count(), 1);
       
   972         mt2.saveDetail(&pn2);
       
   973         QVERIFY(cm->saveContact(&mt2));
       
   974         mt2 = cm->contact(mt2.localId());
       
   975         QCOMPARE(mt2.details<QContactPhoneNumber>().count(), 2);
       
   976         pn2 = pn2Copy; // reset just in case backend added some fields.
       
   977 
       
   978         // remove the other phone number detail, shouldn't cause side effects to the first...
       
   979         // NOTE: we need to reload the details before attempting to remove/edit them
       
   980         // because the backend can change the ids.
       
   981         QList<QContactPhoneNumber> pnums = mt.details<QContactPhoneNumber>();
       
   982         foreach (const QContactPhoneNumber& pd, pnums) {
       
   983             if (pd.number() == pn2.number())
       
   984                 pn2 = pd;
       
   985             else if (pd.number() == pn.number())
       
   986                 pn = pd;
       
   987         }
       
   988         mt.removeDetail(&pn2);
       
   989         cm->saveContact(&mt);
       
   990         mt = cm->contact(mt.localId()); // force reload of (persisted) contact
       
   991         QCOMPARE(mt.details<QContactPhoneNumber>().count(), 1);
       
   992 
       
   993         // edit the original phone number detail, shouldn't duplicate the phone number
       
   994         // NOTE: we need to reload the details before attempting to remove/edit them
       
   995         // because the backend can change the ids.
       
   996         pnums = mt.details<QContactPhoneNumber>();
       
   997         foreach (const QContactPhoneNumber& pd, pnums) {
       
   998             if (pd.number() == pn2.number())
       
   999                 pn2 = pd;
       
  1000             else if (pd.number() == pn.number())
       
  1001                 pn = pd;
       
  1002         }
       
  1003         pn.setNumber("54321");
       
  1004         mt.saveDetail(&pn);
       
  1005         cm->saveContact(&mt);
       
  1006         mt = cm->contact(mt.localId());
       
  1007         QCOMPARE(mt.details<QContactPhoneNumber>().count(), 1);
       
  1008         QVERIFY(mt.detail<QContactPhoneNumber>() == pn);
       
  1009 
       
  1010         // we also should do the same test for other details (for example, gender).
       
  1011         // if the backend cannot save multiple copies of a detail (eg, gender always overwrites)
       
  1012         // it should FAIL the save operation if the contact has multiple of that detail type,
       
  1013         // and set error to QContactManager::LimitReachedError.
       
  1014         QContactGender mtg, mtg2;
       
  1015         mtg.setGender(QContactGender::GenderFemale);
       
  1016         mtg2.setGender(QContactGender::GenderMale);
       
  1017         mt.saveDetail(&mtg);
       
  1018         QVERIFY(cm->saveContact(&mt)); // one gender is fine
       
  1019         mt.saveDetail(&mtg2);
       
  1020         QVERIFY(!cm->saveContact(&mt)); // two is not
       
  1021         //QCOMPARE(cm->error(), QContactManager::LimitReachedError); // should be LimitReachedError.
       
  1022         mt = cm->contact(mt.localId());
       
  1023         QVERIFY(mt.details<QContactGender>().count() == 1);
       
  1024     }
       
  1025 
       
  1026     /* Save a new contact first */
       
  1027     int contactCount = cm->contacts().size();
       
  1028     QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
  1029     QContact alice = createContact(nameDef, "Alice", "inWonderland", "1234567");
       
  1030     QVERIFY(cm->saveContact(&alice));
       
  1031     QVERIFY(cm->error() == QContactManager::NoError);
       
  1032     contactCount += 1; // added a new contact.
       
  1033     QCOMPARE(cm->contacts().size(), contactCount);
       
  1034 
       
  1035     /* Update name */
       
  1036     QContactName name = alice.detail(QContactName::DefinitionName);
       
  1037     saveContactName(&alice, nameDef, &name, "updated");
       
  1038     QVERIFY(cm->saveContact(&alice));
       
  1039     QVERIFY(cm->error() == QContactManager::NoError);
       
  1040     saveContactName(&alice, nameDef, &name, "updated2");
       
  1041     QVERIFY(cm->saveContact(&alice));
       
  1042     QVERIFY(cm->error() == QContactManager::NoError);
       
  1043     alice = cm->contact(alice.localId()); // force reload of (persisted) alice
       
  1044     QContact updated = cm->contact(alice.localId());
       
  1045     QContactName updatedName = updated.detail(QContactName::DefinitionName);
       
  1046     QCOMPARE(updatedName, name);
       
  1047     QCOMPARE(cm->contacts().size(), contactCount); // contact count should be the same, no new contacts
       
  1048 
       
  1049     /* Test that adding a new detail doesn't cause unwanted side effects */
       
  1050     int detailCount = alice.details().size();
       
  1051     QContactEmailAddress email;
       
  1052     email.setEmailAddress("test@example.com");
       
  1053     alice.saveDetail(&email);
       
  1054     QVERIFY(cm->saveContact(&alice));
       
  1055     QCOMPARE(cm->contacts().size(), contactCount); // contact count shoudl be the same, no new contacts
       
  1056 
       
  1057     // This test is dangerous, since backends can add timestamps etc...
       
  1058     detailCount += 1;
       
  1059     QCOMPARE(detailCount, alice.details().size()); // adding a detail should cause the detail count to increase by one.
       
  1060 
       
  1061     /* Test that removal of fields in a detail works */
       
  1062     QContactPhoneNumber phn = alice.detail<QContactPhoneNumber>();
       
  1063     phn.setNumber("1234567");
       
  1064     phn.setContexts(QContactDetail::ContextHome);
       
  1065     alice.saveDetail(&phn);
       
  1066     QVERIFY(cm->saveContact(&alice));
       
  1067     alice = cm->contact(alice.localId()); // force reload of (persisted) alice
       
  1068     QVERIFY(alice.detail<QContactPhoneNumber>().contexts().contains(QContactDetail::ContextHome)); // check context saved.
       
  1069     phn = alice.detail<QContactPhoneNumber>(); // reload the detail, since it's key could have changed
       
  1070     phn.setContexts(QStringList()); // remove context field.
       
  1071     alice.saveDetail(&phn);
       
  1072     QVERIFY(cm->saveContact(&alice));
       
  1073     alice = cm->contact(alice.localId()); // force reload of (persisted) alice
       
  1074     QVERIFY(alice.detail<QContactPhoneNumber>().contexts().isEmpty()); // check context removed.
       
  1075     QCOMPARE(cm->contacts().size(), contactCount); // removal of a field of a detail shouldn't affect the contact count
       
  1076 
       
  1077     // This test is dangerous, since backends can add timestamps etc...
       
  1078     QCOMPARE(detailCount, alice.details().size()); // removing a field from a detail should affect the detail count
       
  1079 
       
  1080     /* Test that removal of details works */
       
  1081     phn = alice.detail<QContactPhoneNumber>(); // reload the detail, since it's key could have changed
       
  1082     alice.removeDetail(&phn);
       
  1083     QVERIFY(cm->saveContact(&alice));
       
  1084     alice = cm->contact(alice.localId()); // force reload of (persisted) alice
       
  1085     QVERIFY(alice.details<QContactPhoneNumber>().isEmpty()); // no such detail.
       
  1086     QCOMPARE(cm->contacts().size(), contactCount); // removal of a detail shouldn't affect the contact count
       
  1087 
       
  1088     // This test is dangerous, since backends can add timestamps etc...
       
  1089     //detailCount -= 1;
       
  1090     //QCOMPARE(detailCount, alice.details().size()); // removing a detail should cause the detail count to decrease by one.
       
  1091 
       
  1092     if (cm->hasFeature(QContactManager::Groups)) {
       
  1093         // Try changing types - not allowed
       
  1094         // from contact -> group
       
  1095         alice.setType(QContactType::TypeGroup);
       
  1096         QContactName na = alice.detail(QContactName::DefinitionName);
       
  1097         alice.removeDetail(&na);
       
  1098         QVERIFY(!cm->saveContact(&alice));
       
  1099         QVERIFY(cm->error() == QContactManager::AlreadyExistsError);
       
  1100 
       
  1101         // from group -> contact
       
  1102         QContact jabberwock = createContact(nameDef, "", "", "1234567890");
       
  1103         jabberwock.setType(QContactType::TypeGroup);
       
  1104         QVERIFY(cm->saveContact(&jabberwock));
       
  1105         jabberwock.setType(QContactType::TypeContact);
       
  1106         QVERIFY(!cm->saveContact(&jabberwock));
       
  1107         QVERIFY(cm->error() == QContactManager::AlreadyExistsError);
       
  1108     }
       
  1109 }
       
  1110 
       
  1111 void tst_QContactManager::remove()
       
  1112 {
       
  1113     QFETCH(QString, uri);
       
  1114     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  1115 
       
  1116     /* Save a new contact first */
       
  1117     QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
  1118     QContact alice = createContact(nameDef, "Alice", "inWonderland", "1234567");
       
  1119     QVERIFY(cm->saveContact(&alice));
       
  1120     QVERIFY(cm->error() == QContactManager::NoError);
       
  1121     QVERIFY(alice.id() != QContactId());
       
  1122 
       
  1123     /* Remove the created contact */
       
  1124     const int contactCount = cm->contactIds().count();
       
  1125     QVERIFY(cm->removeContact(alice.localId()));
       
  1126     QCOMPARE(cm->contactIds().count(), contactCount - 1);
       
  1127     QVERIFY(cm->contact(alice.localId()).isEmpty());
       
  1128     QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
       
  1129 }
       
  1130 
       
  1131 void tst_QContactManager::batch()
       
  1132 {
       
  1133     QFETCH(QString, uri);
       
  1134     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  1135 
       
  1136     /* First test null pointer operations */
       
  1137     QVERIFY(!cm->saveContacts(NULL, NULL));
       
  1138     QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  1139 
       
  1140     QVERIFY(!cm->removeContacts(QList<QContactLocalId>(), NULL));
       
  1141     QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  1142     
       
  1143     // Get supported name field
       
  1144     QString nameField = QContactName::FieldFirstName;
       
  1145     QContactDetailDefinition def = cm->detailDefinition(QContactName::DefinitionName);
       
  1146     if (!def.fields().contains(QContactName::FieldFirstName)) {
       
  1147         if(def.fields().contains(QContactName::FieldCustomLabel))
       
  1148             nameField = QLatin1String(QContactName::FieldCustomLabel);
       
  1149         else
       
  1150             QSKIP("This backend does not support the required name field!", SkipSingle);
       
  1151     }
       
  1152 
       
  1153     /* Now add 3 contacts, all valid */
       
  1154     QContact a;
       
  1155     QContactName na;
       
  1156     na.setValue(nameField, "XXXXXX Albert");
       
  1157     a.saveDetail(&na);
       
  1158 
       
  1159     QContact b;
       
  1160     QContactName nb;
       
  1161     nb.setValue(nameField, "XXXXXX Bob");
       
  1162     b.saveDetail(&nb);
       
  1163 
       
  1164     QContact c;
       
  1165     QContactName nc;
       
  1166     nc.setValue(nameField, "XXXXXX Carol");
       
  1167     c.saveDetail(&nc);
       
  1168 
       
  1169     QList<QContact> contacts;
       
  1170     contacts << a << b << c;
       
  1171 
       
  1172     QMap<int, QContactManager::Error> errorMap;
       
  1173     // Add one dummy error to test if the errors are reset
       
  1174     errorMap.insert(0, QContactManager::NoError);
       
  1175     QVERIFY(cm->saveContacts(&contacts, &errorMap));
       
  1176     QVERIFY(cm->error() == QContactManager::NoError);
       
  1177     QVERIFY(errorMap.count() == 0);
       
  1178 
       
  1179     /* Make sure our contacts got updated too */
       
  1180     QVERIFY(contacts.count() == 3);
       
  1181     QVERIFY(contacts.at(0).id() != QContactId());
       
  1182     QVERIFY(contacts.at(1).id() != QContactId());
       
  1183     QVERIFY(contacts.at(2).id() != QContactId());
       
  1184 
       
  1185     QVERIFY(contacts.at(0).detail(QContactName::DefinitionName) == na);
       
  1186     QVERIFY(contacts.at(1).detail(QContactName::DefinitionName) == nb);
       
  1187     QVERIFY(contacts.at(2).detail(QContactName::DefinitionName) == nc);
       
  1188 
       
  1189     /* Retrieve again */
       
  1190     a = cm->contact(contacts.at(0).id().localId());
       
  1191     b = cm->contact(contacts.at(1).id().localId());
       
  1192     c = cm->contact(contacts.at(2).id().localId());
       
  1193     QVERIFY(contacts.at(0).detail(QContactName::DefinitionName) == na);
       
  1194     QVERIFY(contacts.at(1).detail(QContactName::DefinitionName) == nb);
       
  1195     QVERIFY(contacts.at(2).detail(QContactName::DefinitionName) == nc);
       
  1196 
       
  1197     /* Save again, with a null error map */
       
  1198     QVERIFY(cm->saveContacts(&contacts, NULL));
       
  1199     QVERIFY(cm->error() == QContactManager::NoError);
       
  1200 
       
  1201     /* Now make an update to them all */
       
  1202     QContactPhoneNumber number;
       
  1203     number.setNumber("1234567");
       
  1204 
       
  1205     QVERIFY(contacts[0].saveDetail(&number));
       
  1206     number.setNumber("234567");
       
  1207     QVERIFY(contacts[1].saveDetail(&number));
       
  1208     number.setNumber("34567");
       
  1209     QVERIFY(contacts[2].saveDetail(&number));
       
  1210 
       
  1211     QVERIFY(cm->saveContacts(&contacts, &errorMap));
       
  1212     QVERIFY(cm->error() == QContactManager::NoError);
       
  1213     QVERIFY(errorMap.count() == 0);
       
  1214 
       
  1215     /* Retrieve them and check them again */
       
  1216     a = cm->contact(contacts.at(0).id().localId());
       
  1217     b = cm->contact(contacts.at(1).id().localId());
       
  1218     c = cm->contact(contacts.at(2).id().localId());
       
  1219     QVERIFY(contacts.at(0).detail(QContactName::DefinitionName) == na);
       
  1220     QVERIFY(contacts.at(1).detail(QContactName::DefinitionName) == nb);
       
  1221     QVERIFY(contacts.at(2).detail(QContactName::DefinitionName) == nc);
       
  1222 
       
  1223     QVERIFY(a.details<QContactPhoneNumber>().count() == 1);
       
  1224     QVERIFY(b.details<QContactPhoneNumber>().count() == 1);
       
  1225     QVERIFY(c.details<QContactPhoneNumber>().count() == 1);
       
  1226 
       
  1227     QVERIFY(a.details<QContactPhoneNumber>().at(0).number() == "1234567");
       
  1228     QVERIFY(b.details<QContactPhoneNumber>().at(0).number() == "234567");
       
  1229     QVERIFY(c.details<QContactPhoneNumber>().at(0).number() == "34567");
       
  1230 
       
  1231     /* Now delete them all */
       
  1232     QList<QContactLocalId> ids;
       
  1233     ids << a.id().localId() << b.id().localId() << c.id().localId();
       
  1234     QVERIFY(cm->removeContacts(ids, &errorMap));
       
  1235     QVERIFY(errorMap.count() == 0);
       
  1236     QVERIFY(cm->error() == QContactManager::NoError);
       
  1237 
       
  1238     /* Make sure the contacts really don't exist any more */
       
  1239     QVERIFY(cm->contact(a.id().localId()).id() == QContactId());
       
  1240     QVERIFY(cm->contact(a.id().localId()).isEmpty());
       
  1241     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1242     QVERIFY(cm->contact(b.id().localId()).id() == QContactId());
       
  1243     QVERIFY(cm->contact(b.id().localId()).isEmpty());
       
  1244     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1245     QVERIFY(cm->contact(c.id().localId()).id() == QContactId());
       
  1246     QVERIFY(cm->contact(c.id().localId()).isEmpty());
       
  1247     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1248 
       
  1249     /* Now try removing with all invalid ids (e.g. the ones we just removed) */
       
  1250     ids.clear();
       
  1251     ids << a.id().localId() << b.id().localId() << c.id().localId();
       
  1252     QVERIFY(!cm->removeContacts(ids, &errorMap));
       
  1253     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1254     QVERIFY(errorMap.count() == 3);
       
  1255     QVERIFY(errorMap.values().at(0) == QContactManager::DoesNotExistError);
       
  1256     QVERIFY(errorMap.values().at(1) == QContactManager::DoesNotExistError);
       
  1257     QVERIFY(errorMap.values().at(2) == QContactManager::DoesNotExistError);
       
  1258 
       
  1259     /* And again with a null error map */
       
  1260     QVERIFY(!cm->removeContacts(ids, NULL));
       
  1261     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1262 
       
  1263     /* Try adding some new ones again, this time one with an error */
       
  1264     contacts.clear();
       
  1265     a.setId(QContactId());
       
  1266     b.setId(QContactId());
       
  1267     c.setId(QContactId());
       
  1268 
       
  1269     /* Make B the bad guy */
       
  1270     QContactDetail bad("does not exist and will break if you add it");
       
  1271     bad.setValue("This is also bad", "Very bad");
       
  1272     b.saveDetail(&bad);
       
  1273 
       
  1274     contacts << a << b << c;
       
  1275     QVERIFY(!cm->saveContacts(&contacts, &errorMap));
       
  1276     /* We can't really say what the error will be.. maybe bad argument, maybe invalid detail */
       
  1277     QVERIFY(cm->error() != QContactManager::NoError);
       
  1278 
       
  1279     /* It's permissible to fail all the adds, or to add the successful ones */
       
  1280     QVERIFY(errorMap.count() > 0);
       
  1281     QVERIFY(errorMap.count() <= 3);
       
  1282 
       
  1283     // A might have gone through
       
  1284     if (errorMap.keys().contains(0)) {
       
  1285         QVERIFY(errorMap.value(0) != QContactManager::NoError);
       
  1286         QVERIFY(contacts.at(0).id() == QContactId());
       
  1287     } else {
       
  1288         QVERIFY(contacts.at(0).id() != QContactId());
       
  1289     }
       
  1290 
       
  1291     // B should have failed
       
  1292     QVERIFY(errorMap.value(1) == QContactManager::InvalidDetailError);
       
  1293     QVERIFY(contacts.at(1).id() == QContactId());
       
  1294 
       
  1295     // C might have gone through
       
  1296     if (errorMap.keys().contains(2)) {
       
  1297         QVERIFY(errorMap.value(2) != QContactManager::NoError);
       
  1298         QVERIFY(contacts.at(2).id() == QContactId());
       
  1299     } else {
       
  1300         QVERIFY(contacts.at(2).id() != QContactId());
       
  1301     }
       
  1302 
       
  1303     /* Fix up B and re save it */
       
  1304     QVERIFY(contacts[1].removeDetail(&bad));
       
  1305     QVERIFY(cm->saveContacts(&contacts, &errorMap));
       
  1306     QVERIFY(errorMap.count() == 0);
       
  1307     QVERIFY(cm->error() == QContactManager::NoError);
       
  1308     
       
  1309     // Save and remove a fourth contact. Store the id.
       
  1310     a.setId(QContactId());
       
  1311     QVERIFY(cm->saveContact(&a));
       
  1312     QContactLocalId removedId = a.localId();
       
  1313     QVERIFY(cm->removeContact(removedId));
       
  1314 
       
  1315     /* Now delete 3 items, but with one bad argument */
       
  1316     ids.clear();
       
  1317     ids << contacts.at(0).id().localId();
       
  1318     ids << removedId;
       
  1319     ids << contacts.at(2).id().localId();
       
  1320 
       
  1321     QVERIFY(!cm->removeContacts(ids, &errorMap));
       
  1322     QVERIFY(cm->error() != QContactManager::NoError);
       
  1323 
       
  1324     /* Again, the backend has the choice of either removing the successful ones, or not */
       
  1325     QVERIFY(errorMap.count() > 0);
       
  1326     QVERIFY(errorMap.count() <= 3);
       
  1327 
       
  1328     // A might have gone through
       
  1329     if (errorMap.keys().contains(0)) {
       
  1330         QVERIFY(errorMap.value(0) != QContactManager::NoError);
       
  1331         QVERIFY(contacts.at(0).id() == QContactId());
       
  1332     } else {
       
  1333         QVERIFY(contacts.at(0).id() != QContactId());
       
  1334     }
       
  1335 
       
  1336     /* B should definitely have failed */
       
  1337     QVERIFY(errorMap.value(1) == QContactManager::DoesNotExistError);
       
  1338     QVERIFY(ids.at(1) == removedId);
       
  1339 
       
  1340     // A might have gone through
       
  1341     if (errorMap.keys().contains(2)) {
       
  1342         QVERIFY(errorMap.value(2) != QContactManager::NoError);
       
  1343         QVERIFY(contacts.at(2).id() == QContactId());
       
  1344     } else {
       
  1345         QVERIFY(contacts.at(2).id() != QContactId());
       
  1346     }
       
  1347 }
       
  1348 
       
  1349 void tst_QContactManager::invalidManager()
       
  1350 {
       
  1351     /* Create an invalid manager */
       
  1352     QContactManager manager("this should never work");
       
  1353     QVERIFY(manager.managerName() == "invalid");
       
  1354     QVERIFY(manager.managerVersion() == 0);
       
  1355 
       
  1356     /* also, test the other ctor behaviour is sane also */
       
  1357     QContactManager anotherManager("this should never work", 15);
       
  1358     QVERIFY(anotherManager.managerName() == "invalid");
       
  1359     QVERIFY(anotherManager.managerVersion() == 0);
       
  1360 
       
  1361     /* Now test that all the operations fail */
       
  1362     QVERIFY(manager.contactIds().count() == 0);
       
  1363     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1364 
       
  1365     QContact foo;
       
  1366     QContactName nf;
       
  1367     nf.setLastName("Lastname");
       
  1368     foo.saveDetail(&nf);
       
  1369 
       
  1370     QVERIFY(manager.synthesizedContactDisplayLabel(foo).isEmpty());
       
  1371     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1372 
       
  1373     QVERIFY(manager.saveContact(&foo) == false);
       
  1374     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1375     QVERIFY(foo.id() == QContactId());
       
  1376     QVERIFY(manager.contactIds().count() == 0);
       
  1377 
       
  1378     QVERIFY(manager.contact(foo.id().localId()).id() == QContactId());
       
  1379     QVERIFY(manager.contact(foo.id().localId()).isEmpty());
       
  1380     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1381 
       
  1382     QVERIFY(manager.removeContact(foo.id().localId()) == false);
       
  1383     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1384 
       
  1385     QMap<int, QContactManager::Error> errorMap;
       
  1386     errorMap.insert(0, QContactManager::NoError);
       
  1387     QVERIFY(!manager.saveContacts(0, &errorMap));
       
  1388     QVERIFY(errorMap.count() == 0);
       
  1389     QVERIFY(manager.error() == QContactManager::BadArgumentError);
       
  1390 
       
  1391     /* filters */
       
  1392     QContactFilter f; // matches everything
       
  1393     QContactDetailFilter df;
       
  1394     df.setDetailDefinitionName(QContactDisplayLabel::DefinitionName, QContactDisplayLabel::FieldLabel);
       
  1395     QVERIFY(manager.contactIds(QContactFilter()).count() == 0);
       
  1396     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1397     QVERIFY(manager.contactIds(df).count() == 0);
       
  1398     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1399     QVERIFY(manager.contactIds(f | f).count() == 0);
       
  1400     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1401     QVERIFY(manager.contactIds(df | df).count() == 0);
       
  1402     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1403 
       
  1404     QVERIFY(manager.isFilterSupported(f) == false);
       
  1405     QVERIFY(manager.isFilterSupported(df) == false);
       
  1406 
       
  1407     QList<QContact> list;
       
  1408     list << foo;
       
  1409 
       
  1410     QVERIFY(!manager.saveContacts(&list, &errorMap));
       
  1411     QVERIFY(errorMap.count() == 0);
       
  1412     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1413 
       
  1414     QVERIFY(!manager.removeContacts(QList<QContactLocalId>(), &errorMap));
       
  1415     QVERIFY(errorMap.count() == 0);
       
  1416     QVERIFY(manager.error() == QContactManager::BadArgumentError);
       
  1417 
       
  1418     QList<QContactLocalId> idlist;
       
  1419     idlist << foo.id().localId();
       
  1420     QVERIFY(!manager.removeContacts(idlist, &errorMap));
       
  1421     QVERIFY(errorMap.count() == 0);
       
  1422     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1423 
       
  1424     /* Detail definitions */
       
  1425     QVERIFY(manager.detailDefinitions().count() == 0);
       
  1426     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1427 
       
  1428     QContactDetailDefinition def;
       
  1429     def.setUnique(true);
       
  1430     def.setName("new field");
       
  1431     QMap<QString, QContactDetailFieldDefinition> fields;
       
  1432     QContactDetailFieldDefinition currField;
       
  1433     currField.setDataType(QVariant::String);
       
  1434     fields.insert("value", currField);
       
  1435     def.setFields(fields);
       
  1436 
       
  1437     QVERIFY(manager.saveDetailDefinition(def, QContactType::TypeContact) == false);
       
  1438     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1439     QVERIFY(manager.saveDetailDefinition(def) == false);
       
  1440     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1441     QVERIFY(manager.detailDefinitions().count(QContactType::TypeContact) == 0);
       
  1442     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1443     QVERIFY(manager.detailDefinitions().count() == 0);
       
  1444     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1445     QVERIFY(manager.detailDefinition("new field").name() == QString());
       
  1446     QVERIFY(manager.removeDetailDefinition(def.name(), QContactType::TypeContact) == false);
       
  1447     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1448     QVERIFY(manager.removeDetailDefinition(def.name()) == false);
       
  1449     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1450     QVERIFY(manager.detailDefinitions().count() == 0);
       
  1451     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1452 
       
  1453     /* Self contact id */
       
  1454     QVERIFY(!manager.setSelfContactId(QContactLocalId(12)));
       
  1455     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1456     QVERIFY(manager.selfContactId() == QContactLocalId());
       
  1457     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::DoesNotExistError);
       
  1458 
       
  1459     /* Relationships */
       
  1460     QContactId idOne, idTwo;
       
  1461     idOne.setLocalId(QContactLocalId(15));
       
  1462     idOne.setManagerUri(QString());
       
  1463     idTwo.setLocalId(QContactLocalId(22));
       
  1464     idTwo.setManagerUri(QString());
       
  1465     QContactRelationship invalidRel;
       
  1466     invalidRel.setFirst(idOne);
       
  1467     invalidRel.setSecond(idTwo);
       
  1468     QList<QContactRelationship> invalidRelList;
       
  1469     invalidRelList << invalidRel;
       
  1470     QVERIFY(!manager.saveRelationship(&invalidRel));
       
  1471     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1472     QVERIFY(manager.relationships().isEmpty());
       
  1473     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1474     manager.saveRelationships(&invalidRelList, NULL);
       
  1475     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1476     manager.removeRelationships(invalidRelList, NULL);
       
  1477     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::DoesNotExistError);
       
  1478 
       
  1479     /* Capabilities */
       
  1480     QVERIFY(manager.supportedDataTypes().count() == 0);
       
  1481     QVERIFY(!manager.hasFeature(QContactManager::ActionPreferences));
       
  1482     QVERIFY(!manager.hasFeature(QContactManager::MutableDefinitions));
       
  1483 }
       
  1484 
       
  1485 void tst_QContactManager::memoryManager()
       
  1486 {
       
  1487     QMap<QString, QString> params;
       
  1488     QContactManager m1("memory");
       
  1489     params.insert("random", "shouldNotBeUsed");
       
  1490     QContactManager m2("memory", params);
       
  1491     params.insert("id", "shouldBeUsed");
       
  1492     QContactManager m3("memory", params);
       
  1493     QContactManager m4("memory", params);
       
  1494     params.insert("id", QString(""));
       
  1495     QContactManager m5("memory", params); // should be another anonymous
       
  1496 
       
  1497     QVERIFY(m1.hasFeature(QContactManager::ActionPreferences));
       
  1498     QVERIFY(m1.hasFeature(QContactManager::MutableDefinitions));
       
  1499     QVERIFY(m1.hasFeature(QContactManager::Anonymous));
       
  1500 
       
  1501     // add a contact to each of m1, m2, m3
       
  1502     QContact c;
       
  1503     QContactName nc;
       
  1504     nc.setFirstName("John");
       
  1505     nc.setLastName("Civilian");
       
  1506     c.saveDetail(&nc);
       
  1507     m1.saveContact(&c);
       
  1508     c.setId(QContactId());
       
  1509     QContact c2;
       
  1510     QContactName nc2 = c2.detail(QContactName::DefinitionName);
       
  1511     c2 = c;
       
  1512     nc2.setMiddleName("Public");
       
  1513     c2.saveDetail(&nc2);
       
  1514     m2.saveContact(&c2);            // save c2 first; c will be given a higher id
       
  1515     m2.saveContact(&c);             // save c to m2
       
  1516     c.setId(QContactId());
       
  1517     nc.setSuffix("MD");
       
  1518     c.saveDetail(&nc);
       
  1519     m3.saveContact(&c);
       
  1520 
       
  1521     /* test that m1 != m2 != m3 and that m3 == m4 */
       
  1522 
       
  1523     // check the counts are correct - especially note m4 and m3.
       
  1524     QCOMPARE(m1.contactIds().count(), 1);
       
  1525     QCOMPARE(m2.contactIds().count(), 2);
       
  1526     QCOMPARE(m3.contactIds().count(), 1);
       
  1527     QCOMPARE(m4.contactIds().count(), 1);
       
  1528     QCOMPARE(m5.contactIds().count(), 0);
       
  1529 
       
  1530     // remove c2 from m2 - ensure that this doesn't affect any other manager.
       
  1531     m2.removeContact(c2.id().localId());
       
  1532     QCOMPARE(m1.contactIds().count(), 1);
       
  1533     QCOMPARE(m2.contactIds().count(), 1);
       
  1534     QCOMPARE(m3.contactIds().count(), 1);
       
  1535     QCOMPARE(m4.contactIds().count(), 1);
       
  1536     QCOMPARE(m5.contactIds().count(), 0);
       
  1537 
       
  1538     // check that the contacts contained within are different.
       
  1539     // note that in the m1->m2 case, only the id will be different!
       
  1540     QVERIFY(m1.contact(m1.contactIds().at(0)) != m2.contact(m2.contactIds().at(0)));
       
  1541     QVERIFY(m1.contact(m1.contactIds().at(0)) != m3.contact(m3.contactIds().at(0)));
       
  1542     QVERIFY(m2.contact(m2.contactIds().at(0)) != m3.contact(m3.contactIds().at(0)));
       
  1543     QVERIFY(m3.contact(m3.contactIds().at(0)) == m4.contact(m4.contactIds().at(0)));
       
  1544 
       
  1545     // now, we should be able to remove from m4, and have m3 empty
       
  1546     QVERIFY(m4.removeContact(c.id().localId()));
       
  1547     QCOMPARE(m3.contactIds().count(), 0);
       
  1548     QCOMPARE(m4.contactIds().count(), 0);
       
  1549     QCOMPARE(m5.contactIds().count(), 0);
       
  1550 }
       
  1551 
       
  1552 void tst_QContactManager::nameSynthesis_data()
       
  1553 {
       
  1554     QTest::addColumn<QString>("expected");
       
  1555 
       
  1556     QTest::addColumn<bool>("addname");
       
  1557     QTest::addColumn<QString>("prefix");
       
  1558     QTest::addColumn<QString>("first");
       
  1559     QTest::addColumn<QString>("middle");
       
  1560     QTest::addColumn<QString>("last");
       
  1561     QTest::addColumn<QString>("suffix");
       
  1562 
       
  1563     QTest::addColumn<bool>("addcompany");
       
  1564     QTest::addColumn<QString>("company");
       
  1565 
       
  1566     QTest::addColumn<bool>("addname2");
       
  1567     QTest::addColumn<QString>("secondprefix");
       
  1568     QTest::addColumn<QString>("secondfirst");
       
  1569     QTest::addColumn<QString>("secondmiddle");
       
  1570     QTest::addColumn<QString>("secondlast");
       
  1571     QTest::addColumn<QString>("secondsuffix");
       
  1572 
       
  1573     QTest::addColumn<bool>("addcompany2");
       
  1574     QTest::addColumn<QString>("secondcompany");
       
  1575 
       
  1576     QString e; // empty string.. gets a work out
       
  1577 
       
  1578     /* Various empty ones */
       
  1579     QTest::newRow("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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 
       
  1762 void 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(&name);
       
  1810     if (addname2)
       
  1811         c.saveDetail(&name2);
       
  1812     if (addcompany)
       
  1813         c.saveDetail(&org);
       
  1814     if (addcompany2)
       
  1815         c.saveDetail(&org2);
       
  1816 
       
  1817     // Finally!
       
  1818     QCOMPARE(cm.synthesizedContactDisplayLabel(c), expected);
       
  1819 }
       
  1820 
       
  1821 void tst_QContactManager::compatibleContact_data()
       
  1822 {
       
  1823     QTest::addColumn<QContact>("input");
       
  1824     QTest::addColumn<QContact>("expected");
       
  1825     QTest::addColumn<QContactManager::Error>("error");
       
  1826 
       
  1827     QContact baseContact;
       
  1828     QContactName name;
       
  1829     name.setFirstName(QLatin1String("First"));
       
  1830     baseContact.saveDetail(&name);
       
  1831 
       
  1832     {
       
  1833         QTest::newRow("already compatible") << baseContact << baseContact << QContactManager::NoError;
       
  1834     }
       
  1835 
       
  1836     {
       
  1837         QContact contact(baseContact);
       
  1838         QContactDetail detail("UnknownDetail");
       
  1839         detail.setValue("Key", QLatin1String("Value"));
       
  1840         contact.saveDetail(&detail);
       
  1841         QTest::newRow("unknown detail") << contact << baseContact << QContactManager::NoError;
       
  1842     }
       
  1843 
       
  1844     {
       
  1845         QContact contact(baseContact);
       
  1846         QContactType type1;
       
  1847         type1.setType(QContactType::TypeContact);
       
  1848         contact.saveDetail(&type1);
       
  1849         QContactType type2;
       
  1850         type2.setType(QContactType::TypeGroup);
       
  1851         contact.saveDetail(&type2);
       
  1852         QContact expected(baseContact);
       
  1853         expected.saveDetail(&type2);
       
  1854         QTest::newRow("duplicate unique field") << contact << expected << QContactManager::NoError;
       
  1855     }
       
  1856 
       
  1857     {
       
  1858         QContact contact(baseContact);
       
  1859         QContactPhoneNumber phoneNumber;
       
  1860         phoneNumber.setValue("UnknownKey", "Value");
       
  1861         contact.saveDetail(&phoneNumber);
       
  1862         QTest::newRow("unknown field") << contact << baseContact << QContactManager::NoError;
       
  1863     }
       
  1864 
       
  1865     {
       
  1866         QContact contact(baseContact);
       
  1867         QContactDisplayLabel displayLabel;
       
  1868         displayLabel.setValue(QContactDisplayLabel::FieldLabel, QStringList("Value"));
       
  1869         contact.saveDetail(&displayLabel);
       
  1870         QTest::newRow("wrong type") << contact << baseContact << QContactManager::NoError;
       
  1871     }
       
  1872 
       
  1873     {
       
  1874         QContact contact(baseContact);
       
  1875         QContactPhoneNumber phoneNumber1;
       
  1876         phoneNumber1.setNumber(QLatin1String("1234"));
       
  1877         phoneNumber1.setSubTypes(QStringList()
       
  1878                                 << QContactPhoneNumber::SubTypeMobile
       
  1879                                 << QContactPhoneNumber::SubTypeVoice
       
  1880                                 << QLatin1String("InvalidSubtype"));
       
  1881         contact.saveDetail(&phoneNumber1);
       
  1882         QContact expected(baseContact);
       
  1883         QContactPhoneNumber phoneNumber2;
       
  1884         phoneNumber2.setNumber(QLatin1String("1234"));
       
  1885         phoneNumber2.setSubTypes(QStringList()
       
  1886                                 << QContactPhoneNumber::SubTypeMobile
       
  1887                                 << QContactPhoneNumber::SubTypeVoice);
       
  1888         expected.saveDetail(&phoneNumber2);
       
  1889         QTest::newRow("bad value (list)") << contact << expected << QContactManager::NoError;
       
  1890     }
       
  1891 
       
  1892     {
       
  1893         QContact contact(baseContact);
       
  1894         QContactPhoneNumber phoneNumber1;
       
  1895         phoneNumber1.setNumber(QLatin1String("1234"));
       
  1896         phoneNumber1.setSubTypes(QStringList(QLatin1String("InvalidSubtype")));
       
  1897         contact.saveDetail(&phoneNumber1);
       
  1898         QContact expected(baseContact);
       
  1899         QContactPhoneNumber phoneNumber2;
       
  1900         phoneNumber2.setNumber(QLatin1String("1234"));
       
  1901         expected.saveDetail(&phoneNumber2);
       
  1902         QTest::newRow("all bad value (list)") << contact << expected << QContactManager::NoError;
       
  1903     }
       
  1904 
       
  1905     {
       
  1906         QContact contact(baseContact);
       
  1907         QContactGender gender;
       
  1908         gender.setGender(QLatin1String("UnknownGender"));
       
  1909         contact.saveDetail(&gender);
       
  1910         QTest::newRow("bad value (string)") << contact << baseContact << QContactManager::NoError;
       
  1911     }
       
  1912 
       
  1913     {
       
  1914         QContact contact;
       
  1915         QContactGender gender;
       
  1916         gender.setGender(QLatin1String("UnknownGender"));
       
  1917         contact.saveDetail(&gender);
       
  1918         QTest::newRow("bad value (string)") << contact << QContact() << QContactManager::DoesNotExistError;
       
  1919     }
       
  1920 }
       
  1921 
       
  1922 void tst_QContactManager::compatibleContact()
       
  1923 {
       
  1924     QContactManager cm("memory");
       
  1925 
       
  1926     QFETCH(QContact, input);
       
  1927     QFETCH(QContact, expected);
       
  1928     QFETCH(QContactManager::Error, error);
       
  1929     QCOMPARE(cm.compatibleContact(input), expected);
       
  1930     QCOMPARE(cm.error(), error);
       
  1931 }
       
  1932 
       
  1933 void tst_QContactManager::contactValidation()
       
  1934 {
       
  1935     /* Use the memory engine as a reference (validation is not engine specific) */
       
  1936     QScopedPointer<QContactManager> cm(new QContactManager("memory"));
       
  1937     QContact c;
       
  1938 
       
  1939     /*
       
  1940      * Add some definitions for testing:
       
  1941      *
       
  1942      * 1) a unique detail
       
  1943      * 2) a detail with restricted values
       
  1944      * 3) a create only detail
       
  1945      * 4) a unique create only detail
       
  1946      */
       
  1947     QContactDetailDefinition uniqueDef;
       
  1948     QMap<QString, QContactDetailFieldDefinition> fields;
       
  1949     QContactDetailFieldDefinition field;
       
  1950     field.setDataType(QVariant::String);
       
  1951     fields.insert("value", field);
       
  1952 
       
  1953     uniqueDef.setName("UniqueDetail");
       
  1954     uniqueDef.setFields(fields);
       
  1955     uniqueDef.setUnique(true);
       
  1956 
       
  1957     QVERIFY(cm->saveDetailDefinition(uniqueDef));
       
  1958 
       
  1959     QContactDetailDefinition restrictedDef;
       
  1960     restrictedDef.setName("RestrictedDetail");
       
  1961     fields.clear();
       
  1962     field.setAllowableValues(QVariantList() << "One" << "Two" << "Three");
       
  1963     fields.insert("value", field);
       
  1964     restrictedDef.setFields(fields);
       
  1965 
       
  1966     QVERIFY(cm->saveDetailDefinition(restrictedDef));
       
  1967 
       
  1968     // first, test an invalid definition
       
  1969     QContactDetail d1 = QContactDetail("UnknownDefinition");
       
  1970     d1.setValue("test", "test");
       
  1971     c.saveDetail(&d1);
       
  1972     QVERIFY(!cm->saveContact(&c));
       
  1973     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  1974     c.removeDetail(&d1);
       
  1975 
       
  1976     // second, test an invalid uniqueness constraint
       
  1977     QContactDetail d2 = QContactDetail("UniqueDetail");
       
  1978     d2.setValue("value", "test");
       
  1979     c.saveDetail(&d2);
       
  1980 
       
  1981     // One unique should be ok
       
  1982     QVERIFY(cm->saveContact(&c));
       
  1983     QCOMPARE(cm->error(), QContactManager::NoError);
       
  1984 
       
  1985     // Two uniques should not be ok
       
  1986     QContactDetail d3 = QContactDetail("UniqueDetail");
       
  1987     d3.setValue("value", "test2");
       
  1988     c.saveDetail(&d3);
       
  1989     QVERIFY(!cm->saveContact(&c));
       
  1990     QCOMPARE(cm->error(), QContactManager::AlreadyExistsError);
       
  1991     c.removeDetail(&d3);
       
  1992     c.removeDetail(&d2);
       
  1993 
       
  1994     // third, test an invalid field name
       
  1995     QContactDetail d4 = QContactDetail(QContactPhoneNumber::DefinitionName);
       
  1996     d4.setValue("test", "test");
       
  1997     c.saveDetail(&d4);
       
  1998     QVERIFY(!cm->saveContact(&c));
       
  1999     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  2000     c.removeDetail(&d4);
       
  2001 
       
  2002     // fourth, test an invalid field data type
       
  2003     QContactDetail d5 = QContactDetail(QContactPhoneNumber::DefinitionName);
       
  2004     d5.setValue(QContactPhoneNumber::FieldNumber, QDateTime::currentDateTime());
       
  2005     c.saveDetail(&d5);
       
  2006     QVERIFY(!cm->saveContact(&c));
       
  2007     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  2008     c.removeDetail(&d5);
       
  2009 
       
  2010     // fifth, test an invalid field value (not in the allowed list)
       
  2011     QContactDetail d6 = QContactDetail("RestrictedDetail");
       
  2012     d6.setValue("value", "Seven"); // not in One, Two or Three
       
  2013     c.saveDetail(&d6);
       
  2014     QVERIFY(!cm->saveContact(&c));
       
  2015     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  2016     c.removeDetail(&d6);
       
  2017 
       
  2018     /* Now a valid value */
       
  2019     d6.setValue("value", "Two");
       
  2020     c.saveDetail(&d6);
       
  2021     QVERIFY(cm->saveContact(&c));
       
  2022     QCOMPARE(cm->error(), QContactManager::NoError);
       
  2023     c.removeDetail(&d6);
       
  2024 
       
  2025     // Test a completely valid one.
       
  2026     QContactDetail d7 = QContactDetail(QContactPhoneNumber::DefinitionName);
       
  2027     d7.setValue(QContactPhoneNumber::FieldNumber, "0123456");
       
  2028     c.saveDetail(&d7);
       
  2029     QVERIFY(cm->saveContact(&c));
       
  2030     QCOMPARE(cm->error(), QContactManager::NoError);
       
  2031     c.removeDetail(&d7);
       
  2032 }
       
  2033 
       
  2034 void tst_QContactManager::signalEmission()
       
  2035 {
       
  2036     QTest::qWait(500); // clear the signal queue
       
  2037     QFETCH(QString, uri);
       
  2038     QScopedPointer<QContactManager> m1(QContactManager::fromUri(uri));
       
  2039 
       
  2040     qRegisterMetaType<QContactLocalId>("QContactLocalId");
       
  2041     qRegisterMetaType<QList<QContactLocalId> >("QList<QContactLocalId>");
       
  2042     QSignalSpy spyCA(m1.data(), SIGNAL(contactsAdded(QList<QContactLocalId>)));
       
  2043     QSignalSpy spyCM(m1.data(), SIGNAL(contactsChanged(QList<QContactLocalId>)));
       
  2044     QSignalSpy spyCR(m1.data(), SIGNAL(contactsRemoved(QList<QContactLocalId>)));
       
  2045 
       
  2046     QList<QVariant> args;
       
  2047     QList<QContactLocalId> arg;
       
  2048     QContact c;
       
  2049     QList<QContact> batchAdd;
       
  2050     QList<QContactLocalId> batchRemove;
       
  2051     QList<QContactLocalId> sigids;
       
  2052     int addSigCount = 0; // the expected signal counts.
       
  2053     int modSigCount = 0;
       
  2054     int remSigCount = 0;
       
  2055 
       
  2056     QContactDetailDefinition nameDef = m1->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
  2057 
       
  2058     // verify add emits signal added
       
  2059     QContactName nc;
       
  2060     saveContactName(&c, nameDef, &nc, "John");
       
  2061     QVERIFY(m1->saveContact(&c));
       
  2062     QContactLocalId cid = c.id().localId();
       
  2063     addSigCount += 1;
       
  2064     QTRY_COMPARE(spyCA.count(), addSigCount);
       
  2065     args = spyCA.takeFirst();
       
  2066     addSigCount -= 1;
       
  2067     arg = args.first().value<QList<quint32> >();
       
  2068     QVERIFY(arg.count() == 1);
       
  2069     QCOMPARE(QContactLocalId(arg.at(0)), cid);
       
  2070 
       
  2071     // verify save modified emits signal changed
       
  2072     saveContactName(&c, nameDef, &nc, "Citizen");
       
  2073     QVERIFY(m1->saveContact(&c));
       
  2074     modSigCount += 1;
       
  2075     QTRY_COMPARE(spyCM.count(), modSigCount);
       
  2076     args = spyCM.takeFirst();
       
  2077     modSigCount -= 1;
       
  2078     arg = args.first().value<QList<quint32> >();
       
  2079     QVERIFY(arg.count() == 1);
       
  2080     QCOMPARE(QContactLocalId(arg.at(0)), cid);
       
  2081 
       
  2082     // verify remove emits signal removed
       
  2083     m1->removeContact(c.id().localId());
       
  2084     remSigCount += 1;
       
  2085     QTRY_COMPARE(spyCR.count(), remSigCount);
       
  2086     args = spyCR.takeFirst();
       
  2087     remSigCount -= 1;
       
  2088     arg = args.first().value<QList<quint32> >();
       
  2089     QVERIFY(arg.count() == 1);
       
  2090     QCOMPARE(QContactLocalId(arg.at(0)), cid);
       
  2091 
       
  2092     // verify multiple adds works as advertised
       
  2093     QContact c2, c3;
       
  2094     QContactName nc2, nc3;
       
  2095     saveContactName(&c2, nameDef, &nc2, "Mark");
       
  2096     saveContactName(&c3, nameDef, &nc3, "Garry");
       
  2097 #if defined(Q_OS_SYMBIAN)
       
  2098     // TODO: symbiansim backend fails this test currently. Commented out for
       
  2099     // now. Will be fixed later.
       
  2100     if(!uri.contains("symbiansim")) {
       
  2101         QVERIFY(!m1->saveContact(&c)); // saving contact with nonexistent id fails
       
  2102     }
       
  2103 #endif
       
  2104     QVERIFY(m1->saveContact(&c2));
       
  2105     addSigCount += 1;
       
  2106     QVERIFY(m1->saveContact(&c3));
       
  2107     addSigCount += 1;
       
  2108     QTRY_COMPARE(spyCM.count(), modSigCount);
       
  2109     QTRY_COMPARE(spyCA.count(), addSigCount);
       
  2110 
       
  2111     // verify multiple modifies works as advertised
       
  2112     saveContactName(&c2, nameDef, &nc2, "M.");
       
  2113     QVERIFY(m1->saveContact(&c2));
       
  2114     modSigCount += 1;
       
  2115     saveContactName(&c2, nameDef, &nc2, "Mark");
       
  2116     saveContactName(&c3, nameDef, &nc3, "G.");
       
  2117     QVERIFY(m1->saveContact(&c2));
       
  2118     modSigCount += 1;
       
  2119     QVERIFY(m1->saveContact(&c3));
       
  2120     modSigCount += 1;
       
  2121     QTRY_COMPARE(spyCM.count(), modSigCount);
       
  2122 
       
  2123     // verify multiple removes works as advertised
       
  2124     m1->removeContact(c3.id().localId());
       
  2125     remSigCount += 1;
       
  2126     m1->removeContact(c2.id().localId());
       
  2127     remSigCount += 1;
       
  2128     QTRY_COMPARE(spyCR.count(), remSigCount);
       
  2129 
       
  2130     QVERIFY(!m1->removeContact(c.id().localId())); // not saved.
       
  2131 
       
  2132     /* Now test the batch equivalents */
       
  2133     spyCA.clear();
       
  2134     spyCM.clear();
       
  2135     spyCR.clear();
       
  2136 
       
  2137     /* Batch adds - set ids to zero so add succeeds. */
       
  2138     c.setId(QContactId());
       
  2139     c2.setId(QContactId());
       
  2140     c3.setId(QContactId());
       
  2141     batchAdd << c << c2 << c3;
       
  2142     QMap<int, QContactManager::Error> errorMap;
       
  2143     QVERIFY(m1->saveContacts(&batchAdd, &errorMap));
       
  2144 
       
  2145     QVERIFY(batchAdd.count() == 3);
       
  2146     c = batchAdd.at(0);
       
  2147     c2 = batchAdd.at(1);
       
  2148     c3 = batchAdd.at(2);
       
  2149 
       
  2150     /* We basically loop, processing events, until we've seen an Add signal for each contact */
       
  2151     sigids.clear();
       
  2152 
       
  2153     QTRY_WAIT( while(spyCA.size() > 0) {sigids += spyCA.takeFirst().at(0).value<QList<QContactLocalId> >(); }, sigids.contains(c.localId()) && sigids.contains(c2.localId()) && sigids.contains(c3.localId()));
       
  2154     QTRY_COMPARE(spyCM.count(), 0);
       
  2155     QTRY_COMPARE(spyCR.count(), 0);
       
  2156 
       
  2157     /* Batch modifies */
       
  2158     QContactName modifiedName = c.detail(QContactName::DefinitionName);
       
  2159     saveContactName(&c, nameDef, &modifiedName, "Modified number 1");
       
  2160     modifiedName = c2.detail(QContactName::DefinitionName);
       
  2161     saveContactName(&c2, nameDef, &modifiedName, "Modified number 2");
       
  2162     modifiedName = c3.detail(QContactName::DefinitionName);
       
  2163     saveContactName(&c3, nameDef, &modifiedName, "Modified number 3");
       
  2164 
       
  2165     batchAdd.clear();
       
  2166     batchAdd << c << c2 << c3;
       
  2167     QVERIFY(m1->saveContacts(&batchAdd, &errorMap));
       
  2168 
       
  2169     sigids.clear();
       
  2170     QTRY_WAIT( while(spyCM.size() > 0) {sigids += spyCM.takeFirst().at(0).value<QList<QContactLocalId> >(); }, sigids.contains(c.localId()) && sigids.contains(c2.localId()) && sigids.contains(c3.localId()));
       
  2171 
       
  2172     /* Batch removes */
       
  2173     batchRemove << c.id().localId() << c2.id().localId() << c3.id().localId();
       
  2174     QVERIFY(m1->removeContacts(batchRemove, &errorMap));
       
  2175 
       
  2176     sigids.clear();
       
  2177     QTRY_WAIT( while(spyCR.size() > 0) {sigids += spyCR.takeFirst().at(0).value<QList<QContactLocalId> >(); }, sigids.contains(c.localId()) && sigids.contains(c2.localId()) && sigids.contains(c3.localId()));
       
  2178 
       
  2179     QTRY_COMPARE(spyCA.count(), 0);
       
  2180     QTRY_COMPARE(spyCM.count(), 0);
       
  2181 
       
  2182     QScopedPointer<QContactManager> m2(QContactManager::fromUri(uri));
       
  2183     
       
  2184     // During construction SIM backend (m2) will try writing contacts with 
       
  2185     // nickname, email and additional number to find out if the SIM card
       
  2186     // will support these fields. The other backend (m1) will then receive
       
  2187     // signals about that. These need to be caught so they don't interfere
       
  2188     // with the tests. (This trial and error method is used because existing
       
  2189     // API for checking the availability of these fields is not public.)
       
  2190 	// NOTE: This applies only to pre 10.1 platforms (S60 3.1, 3.2, ect.)
       
  2191     if (uri.contains("symbiansim")) {
       
  2192         QTest::qWait(0);
       
  2193         spyCA.clear();
       
  2194         spyCM.clear();
       
  2195         spyCR.clear();
       
  2196     }
       
  2197 
       
  2198     QVERIFY(m1->hasFeature(QContactManager::Anonymous) ==
       
  2199         m2->hasFeature(QContactManager::Anonymous));
       
  2200 
       
  2201     /* Now some cross manager testing */
       
  2202     if (!m1->hasFeature(QContactManager::Anonymous)) {
       
  2203         // verify that signals are emitted for modifications made to other managers (same id).
       
  2204         QContactName ncs = c.detail(QContactName::DefinitionName);
       
  2205         saveContactName(&c, nameDef, &ncs, "Test");
       
  2206         c.setId(QContactId()); // reset id so save can succeed.
       
  2207         QVERIFY(m2->saveContact(&c));
       
  2208         saveContactName(&c, nameDef, &ncs, "Test2");
       
  2209         QVERIFY(m2->saveContact(&c));
       
  2210         QTRY_COMPARE(spyCA.count(), 1); // check that we received the update signals.
       
  2211         QTRY_COMPARE(spyCM.count(), 1); // check that we received the update signals.
       
  2212         m2->removeContact(c.localId());
       
  2213         QTRY_COMPARE(spyCR.count(), 1); // check that we received the remove signal.
       
  2214     }
       
  2215 }
       
  2216 
       
  2217 void tst_QContactManager::errorStayingPut()
       
  2218 {
       
  2219     /* Make sure that when we clone a manager, we don't clone the error */
       
  2220     QMap<QString, QString> params;
       
  2221     params.insert("id", "error isolation test");
       
  2222     QContactManager m1("memory",params);
       
  2223 
       
  2224     QVERIFY(m1.error() == QContactManager::NoError);
       
  2225 
       
  2226     /* Remove an invalid contact to get an error */
       
  2227     QVERIFY(m1.removeContact(0) == false);
       
  2228     QVERIFY(m1.error() == QContactManager::DoesNotExistError);
       
  2229 
       
  2230     /* Create a new manager with hopefully the same backend */
       
  2231     QContactManager m2("memory", params);
       
  2232 
       
  2233     QVERIFY(m1.error() == QContactManager::DoesNotExistError);
       
  2234     QVERIFY(m2.error() == QContactManager::NoError);
       
  2235 
       
  2236     /* Cause an error on the other ones and check the first is not affected */
       
  2237     m2.saveContacts(0, 0);
       
  2238     QVERIFY(m1.error() == QContactManager::DoesNotExistError);
       
  2239     QVERIFY(m2.error() == QContactManager::BadArgumentError);
       
  2240 
       
  2241     QContact c;
       
  2242     QContactDetail d("This does not exist and if it does this will break");
       
  2243     d.setValue("Value that also doesn't exist", 5);
       
  2244     c.saveDetail(&d);
       
  2245 
       
  2246     QVERIFY(m1.saveContact(&c) == false);
       
  2247     QVERIFY(m1.error() == QContactManager::InvalidDetailError);
       
  2248     QVERIFY(m2.error() == QContactManager::BadArgumentError);
       
  2249 }
       
  2250 
       
  2251 void tst_QContactManager::detailDefinitions()
       
  2252 {
       
  2253     QFETCH(QString, uri);
       
  2254     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2255     QMap<QString, QContactDetailDefinition> defs = cm->detailDefinitions();
       
  2256 
       
  2257     /* Validate the existing definitions */
       
  2258 
       
  2259     // Do some sanity checking on the definitions first
       
  2260     if (defs.keys().count() != defs.uniqueKeys().count()) {
       
  2261         qDebug() << "ERROR - duplicate definitions with the same name:";
       
  2262 
       
  2263         QList<QString> defkeys = defs.keys();
       
  2264         foreach(QString uniq, defs.uniqueKeys()) {
       
  2265             if (defkeys.count(uniq) > 1) {
       
  2266                 qDebug() << QString(" %1").arg(uniq).toAscii().constData();
       
  2267                 defkeys.removeAll(uniq);
       
  2268             }
       
  2269         }
       
  2270         QVERIFY(defs.keys().count() == defs.uniqueKeys().count());
       
  2271     }
       
  2272 
       
  2273     foreach(QContactDetailDefinition def, defs.values()) {
       
  2274         QMap<QString, QContactDetailFieldDefinition> fields = def.fields();
       
  2275 
       
  2276         // Again some sanity checking
       
  2277         if (fields.keys().count() != fields.uniqueKeys().count()) {
       
  2278             qDebug() << "ERROR - duplicate fields with the same name:";
       
  2279 
       
  2280             QList<QString> defkeys = fields.keys();
       
  2281             foreach(QString uniq, fields.uniqueKeys()) {
       
  2282                 if (defkeys.count(uniq) > 1) {
       
  2283                     qDebug() << QString(" %2::%1").arg(uniq).arg(def.name()).toAscii().constData();
       
  2284                     defkeys.removeAll(uniq);
       
  2285                 }
       
  2286             }
       
  2287             QVERIFY(fields.keys().count() == fields.uniqueKeys().count());
       
  2288         }
       
  2289 
       
  2290         foreach(QContactDetailFieldDefinition field, def.fields().values()) {
       
  2291             // Sanity check the allowed values
       
  2292             if (field.allowableValues().count() > 0) {
       
  2293                 if (field.dataType() == QVariant::StringList) {
       
  2294                     // We accept QString or QStringList allowed values
       
  2295                     foreach(QVariant var, field.allowableValues()) {
       
  2296                         if (var.type() != QVariant::String && var.type() != QVariant::StringList) {
       
  2297                             QString foo;
       
  2298                             QDebug dbg(&foo);
       
  2299                             dbg.nospace() << var;
       
  2300                             qDebug().nospace() << "Field " << QString("%1::%2").arg(def.name()).arg(def.fields().key(field)).toAscii().constData() << " allowable value '" << foo.simplified().toAscii().constData() << "' not supported for field type " << QMetaType::typeName(field.dataType());
       
  2301                         }
       
  2302                         QVERIFY(var.type() == QVariant::String || var.type() == QVariant::StringList);
       
  2303                     }
       
  2304                 } else if (field.dataType() == QVariant::List || field.dataType() == QVariant::Map || field.dataType() == (QVariant::Type) qMetaTypeId<QVariant>()) {
       
  2305                     // Well, anything goes
       
  2306                 } else {
       
  2307                     // The type of each allowed value must match the data type
       
  2308                     foreach(QVariant var, field.allowableValues()) {
       
  2309                         if (var.type() != field.dataType()) {
       
  2310                             QString foo;
       
  2311                             QDebug dbg(&foo);
       
  2312                             dbg.nospace() << var;
       
  2313                             qDebug().nospace() << "Field " << QString("%1::%2").arg(def.name()).arg(def.fields().key(field)).toAscii().constData() << " allowable value '" << foo.simplified().toAscii().constData() << "' not supported for field type " << QMetaType::typeName(field.dataType());
       
  2314                         }
       
  2315                         QVERIFY(var.type() == field.dataType());
       
  2316                     }
       
  2317                 }
       
  2318             }
       
  2319         }
       
  2320     }
       
  2321 
       
  2322 
       
  2323     /* Try to make a credible definition */
       
  2324     QContactDetailDefinition newDef;
       
  2325     QContactDetailFieldDefinition field;
       
  2326     QMap<QString, QContactDetailFieldDefinition> fields;
       
  2327     field.setDataType(cm->supportedDataTypes().value(0));
       
  2328     fields.insert("New Value", field);
       
  2329     newDef.setName("New Definition");
       
  2330     newDef.setFields(fields);
       
  2331 
       
  2332     /* Updated version of an existing definition */
       
  2333     QContactDetailDefinition updatedDef = defs.begin().value(); // XXX TODO Fixme
       
  2334     fields = updatedDef.fields();
       
  2335     fields.insert("New Value", field);
       
  2336     updatedDef.setFields(fields);
       
  2337 
       
  2338     /* A detail definition with valid allowed values (or really just one) */
       
  2339     QContactDetailDefinition allowedDef = newDef;
       
  2340     field.setAllowableValues(field.allowableValues() << (QVariant(field.dataType())));
       
  2341     fields.clear();
       
  2342     fields.insert("Restricted value", field);
       
  2343     allowedDef.setFields(fields);
       
  2344 
       
  2345     /* Many invalid definitions */
       
  2346     QContactDetailDefinition noIdDef;
       
  2347     noIdDef.setFields(fields);
       
  2348 
       
  2349     QContactDetailDefinition noFieldsDef;
       
  2350     noFieldsDef.setName("No fields");
       
  2351 
       
  2352     QContactDetailDefinition invalidFieldKeyDef;
       
  2353     invalidFieldKeyDef.setName("Invalid field key");
       
  2354     QMap<QString, QContactDetailFieldDefinition> badfields;
       
  2355     badfields.insert(QString(), field);
       
  2356     invalidFieldKeyDef.setFields(badfields);
       
  2357 
       
  2358     QContactDetailDefinition invalidFieldTypeDef;
       
  2359     invalidFieldTypeDef.setName("Invalid field type");
       
  2360     badfields.clear();
       
  2361     QContactDetailFieldDefinition badfield;
       
  2362     badfield.setDataType((QVariant::Type) qMetaTypeId<UnsupportedMetatype>());
       
  2363     badfields.insert("Bad type", badfield);
       
  2364     invalidFieldTypeDef.setFields(badfields);
       
  2365 
       
  2366     QContactDetailDefinition invalidAllowedValuesDef;
       
  2367     invalidAllowedValuesDef.setName("Invalid field allowed values");
       
  2368     badfields.clear();
       
  2369     badfield.setDataType(field.dataType()); // use a supported type
       
  2370     badfield.setAllowableValues(QList<QVariant>() << "String" << 5); // but unsupported value
       
  2371     badfields.insert("Bad allowed", badfield);
       
  2372     invalidAllowedValuesDef.setFields(badfields);
       
  2373 
       
  2374     /* XXX Multiply defined fields.. depends on semantichangeSet. */
       
  2375 
       
  2376     if (cm->hasFeature(QContactManager::MutableDefinitions)) {
       
  2377         /* First do some negative testing */
       
  2378 
       
  2379         /* Bad add class */
       
  2380         QVERIFY(cm->saveDetailDefinition(QContactDetailDefinition()) == false);
       
  2381         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2382 
       
  2383         /* Bad remove string */
       
  2384         QVERIFY(cm->removeDetailDefinition(QString()) == false);
       
  2385         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2386 
       
  2387         QVERIFY(cm->saveDetailDefinition(noIdDef) == false);
       
  2388         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2389 
       
  2390         QVERIFY(cm->saveDetailDefinition(noFieldsDef) == false);
       
  2391         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2392 
       
  2393         QVERIFY(cm->saveDetailDefinition(invalidFieldKeyDef) == false);
       
  2394         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2395 
       
  2396         QVERIFY(cm->saveDetailDefinition(invalidFieldTypeDef) == false);
       
  2397         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2398 
       
  2399         QVERIFY(cm->saveDetailDefinition(invalidAllowedValuesDef) == false);
       
  2400         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2401 
       
  2402         /* Check that our new definition doesn't already exist */
       
  2403         QVERIFY(cm->detailDefinition(newDef.name()).isEmpty());
       
  2404         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2405 
       
  2406         QVERIFY(cm->removeDetailDefinition(newDef.name()) == false);
       
  2407         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2408 
       
  2409         /* Add a new definition */
       
  2410         QVERIFY(cm->saveDetailDefinition(newDef) == true);
       
  2411         QVERIFY(cm->error() == QContactManager::NoError);
       
  2412 
       
  2413         /* Now retrieve it */
       
  2414         QContactDetailDefinition def = cm->detailDefinition(newDef.name());
       
  2415         QVERIFY(def == newDef);
       
  2416 
       
  2417         /* Update it */
       
  2418         QMap<QString, QContactDetailFieldDefinition> newFields = def.fields();
       
  2419         newFields.insert("Another new value", field);
       
  2420         newDef.setFields(newFields);
       
  2421 
       
  2422         QVERIFY(cm->saveDetailDefinition(newDef) == true);
       
  2423         QVERIFY(cm->error() == QContactManager::NoError);
       
  2424 
       
  2425         QVERIFY(cm->detailDefinition(newDef.name()) == newDef);
       
  2426 
       
  2427         /* Remove it */
       
  2428         QVERIFY(cm->removeDetailDefinition(newDef.name()) == true);
       
  2429         QVERIFY(cm->error() == QContactManager::NoError);
       
  2430 
       
  2431         /* and make sure it does not exist any more */
       
  2432         QVERIFY(cm->detailDefinition(newDef.name()) == QContactDetailDefinition());
       
  2433         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2434 
       
  2435         /* Add the other good one */
       
  2436         QVERIFY(cm->saveDetailDefinition(allowedDef) == true);
       
  2437         QVERIFY(cm->error() == QContactManager::NoError);
       
  2438 
       
  2439         QVERIFY(allowedDef == cm->detailDefinition(allowedDef.name()));
       
  2440 
       
  2441         /* and remove it */
       
  2442         QVERIFY(cm->removeDetailDefinition(allowedDef.name()) == true);
       
  2443         QVERIFY(cm->detailDefinition(allowedDef.name()) == QContactDetailDefinition());
       
  2444         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2445 
       
  2446     } else {
       
  2447         /* Bad add class */
       
  2448         QVERIFY(cm->saveDetailDefinition(QContactDetailDefinition()) == false);
       
  2449         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2450 
       
  2451         /* Make sure we can't add/remove/modify detail definitions */
       
  2452         QVERIFY(cm->removeDetailDefinition(QString()) == false);
       
  2453         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2454 
       
  2455         /* Try updating an existing definition */
       
  2456         QVERIFY(cm->saveDetailDefinition(updatedDef) == false);
       
  2457         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2458 
       
  2459         /* Try removing an existing definition */
       
  2460         QVERIFY(cm->removeDetailDefinition(updatedDef.name()) == false);
       
  2461         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2462     }
       
  2463 }
       
  2464 
       
  2465 void tst_QContactManager::displayName()
       
  2466 {
       
  2467     QFETCH(QString, uri);
       
  2468     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2469 
       
  2470     /*
       
  2471      * Very similar to the tst_QContact functions, except we test
       
  2472      * saving and retrieving contacts updates the display label
       
  2473      */
       
  2474 
       
  2475     /* Try to make this a bit more consistent by using a single name */
       
  2476     QContact d;
       
  2477     QContactName name;
       
  2478     saveContactName(&d, cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact), &name, "Wesley");
       
  2479 
       
  2480     QVERIFY(d.displayLabel().isEmpty());
       
  2481 
       
  2482     QString synth = cm->synthesizedContactDisplayLabel(d);
       
  2483 
       
  2484     // Make sure this doesn't crash
       
  2485     cm->synthesizeContactDisplayLabel(0);
       
  2486 
       
  2487     // Make sure this gives the same results
       
  2488     cm->synthesizeContactDisplayLabel(&d);
       
  2489     QCOMPARE(d.displayLabel(), synth);
       
  2490 
       
  2491     /*
       
  2492      * The display label is not updated until you save the contact or call synthCDL
       
  2493      */
       
  2494     QVERIFY(cm->saveContact(&d));
       
  2495     d = cm->contact(d.id().localId());
       
  2496     QVERIFY(!d.isEmpty());
       
  2497     QCOMPARE(d.displayLabel(), synth);
       
  2498 
       
  2499     /* Remove the detail via removeDetail */
       
  2500     QContactDisplayLabel old;
       
  2501     int count = d.details().count();
       
  2502     QVERIFY(!d.removeDetail(&old)); // should fail.
       
  2503     QVERIFY(d.isEmpty() == false);
       
  2504     QVERIFY(d.details().count() == count); // it should not be removed!
       
  2505 
       
  2506     /* Save the contact again */
       
  2507     QVERIFY(cm->saveContact(&d));
       
  2508     d = cm->contact(d.id().localId());
       
  2509     QVERIFY(!d.isEmpty());
       
  2510 
       
  2511     /* Make sure the label is still the synth version */
       
  2512     QCOMPARE(d.displayLabel(), synth);
       
  2513 
       
  2514     /* And delete the contact */
       
  2515     QVERIFY(cm->removeContact(d.id().localId()));
       
  2516 }
       
  2517 
       
  2518 void tst_QContactManager::actionPreferences()
       
  2519 {
       
  2520     QFETCH(QString, uri);
       
  2521     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2522 
       
  2523     // early out if the manager doesn't support action preference saving.
       
  2524     if (!cm->hasFeature(QContactManager::ActionPreferences)) {
       
  2525         QSKIP("Manager does not support action preferences", SkipSingle);
       
  2526     }
       
  2527 
       
  2528     // create a sample contact
       
  2529     QContactAvatar a;
       
  2530     a.setImageUrl(QUrl("test.png"));
       
  2531     QContactPhoneNumber p1;
       
  2532     p1.setNumber("12345");
       
  2533     QContactPhoneNumber p2;
       
  2534     p2.setNumber("34567");
       
  2535     QContactPhoneNumber p3;
       
  2536     p3.setNumber("56789");
       
  2537     QContactUrl u;
       
  2538     u.setUrl("http://test.nokia.com");
       
  2539     QContactName n;
       
  2540     QContact c;
       
  2541     saveContactName(&c, cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact), &n, "TestContact");
       
  2542     c.saveDetail(&a);
       
  2543     c.saveDetail(&p1);
       
  2544     c.saveDetail(&p2);
       
  2545     c.saveDetail(&p3);
       
  2546     c.saveDetail(&u);
       
  2547 
       
  2548     QVERIFY(cm->saveContact(&c));          // save the contact
       
  2549     QContact loaded = cm->contact(c.id().localId()); // reload the contact
       
  2550     cm->removeContact(c.id().localId());
       
  2551 }
       
  2552 
       
  2553 void tst_QContactManager::changeSet()
       
  2554 {
       
  2555     QContactLocalId id(1);
       
  2556 
       
  2557     QContactChangeSet changeSet;
       
  2558     QVERIFY(changeSet.addedContacts().isEmpty());
       
  2559     QVERIFY(changeSet.changedContacts().isEmpty());
       
  2560     QVERIFY(changeSet.removedContacts().isEmpty());
       
  2561 
       
  2562     changeSet.insertAddedContact(id);
       
  2563     QVERIFY(!changeSet.addedContacts().isEmpty());
       
  2564     QVERIFY(changeSet.changedContacts().isEmpty());
       
  2565     QVERIFY(changeSet.removedContacts().isEmpty());
       
  2566     QVERIFY(changeSet.addedContacts().contains(id));
       
  2567 
       
  2568     changeSet.insertChangedContact(id);
       
  2569     changeSet.insertChangedContacts(QList<QContactLocalId>() << id);
       
  2570     QVERIFY(changeSet.changedContacts().size() == 1); // set, should only be added once.
       
  2571     QVERIFY(!changeSet.addedContacts().isEmpty());
       
  2572     QVERIFY(!changeSet.changedContacts().isEmpty());
       
  2573     QVERIFY(changeSet.removedContacts().isEmpty());
       
  2574     QVERIFY(changeSet.changedContacts().contains(id));
       
  2575     changeSet.clearChangedContacts();
       
  2576     QVERIFY(changeSet.changedContacts().isEmpty());
       
  2577 
       
  2578     changeSet.insertRemovedContacts(QList<QContactLocalId>() << id);
       
  2579     QVERIFY(changeSet.removedContacts().contains(id));
       
  2580     changeSet.clearRemovedContacts();
       
  2581     QVERIFY(changeSet.removedContacts().isEmpty());
       
  2582 
       
  2583     QVERIFY(changeSet.dataChanged() == false);
       
  2584     QContactChangeSet changeSet2;
       
  2585     changeSet2 = changeSet;
       
  2586     QVERIFY(changeSet.addedContacts() == changeSet2.addedContacts());
       
  2587     changeSet.emitSignals(0);
       
  2588 
       
  2589     changeSet2.clearAddedContacts();
       
  2590     QVERIFY(changeSet2.addedContacts().isEmpty());
       
  2591     changeSet2.insertAddedContacts(changeSet.addedContacts().toList());
       
  2592     QVERIFY(changeSet.addedContacts() == changeSet2.addedContacts());
       
  2593 
       
  2594     changeSet2.clearAll();
       
  2595     QVERIFY(changeSet.addedContacts() != changeSet2.addedContacts());
       
  2596 
       
  2597     QContactChangeSet changeSet3(changeSet2);
       
  2598     QVERIFY(changeSet.addedContacts() != changeSet3.addedContacts());
       
  2599     QVERIFY(changeSet2.addedContacts() == changeSet3.addedContacts());
       
  2600 
       
  2601     changeSet.setDataChanged(true);
       
  2602     QVERIFY(changeSet.dataChanged() == true);
       
  2603     QVERIFY(changeSet.dataChanged() != changeSet2.dataChanged());
       
  2604     QVERIFY(changeSet.dataChanged() != changeSet3.dataChanged());
       
  2605     changeSet.emitSignals(0);
       
  2606 
       
  2607     changeSet.addedRelationshipsContacts().insert(id);
       
  2608     changeSet.insertAddedRelationshipsContacts(QList<QContactLocalId>() << id);
       
  2609     QVERIFY(changeSet.addedRelationshipsContacts().contains(id));
       
  2610     changeSet.clearAddedRelationshipsContacts();
       
  2611     QVERIFY(changeSet.addedRelationshipsContacts().isEmpty());
       
  2612     changeSet.insertRemovedRelationshipsContacts(QList<QContactLocalId>() << id);
       
  2613     QVERIFY(changeSet.removedRelationshipsContacts().contains(id));
       
  2614     changeSet.clearRemovedRelationshipsContacts();
       
  2615     QVERIFY(changeSet.removedRelationshipsContacts().isEmpty());
       
  2616     changeSet.emitSignals(0);
       
  2617     changeSet.removedRelationshipsContacts().insert(id);
       
  2618     changeSet.emitSignals(0);
       
  2619 
       
  2620     changeSet.setOldAndNewSelfContactId(QPair<QContactLocalId, QContactLocalId>(QContactLocalId(0), id));
       
  2621     changeSet2 = changeSet;
       
  2622     QVERIFY(changeSet2.addedRelationshipsContacts() == changeSet.addedRelationshipsContacts());
       
  2623     QVERIFY(changeSet2.removedRelationshipsContacts() == changeSet.removedRelationshipsContacts());
       
  2624     QVERIFY(changeSet2.oldAndNewSelfContactId() == changeSet.oldAndNewSelfContactId());
       
  2625     changeSet.emitSignals(0);
       
  2626     changeSet.setOldAndNewSelfContactId(QPair<QContactLocalId, QContactLocalId>(id, QContactLocalId(0)));
       
  2627     QVERIFY(changeSet2.oldAndNewSelfContactId() != changeSet.oldAndNewSelfContactId());
       
  2628     changeSet.setDataChanged(true);
       
  2629     changeSet.emitSignals(0);
       
  2630 }
       
  2631 
       
  2632 void tst_QContactManager::fetchHint()
       
  2633 {
       
  2634     QContactFetchHint hint;
       
  2635     hint.setOptimizationHints(QContactFetchHint::NoBinaryBlobs);
       
  2636     QCOMPARE(hint.optimizationHints(), QContactFetchHint::NoBinaryBlobs);
       
  2637     QStringList rels;
       
  2638     rels << QString(QLatin1String(QContactRelationship::HasMember));
       
  2639     hint.setRelationshipTypesHint(rels);
       
  2640     QCOMPARE(hint.relationshipTypesHint(), rels);
       
  2641 }
       
  2642 
       
  2643 void tst_QContactManager::selfContactId()
       
  2644 {
       
  2645     QFETCH(QString, uri);
       
  2646     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2647 
       
  2648     // early out if the manager doesn't support self contact id saving
       
  2649     QContactLocalId selfContact = cm->selfContactId();
       
  2650     if (!cm->hasFeature(QContactManager::SelfContact)) {
       
  2651         // ensure that the error codes / return values are meaningful failures.
       
  2652         QEXPECT_FAIL("mgr='maemo5'", "maemo5 supports getting the self contact but not setting it.", Continue);
       
  2653         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2654         QVERIFY(!cm->setSelfContactId(QContactLocalId(123)));
       
  2655         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2656         QSKIP("Manager does not support the concept of a self-contact", SkipSingle);
       
  2657     }
       
  2658 
       
  2659     // create a new "self" contact and retrieve its Id
       
  2660     QVERIFY(cm->error() == QContactManager::NoError || cm->error() == QContactManager::DoesNotExistError);
       
  2661     QContact self;
       
  2662     QContactPhoneNumber selfPhn;
       
  2663     selfPhn.setNumber("12345");
       
  2664     self.saveDetail(&selfPhn);
       
  2665     if (!cm->saveContact(&self)) {
       
  2666         QSKIP("Unable to save the generated self contact", SkipSingle);
       
  2667     }
       
  2668     QContactLocalId newSelfContact = self.localId();
       
  2669 
       
  2670     // Setup signal spy
       
  2671     qRegisterMetaType<QContactLocalId>("QContactLocalId");
       
  2672     QSignalSpy spy(cm.data(), SIGNAL(selfContactIdChanged(QContactLocalId,QContactLocalId)));
       
  2673 
       
  2674     // Set new self contact
       
  2675     QVERIFY(cm->setSelfContactId(newSelfContact));
       
  2676     QVERIFY(cm->error() == QContactManager::NoError);
       
  2677     QTRY_VERIFY(spy.count() == 1);
       
  2678     QVERIFY(spy.at(0).count() == 2);
       
  2679     // note: for some reason qvariant_cast<QContactLocalId>(spy.at(0).at(0)) returns always zero
       
  2680     // because the type is not recognized. Hence the ugly casting below.
       
  2681     QVERIFY(*((const QContactLocalId*) spy.at(0).at(0).constData()) == selfContact);
       
  2682     QVERIFY(*((const QContactLocalId*) spy.at(0).at(1).constData()) == newSelfContact);
       
  2683     QVERIFY(cm->selfContactId() == newSelfContact);
       
  2684 
       
  2685     // Remove self contact
       
  2686     if(!cm->removeContact(self.localId())) {
       
  2687         QSKIP("Unable to remove self contact", SkipSingle);
       
  2688     }
       
  2689     QTRY_VERIFY(spy.count() == 2);
       
  2690     QVERIFY(spy.at(1).count() == 2);
       
  2691     QVERIFY(*((const QContactLocalId*) spy.at(1).at(0).constData()) == newSelfContact);
       
  2692     QVERIFY(*((const QContactLocalId*) spy.at(1).at(1).constData()) == QContactLocalId(0));
       
  2693     QVERIFY(cm->selfContactId() == QContactLocalId(0)); // ensure reset after removed.
       
  2694 
       
  2695     // reset to original state.
       
  2696     cm->setSelfContactId(selfContact);
       
  2697 }
       
  2698 
       
  2699 QList<QContactDetail> tst_QContactManager::removeAllDefaultDetails(const QList<QContactDetail>& details)
       
  2700 {
       
  2701     QList<QContactDetail> newlist;
       
  2702     foreach (const QContactDetail d, details) {
       
  2703         if (d.definitionName() != QContactDisplayLabel::DefinitionName
       
  2704                 && d.definitionName() != QContactType::DefinitionName
       
  2705                 && d.definitionName() != QContactTimestamp::DefinitionName) {
       
  2706             newlist << d;
       
  2707         }
       
  2708     }
       
  2709     return newlist;
       
  2710 }
       
  2711 
       
  2712 void tst_QContactManager::detailOrders()
       
  2713 {
       
  2714     QFETCH(QString, uri);
       
  2715     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2716 
       
  2717     if (!cm->hasFeature(QContactManager::DetailOrdering))
       
  2718         QSKIP("Skipping: This manager does not support detail ordering!", SkipSingle);
       
  2719 
       
  2720     QContact a;
       
  2721     //phone numbers
       
  2722 
       
  2723     QContactDetailDefinition d = cm->detailDefinition(QContactPhoneNumber::DefinitionName, QContactType::TypeContact);
       
  2724     QContactDetailFieldDefinition supportedContexts = d.fields().value(QContactDetail::FieldContext);
       
  2725     QString contextOther = QContactDetail::ContextOther;
       
  2726     if (!supportedContexts.allowableValues().contains(contextOther)) {
       
  2727         contextOther = QString();
       
  2728     }    
       
  2729     
       
  2730     QContactPhoneNumber number1, number2, number3;
       
  2731     
       
  2732     number1.setNumber("11111111");
       
  2733     number1.setContexts(QContactPhoneNumber::ContextHome);
       
  2734 
       
  2735     number2.setNumber("22222222");
       
  2736     number2.setContexts(QContactPhoneNumber::ContextWork);
       
  2737 
       
  2738     number3.setNumber("33333333");
       
  2739     if (!contextOther.isEmpty())
       
  2740         number3.setContexts(contextOther);
       
  2741 
       
  2742     a.saveDetail(&number1);
       
  2743     a.saveDetail(&number2);
       
  2744     a.saveDetail(&number3);
       
  2745 
       
  2746     QVERIFY(cm->saveContact(&a));
       
  2747     a = cm->contact(a.id().localId());
       
  2748     
       
  2749     QList<QContactDetail> details = a.details(QContactPhoneNumber::DefinitionName);
       
  2750     QVERIFY(details.count() == 3);
       
  2751     QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
       
  2752     QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextWork);
       
  2753     QVERIFY(details.at(2).value(QContactPhoneNumber::FieldContext) == contextOther);
       
  2754     
       
  2755     QVERIFY(a.removeDetail(&number2));
       
  2756     QVERIFY(cm->saveContact(&a));
       
  2757     a = cm->contact(a.id().localId());
       
  2758     details = a.details(QContactPhoneNumber::DefinitionName);
       
  2759     QVERIFY(details.count() == 2);
       
  2760     QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
       
  2761     QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == contextOther);
       
  2762 
       
  2763     a.saveDetail(&number2);
       
  2764     QVERIFY(cm->saveContact(&a));
       
  2765     a = cm->contact(a.id().localId());
       
  2766     
       
  2767     details = a.details(QContactPhoneNumber::DefinitionName);
       
  2768     QVERIFY(details.count() == 3);
       
  2769     QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
       
  2770     QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == contextOther);
       
  2771     QVERIFY(details.at(2).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextWork);
       
  2772 
       
  2773     //addresses
       
  2774     
       
  2775     d = cm->detailDefinition(QContactAddress::DefinitionName, QContactType::TypeContact);
       
  2776     supportedContexts = d.fields().value(QContactDetail::FieldContext);
       
  2777     contextOther = QString(QLatin1String(QContactDetail::ContextOther));
       
  2778     if (!supportedContexts.allowableValues().contains(contextOther)) {
       
  2779         contextOther = QString();
       
  2780     }     
       
  2781     
       
  2782     QContactAddress address1, address2, address3;
       
  2783     
       
  2784     address1.setStreet("Brandl St");
       
  2785     address1.setRegion("Brisbane");
       
  2786     address3 = address2 = address1;
       
  2787 
       
  2788     address1.setContexts(QContactAddress::ContextHome);
       
  2789     address2.setContexts(QContactAddress::ContextWork);
       
  2790     if (!contextOther.isEmpty())
       
  2791         address3.setContexts(contextOther);
       
  2792 
       
  2793     a.saveDetail(&address1);
       
  2794     a.saveDetail(&address2);
       
  2795     a.saveDetail(&address3);
       
  2796 
       
  2797     QVERIFY(cm->saveContact(&a));
       
  2798     a = cm->contact(a.id().localId());
       
  2799     
       
  2800     details = a.details(QContactAddress::DefinitionName);
       
  2801     QVERIFY(details.count() == 3);
       
  2802     
       
  2803     QVERIFY(details.at(0).value(QContactAddress::FieldContext) == QContactAddress::ContextHome);
       
  2804     QVERIFY(details.at(1).value(QContactAddress::FieldContext) == QContactAddress::ContextWork);
       
  2805     QVERIFY(details.at(2).value(QContactAddress::FieldContext) == contextOther);
       
  2806 
       
  2807     QVERIFY(a.removeDetail(&address2));
       
  2808     QVERIFY(cm->saveContact(&a));
       
  2809     a = cm->contact(a.id().localId());
       
  2810     details = a.details(QContactAddress::DefinitionName);
       
  2811     QVERIFY(details.count() == 2);
       
  2812     QVERIFY(details.at(0).value(QContactAddress::FieldContext) == QContactAddress::ContextHome);
       
  2813     QVERIFY(details.at(1).value(QContactAddress::FieldContext) == contextOther);
       
  2814 
       
  2815     a.saveDetail(&address2);
       
  2816     QVERIFY(cm->saveContact(&a));
       
  2817     a = cm->contact(a.id().localId());
       
  2818     
       
  2819     details = a.details(QContactAddress::DefinitionName);
       
  2820     QVERIFY(details.count() == 3);
       
  2821     QVERIFY(details.at(0).value(QContactAddress::FieldContext) == QContactAddress::ContextHome);
       
  2822     QVERIFY(details.at(1).value(QContactAddress::FieldContext) == contextOther);
       
  2823     QVERIFY(details.at(2).value(QContactAddress::FieldContext) == QContactAddress::ContextWork);
       
  2824 
       
  2825 
       
  2826     //emails
       
  2827     d = cm->detailDefinition(QContactEmailAddress::DefinitionName, QContactType::TypeContact);
       
  2828     supportedContexts = d.fields().value(QContactDetail::FieldContext);
       
  2829     contextOther = QString(QLatin1String(QContactDetail::ContextOther));
       
  2830     if (!supportedContexts.allowableValues().contains(contextOther)) {
       
  2831         contextOther = QString();
       
  2832     }      
       
  2833     
       
  2834     QContactEmailAddress email1, email2, email3;
       
  2835 
       
  2836     email1.setEmailAddress("aaron@example.com");
       
  2837     email3 = email2 = email1;
       
  2838     email1.setContexts(QContactEmailAddress::ContextHome);
       
  2839     email2.setContexts(QContactEmailAddress::ContextWork);
       
  2840     if (!contextOther.isEmpty())
       
  2841         email3.setContexts(contextOther);
       
  2842 
       
  2843     a.saveDetail(&email1);
       
  2844     a.saveDetail(&email2);
       
  2845     a.saveDetail(&email3);
       
  2846 
       
  2847     QVERIFY(cm->saveContact(&a));
       
  2848     a = cm->contact(a.id().localId());
       
  2849     
       
  2850     details = a.details(QContactEmailAddress::DefinitionName);
       
  2851     QVERIFY(details.count() == 3);
       
  2852     
       
  2853     QVERIFY(details.at(0).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextHome);
       
  2854     QVERIFY(details.at(1).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextWork);
       
  2855     QVERIFY(details.at(2).value(QContactEmailAddress::FieldContext) == contextOther);
       
  2856 
       
  2857     QVERIFY(a.removeDetail(&email2));
       
  2858     QVERIFY(cm->saveContact(&a));
       
  2859     a = cm->contact(a.id().localId());
       
  2860     details = a.details(QContactEmailAddress::DefinitionName);
       
  2861     QVERIFY(details.count() == 2);
       
  2862     QVERIFY(details.at(0).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextHome);
       
  2863     QVERIFY(details.at(1).value(QContactEmailAddress::FieldContext) == contextOther);
       
  2864 
       
  2865     a.saveDetail(&email2);
       
  2866     QVERIFY(cm->saveContact(&a));
       
  2867     a = cm->contact(a.id().localId());
       
  2868     
       
  2869     details = a.details(QContactEmailAddress::DefinitionName);
       
  2870     QVERIFY(details.count() == 3);
       
  2871     QVERIFY(details.at(0).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextHome);
       
  2872     QVERIFY(details.at(1).value(QContactEmailAddress::FieldContext) == contextOther);
       
  2873     QVERIFY(details.at(2).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextWork);
       
  2874 
       
  2875     QVERIFY(cm->removeContact(a.id().localId()));
       
  2876     QVERIFY(cm->error() == QContactManager::NoError);
       
  2877 }
       
  2878 
       
  2879 void tst_QContactManager::relationships()
       
  2880 {
       
  2881     QFETCH(QString, uri);
       
  2882     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2883 
       
  2884     // save some contacts
       
  2885     QContact source;
       
  2886     QContact dest1, dest2, dest3, dest4;
       
  2887     QContactPhoneNumber n1, n2, n3, n4;
       
  2888     n1.setNumber("1");
       
  2889     n2.setNumber("2");
       
  2890     n3.setNumber("3");
       
  2891     n4.setNumber("4");
       
  2892 
       
  2893     dest1.saveDetail(&n1);
       
  2894     dest2.saveDetail(&n2);
       
  2895     dest3.saveDetail(&n3);
       
  2896     dest4.saveDetail(&n3);
       
  2897 
       
  2898     cm->saveContact(&source);
       
  2899     cm->saveContact(&dest1);
       
  2900     cm->saveContact(&dest2);
       
  2901     cm->saveContact(&dest3);
       
  2902     cm->saveContact(&dest4);
       
  2903 
       
  2904     // check if manager supports relationships
       
  2905     if (!cm->hasFeature(QContactManager::Relationships)) {
       
  2906         // ensure that the operations all fail as required.
       
  2907         QContactRelationship r1, r2, r3;
       
  2908         r1.setFirst(source.id());
       
  2909         r1.setSecond(dest1.id());
       
  2910         r1.setRelationshipType(QContactRelationship::HasManager);
       
  2911         r2.setFirst(source.id());
       
  2912         r2.setSecond(dest2.id());
       
  2913         r2.setRelationshipType(QContactRelationship::HasManager);
       
  2914         r3.setFirst(source.id());
       
  2915         r3.setSecond(dest3.id());
       
  2916         r3.setRelationshipType(QContactRelationship::HasManager);
       
  2917 
       
  2918         QList<QContactRelationship> batchList;
       
  2919         batchList << r2 << r3;
       
  2920 
       
  2921         // test save and remove
       
  2922         QVERIFY(!cm->saveRelationship(&r1));
       
  2923         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2924         QVERIFY(!cm->removeRelationship(r1));
       
  2925         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2926         cm->saveRelationships(&batchList, NULL);
       
  2927         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2928 
       
  2929         // test retrieval
       
  2930         QList<QContactRelationship> retrieveList;
       
  2931         retrieveList = cm->relationships(source.id(), QContactRelationship::First);
       
  2932         QVERIFY(retrieveList.isEmpty());
       
  2933         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2934         retrieveList = cm->relationships(source.id(), QContactRelationship::Second);
       
  2935         QVERIFY(retrieveList.isEmpty());
       
  2936         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2937         retrieveList = cm->relationships(source.id(), QContactRelationship::Either); // Either
       
  2938         QVERIFY(retrieveList.isEmpty());
       
  2939         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2940 
       
  2941 
       
  2942         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id(), QContactRelationship::First);
       
  2943         QVERIFY(retrieveList.isEmpty());
       
  2944         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2945         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id(), QContactRelationship::Second);
       
  2946         QVERIFY(retrieveList.isEmpty());
       
  2947         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2948         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id(), QContactRelationship::Either);
       
  2949         QVERIFY(retrieveList.isEmpty());
       
  2950         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2951         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id());
       
  2952         QVERIFY(retrieveList.isEmpty());
       
  2953         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2954         retrieveList = cm->relationships(QContactRelationship::HasManager);
       
  2955         QVERIFY(retrieveList.isEmpty());
       
  2956         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2957         return;
       
  2958     }
       
  2959     
       
  2960     // Get supported relationship types
       
  2961     QStringList availableRelationshipTypes;
       
  2962     if (cm->isRelationshipTypeSupported(QContactRelationship::HasMember))
       
  2963         availableRelationshipTypes << QContactRelationship::HasMember;    
       
  2964     if (cm->isRelationshipTypeSupported(QContactRelationship::HasAssistant))
       
  2965         availableRelationshipTypes << QContactRelationship::HasAssistant;
       
  2966     if (cm->isRelationshipTypeSupported(QContactRelationship::HasManager))
       
  2967         availableRelationshipTypes << QContactRelationship::HasManager;
       
  2968     if (cm->isRelationshipTypeSupported(QContactRelationship::HasSpouse))
       
  2969         availableRelationshipTypes << QContactRelationship::HasSpouse;
       
  2970     if (cm->isRelationshipTypeSupported(QContactRelationship::IsSameAs))
       
  2971         availableRelationshipTypes << QContactRelationship::IsSameAs;
       
  2972 
       
  2973     
       
  2974     // Check arbitary relationship support
       
  2975     if (cm->hasFeature(QContactManager::ArbitraryRelationshipTypes)) {
       
  2976         // add some arbitary type for testing
       
  2977         if (availableRelationshipTypes.count())
       
  2978             availableRelationshipTypes.insert(0, "test-arbitrary-relationship-type");
       
  2979         else {
       
  2980             availableRelationshipTypes.append("test-arbitrary-relationship-type");
       
  2981             availableRelationshipTypes.append(QContactRelationship::HasMember);
       
  2982             availableRelationshipTypes.append(QContactRelationship::HasAssistant);
       
  2983         }
       
  2984     }
       
  2985     
       
  2986     // Verify that we have relationship types. If there are none then the manager
       
  2987     // is saying it supports relationships but does not actually implement any 
       
  2988     // relationship type.
       
  2989     QVERIFY(!availableRelationshipTypes.isEmpty());
       
  2990     
       
  2991     // Some backends (eg. symbian) require that when type is "HasMember" 
       
  2992     // then "first" contact must be a group.
       
  2993     if (availableRelationshipTypes.at(0) == QContactRelationship::HasMember) {
       
  2994         cm->removeContact(source.localId());
       
  2995         source.setId(QContactId());
       
  2996         source.setType(QContactType::TypeGroup);
       
  2997         cm->saveContact(&source);
       
  2998     }
       
  2999 
       
  3000     // Create some common contact id's for testing
       
  3001     QContactId dest1Uri = dest1.id();
       
  3002     QContactId dest1EmptyUri;
       
  3003     dest1EmptyUri.setManagerUri(QString());
       
  3004     dest1EmptyUri.setLocalId(dest1.id().localId());
       
  3005     QContactId dest2Uri = dest2.id();
       
  3006     QContactId dest3Uri = dest3.id();
       
  3007     QContactId dest3EmptyUri;
       
  3008     dest3EmptyUri.setManagerUri(QString());
       
  3009     dest3EmptyUri.setLocalId(dest3.id().localId());
       
  3010 
       
  3011     // build our relationship - source is the manager all of the dest contacts.
       
  3012     QContactRelationship customRelationshipOne;
       
  3013     customRelationshipOne.setFirst(source.id());
       
  3014     customRelationshipOne.setSecond(dest1EmptyUri);
       
  3015     customRelationshipOne.setRelationshipType(availableRelationshipTypes.at(0));
       
  3016     QCOMPARE(customRelationshipOne.first(), source.id());
       
  3017     QCOMPARE(customRelationshipOne.second(), dest1EmptyUri);
       
  3018     QVERIFY(customRelationshipOne.relationshipType() == availableRelationshipTypes.at(0));
       
  3019 
       
  3020     // save the relationship
       
  3021     int managerRelationshipsCount = cm->relationships(availableRelationshipTypes.at(0)).count();
       
  3022     QVERIFY(cm->saveRelationship(&customRelationshipOne));
       
  3023     // test that the empty manager URI has been updated.
       
  3024     QCOMPARE(customRelationshipOne.second(), dest1Uri); // updated with correct manager URI
       
  3025 
       
  3026     // test our accessors.
       
  3027     QCOMPARE(cm->relationships(availableRelationshipTypes.at(0)).count(), (managerRelationshipsCount + 1));
       
  3028     QVERIFY(cm->relationships(availableRelationshipTypes.at(0), source.id()).count() == 1);
       
  3029 
       
  3030     // remove the dest1 contact, relationship should be removed.
       
  3031     cm->removeContact(dest1.localId());
       
  3032     QCOMPARE(cm->relationships(availableRelationshipTypes.at(0), dest1Uri, QContactRelationship::Second).count(), 0);
       
  3033 
       
  3034     // modify and save the relationship
       
  3035     customRelationshipOne.setSecond(dest2Uri);
       
  3036     QVERIFY(cm->saveRelationship(&customRelationshipOne));
       
  3037 
       
  3038     // attempt to save the relationship again.  XXX TODO: what should the result be?  currently succeeds (overwrites)
       
  3039     int relationshipsCount = cm->relationships().count();
       
  3040     QVERIFY(cm->saveRelationship(&customRelationshipOne));    // succeeds, but just overwrites
       
  3041     QCOMPARE(relationshipsCount, cm->relationships().count()); // shouldn't change; save should have overwritten.
       
  3042 
       
  3043     // removing the source contact should result in removal of the relationship.
       
  3044     QVERIFY(cm->removeContact(source.id().localId()));
       
  3045     QCOMPARE(cm->relationships().count(), relationshipsCount - 1); // the relationship should have been removed.
       
  3046 
       
  3047     // now ensure that qcontact relationship caching works as required - perhaps this should be in tst_QContact?
       
  3048     source.setId(QContactId());         // reset id so we can resave
       
  3049     QVERIFY(cm->saveContact(&source));  // save source again.
       
  3050     customRelationshipOne.setFirst(source.id());
       
  3051     customRelationshipOne.setSecond(dest2.id());
       
  3052     QVERIFY(cm->saveRelationship(&customRelationshipOne));
       
  3053 
       
  3054     // Add a second relationship
       
  3055     QContactRelationship customRelationshipTwo;
       
  3056     customRelationshipTwo.setFirst(source.id());
       
  3057     if (availableRelationshipTypes.count() > 1)
       
  3058         customRelationshipTwo.setRelationshipType(availableRelationshipTypes.at(1));
       
  3059     else
       
  3060         customRelationshipTwo.setRelationshipType(availableRelationshipTypes.at(0));
       
  3061     customRelationshipTwo.setSecond(dest3.id());
       
  3062     QVERIFY(cm->saveRelationship(&customRelationshipTwo));
       
  3063 
       
  3064     // currently, the contacts are "stale" - no cached relationships
       
  3065     QVERIFY(dest3.relatedContacts().isEmpty());
       
  3066     QVERIFY(dest3.relationships().isEmpty());
       
  3067     QVERIFY(dest2.relatedContacts().isEmpty());
       
  3068     QVERIFY(dest2.relationships().isEmpty());
       
  3069 
       
  3070     // now refresh the contacts
       
  3071     dest3 = cm->contact(dest3.localId());
       
  3072     dest2 = cm->contact(dest2.localId());
       
  3073     source = cm->contact(source.localId());
       
  3074 
       
  3075     // and test again.
       
  3076     QVERIFY(source.relatedContacts(QString(), QContactRelationship::First).isEmpty()); // source is always the first, so this should be empty.
       
  3077     QVERIFY(source.relatedContacts(QString(), QContactRelationship::Second).contains(dest2.id()));
       
  3078     QVERIFY(source.relatedContacts(QString(), QContactRelationship::Either).contains(dest2.id()));
       
  3079     QVERIFY(source.relatedContacts(QString(), QContactRelationship::Second).contains(dest3.id()));
       
  3080     QVERIFY(source.relatedContacts(QString(), QContactRelationship::Either).contains(dest3.id()));
       
  3081     QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).contains(dest2.id()));
       
  3082     QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::First).isEmpty());
       
  3083 
       
  3084     QVERIFY(dest2.relatedContacts().contains(source.id()));
       
  3085     QVERIFY(dest2.relationships().contains(customRelationshipOne));
       
  3086     QVERIFY(!dest2.relationships().contains(customRelationshipTwo));
       
  3087     QVERIFY(dest2.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipOne));
       
  3088     QVERIFY(!dest2.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipTwo));
       
  3089     QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0)).contains(source.id()));
       
  3090     QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::First).contains(source.id()));
       
  3091     QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).isEmpty());
       
  3092     QVERIFY(!dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).contains(source.id()));
       
  3093     
       
  3094     QVERIFY(dest3.relatedContacts().contains(source.id()));
       
  3095     QVERIFY(!dest3.relationships().contains(customRelationshipOne));
       
  3096     QVERIFY(dest3.relationships().contains(customRelationshipTwo));
       
  3097     QVERIFY(!dest3.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipOne));
       
  3098 
       
  3099     // Test iteration
       
  3100     QList<QContactRelationship> relats = source.relationships();
       
  3101     QList<QContactRelationship>::iterator it = relats.begin();
       
  3102 
       
  3103     while (it != relats.end()) {
       
  3104         QContactId firstId = it->first();
       
  3105         QVERIFY(firstId == source.id());
       
  3106         QVERIFY(it->second() == dest2.id() || it->second() == dest3.id());
       
  3107         it++;
       
  3108     }
       
  3109     
       
  3110     if (availableRelationshipTypes.count() > 1) {
       
  3111         QVERIFY(source.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::Second).contains(dest3.id()));
       
  3112         QVERIFY(source.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::First).isEmpty());
       
  3113         
       
  3114         QVERIFY(dest2.relationships(availableRelationshipTypes.at(1)).isEmpty());
       
  3115         
       
  3116         QVERIFY(!dest3.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipTwo));
       
  3117         QVERIFY(dest3.relationships(availableRelationshipTypes.at(1)).contains(customRelationshipTwo));
       
  3118         QVERIFY(!dest3.relationships(availableRelationshipTypes.at(1)).contains(customRelationshipOne));
       
  3119         QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1)).contains(source.id()));
       
  3120         QVERIFY(!dest3.relatedContacts(availableRelationshipTypes.at(0)).contains(source.id()));
       
  3121         QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1)).contains(source.id())); // role = either
       
  3122         QVERIFY(!dest3.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::Second).contains(source.id()));
       
  3123         QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1), QContactRelationship::First).contains(source.id()));
       
  3124         QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(1)).isEmpty());
       
  3125     }
       
  3126     else {
       
  3127         QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationship::Second).contains(dest3.id()));
       
  3128     }
       
  3129     
       
  3130     // Cleanup a bit
       
  3131     QMap<int, QContactManager::Error> errorMap;
       
  3132     QList<QContactRelationship> moreRels;
       
  3133 
       
  3134     moreRels << customRelationshipOne << customRelationshipTwo;
       
  3135     errorMap.insert(5, QContactManager::BadArgumentError);
       
  3136     QVERIFY(cm->removeRelationships(moreRels, &errorMap));
       
  3137     QVERIFY(errorMap.count() == 0);
       
  3138 
       
  3139     // test batch API and ordering in contacts
       
  3140     QList<QContactRelationship> currentRelationships = cm->relationships(source.id(), QContactRelationship::First);
       
  3141     QList<QContactRelationship> batchList;
       
  3142     QContactRelationship br1, br2, br3;
       
  3143     br1.setFirst(source.id());
       
  3144     br1.setSecond(dest2.id());
       
  3145     br1.setRelationshipType(availableRelationshipTypes.at(0));    
       
  3146     br2.setFirst(source.id());
       
  3147     br2.setSecond(dest3.id());
       
  3148     br2.setRelationshipType(availableRelationshipTypes.at(0));
       
  3149     if (availableRelationshipTypes.count() > 1)
       
  3150     {
       
  3151         br3.setFirst(source.id());
       
  3152         br3.setSecond(dest3.id());
       
  3153         br3.setRelationshipType(availableRelationshipTypes.at(1));
       
  3154     }
       
  3155     else
       
  3156     {
       
  3157         br3.setFirst(source.id());
       
  3158         br3.setSecond(dest4.id());
       
  3159         br3.setRelationshipType(availableRelationshipTypes.at(0));
       
  3160     }
       
  3161     batchList << br1 << br2 << br3;
       
  3162 
       
  3163     // ensure that the batch save works properly
       
  3164     cm->saveRelationships(&batchList, NULL);
       
  3165     QCOMPARE(cm->error(), QContactManager::NoError);
       
  3166     QList<QContactRelationship> batchRetrieve = cm->relationships(source.id(), QContactRelationship::First);
       
  3167     QVERIFY(batchRetrieve.contains(br1));
       
  3168     QVERIFY(batchRetrieve.contains(br2));
       
  3169     QVERIFY(batchRetrieve.contains(br3));
       
  3170     
       
  3171     // remove a single relationship
       
  3172     QVERIFY(cm->removeRelationship(br3));
       
  3173     batchRetrieve = cm->relationships(source.id(), QContactRelationship::First);
       
  3174     QVERIFY(batchRetrieve.contains(br1));
       
  3175     QVERIFY(batchRetrieve.contains(br2));
       
  3176     QVERIFY(!batchRetrieve.contains(br3)); // has already been removed.
       
  3177 
       
  3178     // now ensure that the batch remove works and we get returned to the original state.
       
  3179     batchList.removeOne(br3);
       
  3180     cm->removeRelationships(batchList, NULL);
       
  3181     QVERIFY(cm->error() == QContactManager::NoError);
       
  3182     QCOMPARE(cm->relationships(source.id(), QContactRelationship::First), currentRelationships);
       
  3183 
       
  3184     // attempt to save relationships between an existing source but non-existent destination
       
  3185     QContactId nonexistentDest;
       
  3186     quint32 idSeed = 0x5544;
       
  3187     QContactLocalId nonexistentLocalId = QContactLocalId(idSeed);
       
  3188     nonexistentDest.setManagerUri(cm->managerUri());
       
  3189     while (true) {
       
  3190         nonexistentLocalId = cm->contact(nonexistentLocalId).localId();
       
  3191         if (nonexistentLocalId == QContactLocalId(0)) {
       
  3192             // found a "spare" local id (no contact with that id)
       
  3193             break;
       
  3194         }
       
  3195 
       
  3196         // keep looking...
       
  3197         idSeed += 1;
       
  3198         nonexistentLocalId = QContactLocalId(idSeed);
       
  3199         QVERIFY(nonexistentLocalId != QContactLocalId(0)); // integer overflow check.
       
  3200     }
       
  3201     nonexistentDest.setLocalId(nonexistentLocalId);
       
  3202     QContactRelationship maliciousRel;
       
  3203     maliciousRel.setFirst(source.id());
       
  3204     maliciousRel.setSecond(nonexistentDest);
       
  3205     maliciousRel.setRelationshipType("nokia-test-invalid-relationship-type");
       
  3206     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  3207 
       
  3208     // attempt to save a circular relationship - should fail!
       
  3209     maliciousRel.setFirst(source.id());
       
  3210     maliciousRel.setSecond(source.id());
       
  3211     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  3212     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  3213 
       
  3214     // more negative testing, but force manager to recognise the empty URI
       
  3215     QContactId circularId = source.id();
       
  3216     circularId.setManagerUri(QString());
       
  3217     maliciousRel.setFirst(circularId);
       
  3218     maliciousRel.setSecond(circularId);
       
  3219     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  3220     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  3221     maliciousRel.setFirst(source.id());
       
  3222     maliciousRel.setSecond(circularId);
       
  3223     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  3224     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  3225     maliciousRel.setFirst(circularId);
       
  3226     maliciousRel.setSecond(source.id());
       
  3227     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  3228     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  3229 
       
  3230     // attempt to save a relationship where the source contact comes from another manager
       
  3231     circularId.setManagerUri("test-nokia-invalid-manager-uri");
       
  3232     maliciousRel.setFirst(circularId);   // an invalid source contact
       
  3233     maliciousRel.setSecond(dest2.id());       // a valid destination contact
       
  3234     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  3235     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  3236 
       
  3237     // remove the nonexistent relationship
       
  3238     relationshipsCount = cm->relationships().count();
       
  3239     QVERIFY(!cm->removeRelationship(maliciousRel));         // does not exist; fail remove.
       
  3240     QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
       
  3241     QCOMPARE(cm->relationships().count(), relationshipsCount); // should be unchanged.
       
  3242 
       
  3243     // now we want to ensure that a relationship is removed if one of the contacts is removed.
       
  3244     customRelationshipOne.setFirst(source.id());
       
  3245     customRelationshipOne.setSecond(dest2.id());
       
  3246     customRelationshipOne.setRelationshipType(availableRelationshipTypes.at(0));
       
  3247 
       
  3248     // Test batch save with an error map
       
  3249     moreRels.clear();
       
  3250     moreRels << customRelationshipOne;
       
  3251     errorMap.insert(0, QContactManager::BadArgumentError);
       
  3252     QVERIFY(cm->saveRelationships(&moreRels, &errorMap));
       
  3253     QVERIFY(cm->error() == QContactManager::NoError);
       
  3254     QVERIFY(errorMap.count() == 0); // should be reset
       
  3255     source = cm->contact(source.localId());
       
  3256     dest2 = cm->contact(dest2.localId());
       
  3257     QVERIFY(cm->removeContact(dest2.localId())); // remove dest2, the relationship should be removed
       
  3258     QVERIFY(cm->relationships(availableRelationshipTypes.at(0), dest2.id(), QContactRelationship::Second).isEmpty());
       
  3259     source = cm->contact(source.localId());
       
  3260     QVERIFY(!source.relatedContacts().contains(dest2.id())); // and it shouldn't appear in cache.
       
  3261 
       
  3262     // now clean up and remove our dests.
       
  3263     QVERIFY(cm->removeContact(source.localId()));
       
  3264     QVERIFY(cm->removeContact(dest3.localId()));
       
  3265 
       
  3266     // attempt to save relationships with nonexistent contacts
       
  3267     QVERIFY(!cm->saveRelationship(&br1));
       
  3268     QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  3269     cm->saveRelationships(&batchList, NULL);
       
  3270     QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  3271     QVERIFY(!cm->removeRelationship(br1));
       
  3272     QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
       
  3273     cm->removeRelationships(batchList, NULL);
       
  3274     QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
       
  3275 }
       
  3276 
       
  3277 void tst_QContactManager::contactType()
       
  3278 {
       
  3279     QFETCH(QString, uri);
       
  3280     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  3281 
       
  3282     if (!cm->hasFeature(QContactManager::Groups))
       
  3283         QSKIP("Skipping: This manager does not support group contacts!", SkipSingle);
       
  3284 
       
  3285     QContact g1, g2, c;
       
  3286     g1.setType(QContactType::TypeGroup);
       
  3287     g2.setType(QContactType::TypeGroup);
       
  3288 
       
  3289     QContactPhoneNumber g1p, g2p, cp;
       
  3290     g1p.setNumber("22222");
       
  3291     g2p.setNumber("11111");
       
  3292     cp.setNumber("33333");
       
  3293 
       
  3294     g1.saveDetail(&g1p);
       
  3295     g2.saveDetail(&g2p);
       
  3296     c.saveDetail(&cp);
       
  3297 
       
  3298     QVERIFY(cm->saveContact(&g1));
       
  3299     QVERIFY(cm->saveContact(&g2));
       
  3300     QVERIFY(cm->saveContact(&c));
       
  3301 
       
  3302     // test that the accessing by type works properly
       
  3303     QContactDetailFilter groupFilter;
       
  3304     groupFilter.setDetailDefinitionName(QContactType::DefinitionName, QContactType::FieldType);
       
  3305     groupFilter.setValue(QString(QLatin1String(QContactType::TypeGroup)));
       
  3306     QVERIFY(cm->contactIds(groupFilter).contains(g1.localId()));
       
  3307     QVERIFY(cm->contactIds(groupFilter).contains(g2.localId()));
       
  3308     QVERIFY(!cm->contactIds(groupFilter).contains(c.localId()));
       
  3309 
       
  3310     QList<QContactSortOrder> sortOrders;
       
  3311     QContactSortOrder byPhoneNumber;
       
  3312     byPhoneNumber.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
       
  3313     sortOrders.append(byPhoneNumber);
       
  3314 
       
  3315     // and ensure that sorting works properly with typed contacts also
       
  3316     QList<QContactLocalId> sortedIds = cm->contactIds(groupFilter, sortOrders);
       
  3317     QVERIFY(sortedIds.indexOf(g2.localId()) < sortedIds.indexOf(g1.localId()));
       
  3318 
       
  3319     cm->removeContact(g1.localId());
       
  3320     cm->removeContact(g2.localId());
       
  3321     cm->removeContact(c.localId());
       
  3322 }
       
  3323 
       
  3324 QTEST_MAIN(tst_QContactManager)
       
  3325 #include "tst_qcontactmanager.moc"