qtmobility/tests/auto/qcontactmanager/tst_qcontactmanager.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <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 
       
   112 class tst_QContactManager : public QObject
       
   113 {
       
   114 Q_OBJECT
       
   115 
       
   116 public:
       
   117     tst_QContactManager();
       
   118     virtual ~tst_QContactManager();
       
   119 
       
   120 private:
       
   121     void dumpContactDifferences(const QContact& a, const QContact& b);
       
   122     void dumpContact(const QContact &c);
       
   123     void dumpContacts(QContactManager *cm);
       
   124     bool isSuperset(const QContact& ca, const QContact& cb);
       
   125     QList<QContactDetail> removeAllDefaultDetails(const QList<QContactDetail>& details);
       
   126     void addManagers(); // add standard managers to the data
       
   127     QContact createContact(QContactDetailDefinition nameDef, QString firstName, QString lastName, QString phoneNumber);
       
   128     void setContactName(QContactDetailDefinition nameDef, QContactName& contactName, const QString &name) const;
       
   129 
       
   130     QContactManagerDataHolder managerDataHolder;
       
   131 
       
   132 public slots:
       
   133     void init();
       
   134     void cleanup();
       
   135 private slots:
       
   136 
       
   137     void doDump();
       
   138     void doDump_data() {addManagers();}
       
   139 
       
   140     void doDumpSchema();
       
   141     void doDumpSchema_data() {addManagers();}
       
   142 
       
   143     /* Special test with special data */
       
   144     void uriParsing();
       
   145     void nameSynthesis();
       
   146 
       
   147     /* Tests that are run on all managers */
       
   148     void metadata();
       
   149     void nullIdOperations();
       
   150     void add();
       
   151     void update();
       
   152     void remove();
       
   153     void batch();
       
   154     void signalEmission();
       
   155     void detailDefinitions();
       
   156     void displayName();
       
   157     void actionPreferences();
       
   158     void selfContactId();
       
   159     void detailOrders();
       
   160     void relationships();
       
   161     void contactType();
       
   162 
       
   163     /* Tests that take no data */
       
   164     void contactValidation();
       
   165     void errorStayingPut();
       
   166     void ctors();
       
   167     void invalidManager();
       
   168     void memoryManager();
       
   169     void changeSet();
       
   170 
       
   171     /* data providers (mostly all engines) */
       
   172     void uriParsing_data(); // Special data
       
   173     void nameSynthesis_data(); // Special data
       
   174     void metadata_data() {addManagers();}
       
   175     void nullIdOperations_data() {addManagers();}
       
   176     void add_data() {addManagers();}
       
   177     void update_data() {addManagers();}
       
   178     void remove_data() {addManagers();}
       
   179     void batch_data() {addManagers();}
       
   180     void signalEmission_data() {addManagers();}
       
   181     void detailDefinitions_data() {addManagers();}
       
   182     void displayName_data() {addManagers();}
       
   183     void actionPreferences_data() {addManagers();}
       
   184     void selfContactId_data() {addManagers();}
       
   185     void detailOrders_data() {addManagers();}
       
   186     void relationships_data() {addManagers();}
       
   187     void contactType_data() {addManagers();}
       
   188 };
       
   189 
       
   190 tst_QContactManager::tst_QContactManager()
       
   191 {
       
   192 }
       
   193 
       
   194 tst_QContactManager::~tst_QContactManager()
       
   195 {
       
   196 }
       
   197 
       
   198 void tst_QContactManager::init()
       
   199 {
       
   200     /* Make sure these other test plugins are NOT loaded by default */
       
   201     // These are now removed from the list of managers in addManagers()
       
   202     //QVERIFY(!QContactManager::availableManagers().contains("testdummy"));
       
   203     //QVERIFY(!QContactManager::availableManagers().contains("teststaticdummy"));
       
   204     //QVERIFY(!QContactManager::availableManagers().contains("maliciousplugin"));
       
   205 }
       
   206 
       
   207 void tst_QContactManager::cleanup()
       
   208 {
       
   209 }
       
   210 
       
   211 void tst_QContactManager::dumpContactDifferences(const QContact& ca, const QContact& cb)
       
   212 {
       
   213     // Try to narrow down the differences
       
   214     QContact a(ca);
       
   215     QContact b(cb);
       
   216 
       
   217     QContactName n1 = a.detail(QContactName::DefinitionName);
       
   218     QContactName n2 = b.detail(QContactName::DefinitionName);
       
   219 
       
   220     // Check the name components in more detail
       
   221     QCOMPARE(n1.firstName(), n2.firstName());
       
   222     QCOMPARE(n1.middleName(), n2.middleName());
       
   223     QCOMPARE(n1.lastName(), n2.lastName());
       
   224     QCOMPARE(n1.prefix(), n2.prefix());
       
   225     QCOMPARE(n1.suffix(), n2.suffix());
       
   226     QCOMPARE(n1.customLabel(), n2.customLabel());
       
   227 
       
   228     // Check the display label
       
   229     QCOMPARE(a.displayLabel(), b.displayLabel());
       
   230 
       
   231     // Now look at the rest
       
   232     QList<QContactDetail> aDetails = a.details();
       
   233     QList<QContactDetail> bDetails = b.details();
       
   234 
       
   235     // They can be in any order, so loop
       
   236     // First remove any matches
       
   237     foreach(QContactDetail d, aDetails) {
       
   238         foreach(QContactDetail d2, bDetails) {
       
   239             if(d == d2) {
       
   240                 a.removeDetail(&d);
       
   241                 b.removeDetail(&d2);
       
   242                 break;
       
   243             }
       
   244         }
       
   245     }
       
   246 
       
   247     // Now dump the extra details that were unmatched in A (note that DisplayLabel and Type are always present).
       
   248     aDetails = a.details();
       
   249     bDetails = b.details();
       
   250     foreach(QContactDetail d, aDetails) {
       
   251         if (d.definitionName() != QContactDisplayLabel::DefinitionName && d.definitionName() != QContactType::DefinitionName)
       
   252             qDebug() << "A contact had extra detail:" << d.definitionName() << d.variantValues();
       
   253     }
       
   254     // and same for B
       
   255     foreach(QContactDetail d, bDetails) {
       
   256         if (d.definitionName() != QContactDisplayLabel::DefinitionName && d.definitionName() != QContactType::DefinitionName)
       
   257             qDebug() << "B contact had extra detail:" << d.definitionName() << d.variantValues();
       
   258     }
       
   259 
       
   260     // now test specifically the display label and the type
       
   261     if (a.displayLabel() != b.displayLabel()) {
       
   262         qDebug() << "A contact display label =" << a.displayLabel();
       
   263         qDebug() << "B contact display label =" << b.displayLabel();
       
   264     }
       
   265     if (a.type() != b.type()) {
       
   266         qDebug() << "A contact type =" << a.type();
       
   267         qDebug() << "B contact type =" << b.type();
       
   268     }
       
   269 }
       
   270 
       
   271 bool tst_QContactManager::isSuperset(const QContact& ca, const QContact& cb)
       
   272 {
       
   273     // returns true if contact ca is a superset of contact cb
       
   274     // we use this test instead of equality because dynamic information
       
   275     // such as presence/location, and synthesised information such as
       
   276     // display label and (possibly) type, may differ between a contact
       
   277     // in memory and the contact in the managed store.
       
   278 
       
   279     QContact a(ca);
       
   280     QContact b(cb);
       
   281     QList<QContactDetail> aDetails = a.details();
       
   282     QList<QContactDetail> bDetails = b.details();
       
   283 
       
   284     // They can be in any order, so loop
       
   285     // First remove any matches
       
   286     foreach(QContactDetail d, aDetails) {
       
   287         foreach(QContactDetail d2, bDetails) {
       
   288             if(d == d2) {
       
   289                 a.removeDetail(&d);
       
   290                 b.removeDetail(&d2);
       
   291                 break;
       
   292             }
       
   293         }
       
   294     }
       
   295 
       
   296     // check for contact type updates
       
   297     if (!a.type().isEmpty())
       
   298         if (!b.type().isEmpty())
       
   299             if (a.type() != b.type())
       
   300                 return false; // nonempty type is different.
       
   301 
       
   302     // Now check to see if b has any details remaining; if so, a is not a superset.
       
   303     // Note that the DisplayLabel and Type can never be removed.
       
   304     if (b.details().size() > 2
       
   305             || (b.details().size() == 2 && (b.details().value(0).definitionName() != QContactDisplayLabel::DefinitionName
       
   306                                             || b.details().value(1).definitionName() != QContactType::DefinitionName)))
       
   307         return false;
       
   308     return true;
       
   309 }
       
   310 
       
   311 void tst_QContactManager::dumpContact(const QContact& contact)
       
   312 {
       
   313     QContactManager m;
       
   314     qDebug() << "Contact: " << contact.id().localId() << "(" << m.synthesizedDisplayLabel(contact) << ")";
       
   315     QList<QContactDetail> details = contact.details();
       
   316     foreach(QContactDetail d, details) {
       
   317         qDebug() << "  " << d.definitionName() << ":";
       
   318         qDebug() << "    Vals:" << d.variantValues();
       
   319     }
       
   320 }
       
   321 
       
   322 void tst_QContactManager::dumpContacts(QContactManager *cm)
       
   323 {
       
   324     QList<QContactLocalId> ids = cm->contactIds();
       
   325 
       
   326     qDebug() << "There are" << ids.count() << "contacts in" << cm->managerUri();
       
   327 
       
   328     foreach(QContactLocalId id, ids) {
       
   329         QContact c = cm->contact(id);
       
   330         dumpContact(c);
       
   331     }
       
   332 }
       
   333 
       
   334 void tst_QContactManager::uriParsing_data()
       
   335 {
       
   336     QTest::addColumn<QString>("uri");
       
   337     QTest::addColumn<bool>("good"); // is this a good uri or not
       
   338     QTest::addColumn<QString>("manager");
       
   339     QTest::addColumn<QMap<QString, QString> >("parameters");
       
   340 
       
   341     QMap<QString, QString> inparameters;
       
   342     inparameters.insert("foo", "bar");
       
   343     inparameters.insert("bazflag", QString());
       
   344     inparameters.insert("bar", "glob");
       
   345 
       
   346     QMap<QString, QString> inparameters2;
       
   347     inparameters2.insert("this has spaces", QString());
       
   348     inparameters2.insert("and& an", " &amp;");
       
   349     inparameters2.insert("and an ", "=quals");
       
   350 
       
   351     QTest::newRow("built") << QContactManager::buildUri("manager", inparameters) << true << "manager" << inparameters;
       
   352     QTest::newRow("built with escaped parameters") << QContactManager::buildUri("manager", inparameters2) << true << "manager" << inparameters2;
       
   353     QTest::newRow("no scheme") << "this should not split" << false << QString() << tst_QContactManager_QStringMap();
       
   354     QTest::newRow("wrong scheme") << "invalidscheme:foo bar" << false << QString() << tst_QContactManager_QStringMap();
       
   355     QTest::newRow("right scheme, no colon") << "qtcontacts" << false << QString() << tst_QContactManager_QStringMap();
       
   356     QTest::newRow("no manager, colon, no params") << "qtcontacts::" << false  << "manager" << tst_QContactManager_QStringMap();
       
   357     QTest::newRow("yes manager, no colon, no params") << "qtcontacts:manager" << true << "manager" << tst_QContactManager_QStringMap();
       
   358     QTest::newRow("yes manager, yes colon, no params") << "qtcontacts:manager:" << true << "manager"<< tst_QContactManager_QStringMap();
       
   359     QTest::newRow("yes params") << "qtcontacts:manager:foo=bar&bazflag=&bar=glob" << true << "manager" << inparameters;
       
   360     QTest::newRow("yes params but misformed") << "qtcontacts:manager:foo=bar&=gloo&bar=glob" << false << "manager" << inparameters;
       
   361     QTest::newRow("yes params but misformed 2") << "qtcontacts:manager:=&=gloo&bar=glob" << false << "manager" << inparameters;
       
   362     QTest::newRow("yes params but misformed 3") << "qtcontacts:manager:==" << false << "manager" << inparameters;
       
   363     QTest::newRow("yes params but misformed 4") << "qtcontacts:manager:&&" << false << "manager" << inparameters;
       
   364     QTest::newRow("yes params but misformed 5") << "qtcontacts:manager:&goo=bar" << false << "manager" << inparameters;
       
   365     QTest::newRow("yes params but misformed 6") << "qtcontacts:manager:goo&bar" << false << "manager" << inparameters;
       
   366     QTest::newRow("yes params but misformed 7") << "qtcontacts:manager:goo&bar&gob" << false << "manager" << inparameters;
       
   367     QTest::newRow("yes params but misformed 8") << "qtcontacts:manager:==&&==&goo=bar" << false << "manager" << inparameters;
       
   368     QTest::newRow("yes params but misformed 9") << "qtcontacts:manager:foo=bar=baz" << false << "manager" << inparameters;
       
   369     QTest::newRow("yes params but misformed 10") << "qtcontacts:manager:foo=bar=baz=glob" << false << "manager" << inparameters;
       
   370     QTest::newRow("no manager but yes params") << "qtcontacts::foo=bar&bazflag=&bar=glob" << false << QString() << inparameters;
       
   371     QTest::newRow("no manager or params") << "qtcontacts::" << false << QString() << inparameters;
       
   372     QTest::newRow("no manager or params or colon") << "qtcontacts:" << false << QString() << inparameters;
       
   373 }
       
   374 
       
   375 void tst_QContactManager::addManagers()
       
   376 {
       
   377     QTest::addColumn<QString>("uri");
       
   378 
       
   379     QStringList managers = QContactManager::availableManagers();
       
   380 
       
   381     /* Known one that will not pass */
       
   382     managers.removeAll("invalid");
       
   383     managers.removeAll("testdummy");
       
   384     managers.removeAll("teststaticdummy");
       
   385     managers.removeAll("maliciousplugin");
       
   386 
       
   387     foreach(QString mgr, managers) {
       
   388         QMap<QString, QString> params;
       
   389         QTest::newRow(QString("mgr='%1'").arg(mgr).toLatin1().constData()) << QContactManager::buildUri(mgr, params);
       
   390         if (mgr == "memory") {
       
   391             params.insert("id", "tst_QContactManager");
       
   392             QTest::newRow(QString("mgr='%1', params").arg(mgr).toLatin1().constData()) << QContactManager::buildUri(mgr, params);
       
   393         }
       
   394     }
       
   395 }
       
   396 
       
   397 /*
       
   398  * Helper method for creating a QContact instance with name and phone number
       
   399  * details. Name is generated according to the detail definition assuming that
       
   400  * either first and last name or custom label is supported.
       
   401  */
       
   402 QContact tst_QContactManager::createContact(
       
   403     QContactDetailDefinition nameDef,
       
   404     QString firstName,
       
   405     QString lastName,
       
   406     QString phoneNumber)
       
   407 {
       
   408     QContact contact;
       
   409 
       
   410     if(!firstName.isEmpty() || !lastName.isEmpty()) {
       
   411         QContactName n;
       
   412 
       
   413         if(nameDef.fields().contains(QContactName::FieldFirstName)
       
   414             && nameDef.fields().contains(QContactName::FieldFirstName)) {
       
   415             n.setFirstName(firstName);
       
   416             n.setLastName(lastName);
       
   417         } else if(nameDef.fields().contains(QContactName::FieldCustomLabel)) {
       
   418             n.setCustomLabel(firstName + " " + lastName);
       
   419         } else {
       
   420             // assume that either first and last name or custom label is supported
       
   421             QTest::qWarn("Neither custom label nor first name/last name supported!");
       
   422             return QContact();
       
   423         }
       
   424         contact.saveDetail(&n);
       
   425     }
       
   426 
       
   427     if (!phoneNumber.isEmpty()) {
       
   428         QContactPhoneNumber ph;
       
   429         ph.setNumber(phoneNumber);
       
   430         contact.saveDetail(&ph);
       
   431     }
       
   432 
       
   433     return contact;
       
   434 }
       
   435 
       
   436 void tst_QContactManager::setContactName(QContactDetailDefinition nameDef, QContactName& contactName, const QString &name) const
       
   437 {
       
   438     // check which name fields are supported in the following order:
       
   439     // 1. custom label, 2. first name, 3. last name
       
   440     if(nameDef.fields().contains(QContactName::FieldCustomLabel)) {
       
   441         contactName.setCustomLabel(name);
       
   442     } else if(nameDef.fields().contains(QContactName::FieldFirstName)) {
       
   443         contactName.setFirstName(name);
       
   444     } else if(nameDef.fields().contains(QContactName::FieldLastName)) {
       
   445         contactName.setLastName(name);
       
   446     } else {
       
   447         // Assume that at least one of the above name fields is supported by the backend
       
   448         QVERIFY(false);
       
   449     }
       
   450 }
       
   451 
       
   452 void tst_QContactManager::metadata()
       
   453 {
       
   454     // ensure that the backend is publishing its metadata (name / parameters / uri) correctly
       
   455     QFETCH(QString, uri);
       
   456     QScopedPointer<QContactManager> cm(new QContactManager("memory"));
       
   457     QVERIFY(QContactManager::buildUri(cm->managerName(), cm->managerParameters()) == cm->managerUri());
       
   458 }
       
   459 
       
   460 
       
   461 void tst_QContactManager::nullIdOperations()
       
   462 {
       
   463     QFETCH(QString, uri);
       
   464     QScopedPointer<QContactManager> cm(new QContactManager("memory"));
       
   465     QVERIFY(!cm->removeContact(QContactLocalId()));
       
   466     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
   467 
       
   468 
       
   469     QContact c = cm->contact(QContactLocalId());
       
   470     QVERIFY(c.id() == QContactId());
       
   471     QVERIFY(c.isEmpty());
       
   472     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
   473 }
       
   474 
       
   475 void tst_QContactManager::uriParsing()
       
   476 {
       
   477     QFETCH(QString, uri);
       
   478     QFETCH(bool, good);
       
   479     QFETCH(QString, manager);
       
   480     QFETCH(tst_QContactManager_QStringMap, parameters);
       
   481 
       
   482     QString outmanager;
       
   483     QMap<QString, QString> outparameters;
       
   484 
       
   485     if (good) {
       
   486         /* Good split */
       
   487         /* Test splitting */
       
   488         QVERIFY(QContactManager::parseUri(uri, 0, 0)); // no out parms
       
   489 
       
   490         // 1 out param
       
   491         QVERIFY(QContactManager::parseUri(uri, &outmanager, 0));
       
   492         QCOMPARE(manager, outmanager);
       
   493         QVERIFY(QContactManager::parseUri(uri, 0, &outparameters));
       
   494 
       
   495         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   496 
       
   497         QCOMPARE(parameters, outparameters);
       
   498 
       
   499         outmanager.clear();
       
   500         outparameters.clear();
       
   501         QVERIFY(QContactManager::parseUri(uri, &outmanager, &outparameters));
       
   502 
       
   503         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   504 
       
   505         QCOMPARE(manager, outmanager);
       
   506         QCOMPARE(parameters, outparameters);
       
   507     } else {
       
   508         /* bad splitting */
       
   509         outmanager.clear();
       
   510         outparameters.clear();
       
   511         QVERIFY(QContactManager::parseUri(uri, 0, 0) == false);
       
   512         QVERIFY(QContactManager::parseUri(uri, &outmanager, 0) == false);
       
   513         QVERIFY(outmanager.isEmpty());
       
   514         QVERIFY(QContactManager::parseUri(uri, 0, &outparameters) == false);
       
   515         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   516         QVERIFY(outparameters.isEmpty());
       
   517 
       
   518         /* make sure the in parameters don't change with a bad split */
       
   519         outmanager = manager;
       
   520         outparameters = parameters;
       
   521         QVERIFY(QContactManager::parseUri(uri, &outmanager, 0) == false);
       
   522         QCOMPARE(manager, outmanager);
       
   523         QVERIFY(QContactManager::parseUri(uri, 0, &outparameters) == false);
       
   524         QCONTACTMANAGER_REMOVE_VERSIONS_FROM_URI(outparameters);
       
   525         QCOMPARE(parameters, outparameters);
       
   526     }
       
   527 }
       
   528 
       
   529 void tst_QContactManager::ctors()
       
   530 {
       
   531     /* test the different ctors to make sure we end up with the same uri */
       
   532     QVERIFY(QContactManager::availableManagers().count() > 1); // invalid + something else
       
   533     QVERIFY(QContactManager::availableManagers().contains("invalid"));
       
   534     QString defaultStore = QContactManager::availableManagers().value(0);
       
   535     QVERIFY(defaultStore != "invalid");
       
   536 
       
   537     qDebug() << "Available managers:" << QContactManager::availableManagers();
       
   538 
       
   539     QMap<QString, QString> randomParameters;
       
   540     randomParameters.insert("something", "old");
       
   541     randomParameters.insert("something...", "new");
       
   542     randomParameters.insert("something ", "borrowed");
       
   543     randomParameters.insert(" something", "blue");
       
   544 
       
   545     QObject parent;
       
   546 
       
   547     QContactManager cm; // default
       
   548     QContactManager cm2(defaultStore);
       
   549     QContactManager cm3(defaultStore, QMap<QString, QString>());
       
   550     QContactManager cm4(cm.managerUri()); // should fail
       
   551 
       
   552     QScopedPointer<QContactManager> cm5(QContactManager::fromUri(QContactManager::buildUri(defaultStore, QMap<QString, QString>())));
       
   553     QScopedPointer<QContactManager> cm6(QContactManager::fromUri(cm.managerUri())); // uri is not a name; should fail.
       
   554     QScopedPointer<QContactManager> cm9(QContactManager::fromUri(QString(), &parent));
       
   555 
       
   556     QVERIFY(cm9->parent() == &parent);
       
   557 
       
   558     /* OLD TEST WAS THIS: */
       
   559     //QCOMPARE(cm.managerUri(), cm2.managerUri());
       
   560     //QCOMPARE(cm.managerUri(), cm3.managerUri());
       
   561     //QCOMPARE(cm.managerUri(), cm5->managerUri());
       
   562     //QCOMPARE(cm.managerUri(), cm6->managerUri());
       
   563     //QCOMPARE(cm.managerUri(), cm9->managerUri());
       
   564     /* NEW TEST IS THIS: Test that the names of the managers are the same */
       
   565     QCOMPARE(cm.managerName(), cm2.managerName());
       
   566     QCOMPARE(cm.managerName(), cm3.managerName());
       
   567     QCOMPARE(cm.managerName(), cm5->managerName());
       
   568     QCOMPARE(cm.managerName(), cm6->managerName());
       
   569     QCOMPARE(cm.managerName(), cm9->managerName());
       
   570 
       
   571     QVERIFY(cm.managerUri() != cm4.managerUri()); // don't pass a uri to the ctor
       
   572 
       
   573     /* Test that we get invalid stores when we do silly things */
       
   574     QContactManager em("non existent");
       
   575     QContactManager em2("non existent", QMap<QString, QString>());
       
   576     QContactManager em3("memory", randomParameters);
       
   577 
       
   578     /* Also invalid, since we don't have one of these anyway */
       
   579     QScopedPointer<QContactManager> em4(QContactManager::fromUri("invalid uri"));
       
   580     QScopedPointer<QContactManager> em5(QContactManager::fromUri(QContactManager::buildUri("nonexistent", QMap<QString, QString>())));
       
   581     QScopedPointer<QContactManager> em6(QContactManager::fromUri(em3.managerUri()));
       
   582 
       
   583 
       
   584     /*
       
   585      * Sets of stores that should be equivalent:
       
   586      * - 1, 2, 4, 5
       
   587      * - 3, 6
       
   588      */
       
   589 
       
   590     /* First some URI testing for equivalent stores */
       
   591     QVERIFY(em.managerUri() == em2.managerUri());
       
   592     QVERIFY(em.managerUri() == em5->managerUri());
       
   593     QVERIFY(em.managerUri() == em4->managerUri());
       
   594     QVERIFY(em2.managerUri() == em4->managerUri());
       
   595     QVERIFY(em2.managerUri() == em5->managerUri());
       
   596     QVERIFY(em4->managerUri() == em5->managerUri());
       
   597 
       
   598     QVERIFY(em3.managerUri() == em6->managerUri());
       
   599 
       
   600     /* Test the stores that should not be the same */
       
   601     QVERIFY(em.managerUri() != em3.managerUri());
       
   602     QVERIFY(em.managerUri() != em6->managerUri());
       
   603 
       
   604     /* now the components */
       
   605     QCOMPARE(em.managerName(), QString("invalid"));
       
   606     QCOMPARE(em2.managerName(), QString("invalid"));
       
   607     QCOMPARE(em3.managerName(), QString("memory"));
       
   608     QCOMPARE(em4->managerName(), QString("invalid"));
       
   609     QCOMPARE(em5->managerName(), QString("invalid"));
       
   610     QCOMPARE(em6->managerName(), QString("memory"));
       
   611     QCOMPARE(em.managerParameters(), tst_QContactManager_QStringMap());
       
   612     QCOMPARE(em2.managerParameters(), tst_QContactManager_QStringMap());
       
   613     QCOMPARE(em4->managerParameters(), tst_QContactManager_QStringMap());
       
   614     QCOMPARE(em5->managerParameters(), tst_QContactManager_QStringMap());
       
   615     QCOMPARE(em3.managerParameters(), em6->managerParameters()); // memory engine discards the given params, replaces with id.
       
   616 
       
   617 
       
   618     // Finally test the platform specific engines are actually the defaults
       
   619 #if defined(Q_OS_SYMBIAN)
       
   620     QCOMPARE(defaultStore, QString("symbian"));
       
   621 #elif defined(Q_WS_MAEMO_6)
       
   622     QCOMPARE(defaultStore, QString("tracker"));
       
   623 #elif defined(Q_WS_MAEMO_5)
       
   624     QCOMPARE(defaultStore, QString("maemo5"));
       
   625 #elif defined(Q_OS_WINCE)
       
   626     QCOMPARE(defaultStore, QString("wince"));
       
   627 #else
       
   628     QCOMPARE(defaultStore, QString("memory"));
       
   629 #endif
       
   630 }
       
   631 
       
   632 void tst_QContactManager::doDump()
       
   633 {
       
   634     // Only do this if it has been explicitly selected
       
   635     if (QCoreApplication::arguments().contains("doDump")) {
       
   636         QFETCH(QString, uri);
       
   637         QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   638 
       
   639         dumpContacts(cm.data());
       
   640     }
       
   641 }
       
   642 
       
   643 Q_DECLARE_METATYPE(QVariant)
       
   644 
       
   645 void tst_QContactManager::doDumpSchema()
       
   646 {
       
   647     // Only do this if it has been explicitly selected
       
   648     if (QCoreApplication::arguments().contains("doDumpSchema")) {
       
   649         QFETCH(QString, uri);
       
   650         QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   651 
       
   652         // Get the schema for each supported type
       
   653         foreach(QString type, cm->supportedContactTypes()) {
       
   654             QMap<QString, QContactDetailDefinition> defs = cm->detailDefinitions(type);
       
   655 
       
   656             foreach(QContactDetailDefinition def, defs.values()) {
       
   657                 if (def.isUnique())
       
   658                     qDebug() << QString("%2::%1 (Unique) {").arg(def.name()).arg(type).toAscii().constData();
       
   659                 else
       
   660                     qDebug() << QString("%2::%1 {").arg(def.name()).arg(type).toAscii().constData();
       
   661                 QMap<QString, QContactDetailFieldDefinition> fields = def.fields();
       
   662 
       
   663                 foreach(QString fname, fields.keys()) {
       
   664                     QContactDetailFieldDefinition field = fields.value(fname);
       
   665 
       
   666                     if (field.allowableValues().count() > 0) {
       
   667                         // Make some pretty output
       
   668                         QStringList allowedList;
       
   669                         foreach(QVariant var, field.allowableValues()) {
       
   670                             QString allowed;
       
   671                             if (var.type() == QVariant::String)
       
   672                                 allowed = QString("'%1'").arg(var.toString());
       
   673                             else if (var.type() == QVariant::StringList)
       
   674                                 allowed = QString("'%1'").arg(var.toStringList().join(","));
       
   675                             else {
       
   676                                 // use the textstream <<
       
   677                                 QDebug dbg(&allowed);
       
   678                                 dbg << var;
       
   679                             }
       
   680                             allowedList.append(allowed);
       
   681                         }
       
   682 
       
   683                         qDebug() << QString("   %2 %1 {%3}").arg(fname).arg(QMetaType::typeName(field.dataType())).arg(allowedList.join(",")).toAscii().constData();
       
   684                     } else
       
   685                         qDebug() << QString("   %2 %1").arg(fname).arg(QMetaType::typeName(field.dataType())).toAscii().constData();
       
   686                 }
       
   687 
       
   688                 qDebug() << "}";
       
   689             }
       
   690         }
       
   691     }
       
   692 }
       
   693 
       
   694 void tst_QContactManager::add()
       
   695 {
       
   696     QFETCH(QString, uri);
       
   697     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   698 
       
   699     QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
   700     QContact alice = createContact(nameDef, "Alice", "inWonderland", "1234567");
       
   701     int currCount = cm->contactIds().count();
       
   702     QVERIFY(cm->saveContact(&alice));
       
   703     QVERIFY(cm->error() == QContactManager::NoError);
       
   704 
       
   705     QVERIFY(alice.id() != QContactId());
       
   706     QCOMPARE(cm->contactIds().count(), currCount+1);
       
   707 
       
   708     QContact added = cm->contact(alice.id().localId());
       
   709     QVERIFY(added.id() != QContactId());
       
   710     QVERIFY(added.id() == alice.id());
       
   711 
       
   712     if (!isSuperset(added, alice)) {
       
   713         dumpContacts(cm.data());
       
   714         dumpContactDifferences(added, alice);
       
   715         QCOMPARE(added, alice);
       
   716     }
       
   717 
       
   718     // now try adding a contact that does not exist in the database with non-zero id
       
   719     QContact nonexistent = createContact(nameDef, "nonexistent", "contact", "");
       
   720     QVERIFY(cm->saveContact(&nonexistent));       // should work
       
   721     QVERIFY(cm->removeContact(nonexistent.id().localId())); // now nonexistent has an id which does not exist
       
   722     QVERIFY(!cm->saveContact(&nonexistent));      // hence, should fail
       
   723     QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
       
   724     nonexistent.setId(QContactId());
       
   725     QVERIFY(cm->saveContact(&nonexistent));       // after setting id to zero, should save
       
   726     QVERIFY(cm->removeContact(nonexistent.id().localId()));
       
   727 
       
   728     // now try adding a "megacontact"
       
   729     // - get list of all definitions supported by the manager
       
   730     // - add one detail of each definition to a contact
       
   731     // - save the contact
       
   732     // - read it back
       
   733     // - ensure that it's the same.
       
   734     QContact megacontact;
       
   735     QMap<QString, QContactDetailDefinition> defmap = cm->detailDefinitions();
       
   736     QList<QContactDetailDefinition> defs = defmap.values();
       
   737     foreach (const QContactDetailDefinition def, defs) {
       
   738 
       
   739         // Leave these warnings here - might need an API for this
       
   740         if (def.accessConstraint() == QContactDetailDefinition::ReadOnly) {
       
   741             continue;
       
   742         }
       
   743 
       
   744         // otherwise, create a new detail of the given type and save it to the contact
       
   745         QContactDetail det(def.name());
       
   746         QMap<QString, QContactDetailFieldDefinition> fieldmap = def.fields();
       
   747         QStringList fieldKeys = fieldmap.keys();
       
   748         foreach (const QString& fieldKey, fieldKeys) {
       
   749             // get the field, and check to see that it's not constrained.
       
   750             QContactDetailFieldDefinition currentField = fieldmap.value(fieldKey);
       
   751 
       
   752             // Attempt to create a worthy value
       
   753             if (!currentField.allowableValues().isEmpty()) {
       
   754                 // we want to save a value that will be accepted.
       
   755                 if (currentField.dataType() == QVariant::StringList)
       
   756                     det.setValue(fieldKey, QStringList() << currentField.allowableValues().first().toString());
       
   757                 else if (currentField.dataType() == QVariant::List)
       
   758                     det.setValue(fieldKey, QVariantList() << currentField.allowableValues().first());
       
   759                 else
       
   760                     det.setValue(fieldKey, currentField.allowableValues().first());
       
   761             } else {
       
   762                 // any value of the correct type will be accepted
       
   763                 bool savedSuccessfully = false;
       
   764                 QVariant dummyValue = QVariant(fieldKey); // try to get some unique string data
       
   765                 if (dummyValue.canConvert(currentField.dataType())) {
       
   766                     savedSuccessfully = dummyValue.convert(currentField.dataType());
       
   767                     if (savedSuccessfully) {
       
   768                         // we have successfully created a (supposedly) valid field for this detail.
       
   769                         det.setValue(fieldKey, dummyValue);
       
   770                         continue;
       
   771                     }
       
   772                 }
       
   773 
       
   774                 // nope, couldn't save the string value (test); try a date.
       
   775                 dummyValue = QVariant(QDate::currentDate());
       
   776                 if (dummyValue.canConvert(currentField.dataType())) {
       
   777                     savedSuccessfully = dummyValue.convert(currentField.dataType());
       
   778                     if (savedSuccessfully) {
       
   779                         // we have successfully created a (supposedly) valid field for this detail.
       
   780                         det.setValue(fieldKey, dummyValue);
       
   781                         continue;
       
   782                     }
       
   783                 }
       
   784 
       
   785                 // nope, couldn't convert a string or a date - try the integer value (42)
       
   786                 dummyValue = QVariant(42);
       
   787                 if (dummyValue.canConvert(currentField.dataType())) {
       
   788                     savedSuccessfully = dummyValue.convert(currentField.dataType());
       
   789                     if (savedSuccessfully) {
       
   790                         // we have successfully created a (supposedly) valid field for this detail.
       
   791                         det.setValue(fieldKey, dummyValue);
       
   792                         continue;
       
   793                     }
       
   794                 }
       
   795 
       
   796                 // if we get here, we don't know what sort of value can be saved...
       
   797             }
       
   798         }
       
   799         megacontact.saveDetail(&det);
       
   800     }
       
   801 
       
   802     QVERIFY(cm->saveContact(&megacontact)); // must be able to save since built from definitions.
       
   803     QContact retrievedMegacontact = cm->contact(megacontact.id().localId());
       
   804     if (retrievedMegacontact != megacontact) {
       
   805         dumpContactDifferences(megacontact, retrievedMegacontact);
       
   806         QEXPECT_FAIL("mgr='wince'", "Address Display Label mismatch", Continue);
       
   807         QCOMPARE(megacontact, retrievedMegacontact);
       
   808     }
       
   809 
       
   810     // now a contact with many details of a particular definition
       
   811     // this will fail on some backends; how do we query for this capability?
       
   812     QContact veryContactable = createContact(nameDef, "Very", "Contactable", "");
       
   813     for (int i = 0; i < 50; i++) {
       
   814         QString phnStr = QString::number(i);
       
   815         QContactPhoneNumber vcphn;
       
   816         vcphn.setNumber(phnStr);
       
   817         QVERIFY(veryContactable.saveDetail(&vcphn));
       
   818     }
       
   819 
       
   820     // check that all the numbers were added successfully, and that it can be saved.
       
   821     QVERIFY(veryContactable.details(QContactPhoneNumber::DefinitionName).size() == 50);
       
   822     QVERIFY(cm->saveContact(&veryContactable));
       
   823     QContact retrievedContactable = cm->contact(veryContactable.id().localId());
       
   824     if (retrievedContactable != veryContactable) {
       
   825         dumpContactDifferences(veryContactable, retrievedContactable);
       
   826         QEXPECT_FAIL("mgr='wince'", "Number of phones supported mismatch", Continue);
       
   827         QCOMPARE(veryContactable, retrievedContactable);
       
   828     }
       
   829 }
       
   830 
       
   831 void tst_QContactManager::update()
       
   832 {
       
   833     QFETCH(QString, uri);
       
   834     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   835 
       
   836     /* Save a new contact first */
       
   837     QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
   838     QContact alice = createContact(nameDef, "Alice", "inWonderland", "1234567");
       
   839     QVERIFY(cm->saveContact(&alice));
       
   840     QVERIFY(cm->error() == QContactManager::NoError);
       
   841 
       
   842     /* Update name */
       
   843     QContactName name = alice.detail(QContactName::DefinitionName);
       
   844     setContactName(nameDef, name, "updated");
       
   845     alice.saveDetail(&name);
       
   846     QVERIFY(cm->saveContact(&alice));
       
   847     QVERIFY(cm->error() == QContactManager::NoError);
       
   848     QContact updated = cm->contact(alice.localId());
       
   849     QContactName updatedName = updated.detail(QContactName::DefinitionName);
       
   850     QCOMPARE(updatedName, name);
       
   851 
       
   852     if (cm->hasFeature(QContactManager::Groups)) {
       
   853         // Try changing types - not allowed
       
   854         // from contact -> group
       
   855         alice.setType(QContactType::TypeGroup);
       
   856         QContactName na = alice.detail(QContactName::DefinitionName);
       
   857         alice.removeDetail(&na);
       
   858         QVERIFY(!cm->saveContact(&alice));
       
   859         QVERIFY(cm->error() == QContactManager::AlreadyExistsError);
       
   860 
       
   861         // from group -> contact
       
   862         QContact jabberwock = createContact(nameDef, "", "", "1234567890");
       
   863         jabberwock.setType(QContactType::TypeGroup);
       
   864         QVERIFY(cm->saveContact(&jabberwock));
       
   865         jabberwock.setType(QContactType::TypeContact);
       
   866         QVERIFY(!cm->saveContact(&jabberwock));
       
   867         QVERIFY(cm->error() == QContactManager::AlreadyExistsError);
       
   868     }
       
   869 }
       
   870 
       
   871 void tst_QContactManager::remove()
       
   872 {
       
   873     QFETCH(QString, uri);
       
   874     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   875 
       
   876     /* Save a new contact first */
       
   877     QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
   878     QContact alice = createContact(nameDef, "Alice", "inWonderland", "1234567");
       
   879     QVERIFY(cm->saveContact(&alice));
       
   880     QVERIFY(cm->error() == QContactManager::NoError);
       
   881     QVERIFY(alice.id() != QContactId());
       
   882 
       
   883     /* Remove the created contact */
       
   884     const int contactCount = cm->contactIds().count();
       
   885     QVERIFY(cm->removeContact(alice.localId()));
       
   886     QCOMPARE(cm->contactIds().count(), contactCount - 1);
       
   887     QVERIFY(cm->contact(alice.localId()).isEmpty());
       
   888     QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
       
   889 }
       
   890 
       
   891 void tst_QContactManager::batch()
       
   892 {
       
   893     QFETCH(QString, uri);
       
   894     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
   895 
       
   896     /* First test null pointer operations */
       
   897     QVERIFY(!cm->saveContacts(0, 0));
       
   898     QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
   899 
       
   900     QVERIFY(!cm->removeContacts(0, 0));
       
   901     QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
   902 
       
   903     /* Now add 3 contacts, all valid */
       
   904     QContact a;
       
   905     QContactName na;
       
   906     na.setFirstName("XXXXXX Albert");
       
   907     a.saveDetail(&na);
       
   908 
       
   909     QContact b;
       
   910     QContactName nb;
       
   911     nb.setFirstName("XXXXXX Bob");
       
   912     b.saveDetail(&nb);
       
   913 
       
   914     QContact c;
       
   915     QContactName nc;
       
   916     nc.setFirstName("XXXXXX Carol");
       
   917     c.saveDetail(&nc);
       
   918 
       
   919     QList<QContact> contacts;
       
   920     contacts << a << b << c;
       
   921 
       
   922     QMap<int, QContactManager::Error> errorMap;
       
   923     // Add one dummy error to test if the errors are reset
       
   924     errorMap.insert(0, QContactManager::NoError);
       
   925     QVERIFY(cm->saveContacts(&contacts, &errorMap));
       
   926     QVERIFY(cm->error() == QContactManager::NoError);
       
   927     QVERIFY(errorMap.count() == 0);
       
   928 
       
   929     /* Make sure our contacts got updated too */
       
   930     QVERIFY(contacts.count() == 3);
       
   931     QVERIFY(contacts.at(0).id() != QContactId());
       
   932     QVERIFY(contacts.at(1).id() != QContactId());
       
   933     QVERIFY(contacts.at(2).id() != QContactId());
       
   934 
       
   935     QVERIFY(contacts.at(0).detail(QContactName::DefinitionName) == na);
       
   936     QVERIFY(contacts.at(1).detail(QContactName::DefinitionName) == nb);
       
   937     QVERIFY(contacts.at(2).detail(QContactName::DefinitionName) == nc);
       
   938 
       
   939     /* Retrieve again */
       
   940     a = cm->contact(contacts.at(0).id().localId());
       
   941     b = cm->contact(contacts.at(1).id().localId());
       
   942     c = cm->contact(contacts.at(2).id().localId());
       
   943     QVERIFY(contacts.at(0).detail(QContactName::DefinitionName) == na);
       
   944     QVERIFY(contacts.at(1).detail(QContactName::DefinitionName) == nb);
       
   945     QVERIFY(contacts.at(2).detail(QContactName::DefinitionName) == nc);
       
   946 
       
   947     /* Now make an update to them all */
       
   948     QContactPhoneNumber number;
       
   949     number.setNumber("1234567");
       
   950 
       
   951     QVERIFY(contacts[0].saveDetail(&number));
       
   952     number.setNumber("234567");
       
   953     QVERIFY(contacts[1].saveDetail(&number));
       
   954     number.setNumber("34567");
       
   955     QVERIFY(contacts[2].saveDetail(&number));
       
   956 
       
   957     QVERIFY(cm->saveContacts(&contacts, &errorMap));
       
   958     QVERIFY(cm->error() == QContactManager::NoError);
       
   959     QVERIFY(errorMap.count() == 0);
       
   960 
       
   961     /* Retrieve them and check them again */
       
   962     a = cm->contact(contacts.at(0).id().localId());
       
   963     b = cm->contact(contacts.at(1).id().localId());
       
   964     c = cm->contact(contacts.at(2).id().localId());
       
   965     QVERIFY(contacts.at(0).detail(QContactName::DefinitionName) == na);
       
   966     QVERIFY(contacts.at(1).detail(QContactName::DefinitionName) == nb);
       
   967     QVERIFY(contacts.at(2).detail(QContactName::DefinitionName) == nc);
       
   968 
       
   969     QVERIFY(a.details<QContactPhoneNumber>().count() == 1);
       
   970     QVERIFY(b.details<QContactPhoneNumber>().count() == 1);
       
   971     QVERIFY(c.details<QContactPhoneNumber>().count() == 1);
       
   972 
       
   973     QVERIFY(a.details<QContactPhoneNumber>().at(0).number() == "1234567");
       
   974     QVERIFY(b.details<QContactPhoneNumber>().at(0).number() == "234567");
       
   975     QVERIFY(c.details<QContactPhoneNumber>().at(0).number() == "34567");
       
   976 
       
   977     /* Now delete them all */
       
   978     QList<QContactLocalId> ids;
       
   979     QContactLocalId removedIdForLater = b.id().localId();
       
   980     ids << a.id().localId() << b.id().localId() << c.id().localId();
       
   981     QVERIFY(cm->removeContacts(&ids, &errorMap));
       
   982     QVERIFY(errorMap.count() == 0);
       
   983     QVERIFY(cm->error() == QContactManager::NoError);
       
   984 
       
   985     /* Make sure all the ids are now 0 */
       
   986     QVERIFY(ids.count() == 3);
       
   987     QVERIFY(ids.at(0) == 0);
       
   988     QVERIFY(ids.at(1) == 0);
       
   989     QVERIFY(ids.at(2) == 0);
       
   990 
       
   991     /* Make sure the contacts really don't exist any more */
       
   992     QVERIFY(cm->contact(a.id().localId()).id() == QContactId());
       
   993     QVERIFY(cm->contact(a.id().localId()).isEmpty());
       
   994     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
   995     QVERIFY(cm->contact(b.id().localId()).id() == QContactId());
       
   996     QVERIFY(cm->contact(b.id().localId()).isEmpty());
       
   997     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
   998     QVERIFY(cm->contact(c.id().localId()).id() == QContactId());
       
   999     QVERIFY(cm->contact(c.id().localId()).isEmpty());
       
  1000     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1001 
       
  1002     /* Now try removing with all invalid ids (e.g. the ones we just removed) */
       
  1003     ids.clear();
       
  1004     ids << a.id().localId() << b.id().localId() << c.id().localId();
       
  1005     QVERIFY(!cm->removeContacts(&ids, &errorMap));
       
  1006     QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  1007     QVERIFY(errorMap.count() == 3);
       
  1008     QVERIFY(errorMap.values().at(0) == QContactManager::DoesNotExistError);
       
  1009     QVERIFY(errorMap.values().at(1) == QContactManager::DoesNotExistError);
       
  1010     QVERIFY(errorMap.values().at(2) == QContactManager::DoesNotExistError);
       
  1011 
       
  1012     /* Try adding some new ones again, this time one with an error */
       
  1013     contacts.clear();
       
  1014     a.setId(QContactId());
       
  1015     b.setId(QContactId());
       
  1016     c.setId(QContactId());
       
  1017 
       
  1018     /* Make B the bad guy */
       
  1019     QContactDetail bad("does not exist and will break if you add it");
       
  1020     bad.setValue("This is also bad", "Very bad");
       
  1021     b.saveDetail(&bad);
       
  1022 
       
  1023     contacts << a << b << c;
       
  1024     QVERIFY(!cm->saveContacts(&contacts, &errorMap));
       
  1025     /* We can't really say what the error will be.. maybe bad argument, maybe invalid detail */
       
  1026     QVERIFY(cm->error() != QContactManager::NoError);
       
  1027 
       
  1028     /* It's permissible to fail all the adds, or to add the successful ones */
       
  1029     QVERIFY(errorMap.count() > 0);
       
  1030     QVERIFY(errorMap.count() <= 3);
       
  1031 
       
  1032     // A might have gone through
       
  1033     if (errorMap.keys().contains(0)) {
       
  1034         QVERIFY(errorMap.value(0) != QContactManager::NoError);
       
  1035         QVERIFY(contacts.at(0).id() == QContactId());
       
  1036     } else {
       
  1037         QVERIFY(contacts.at(0).id() != QContactId());
       
  1038     }
       
  1039 
       
  1040     // B should have failed
       
  1041     QVERIFY(errorMap.value(1) == QContactManager::InvalidDetailError);
       
  1042     QVERIFY(contacts.at(1).id() == QContactId());
       
  1043 
       
  1044     // C might have gone through
       
  1045     if (errorMap.keys().contains(2)) {
       
  1046         QVERIFY(errorMap.value(2) != QContactManager::NoError);
       
  1047         QVERIFY(contacts.at(2).id() == QContactId());
       
  1048     } else {
       
  1049         QVERIFY(contacts.at(2).id() != QContactId());
       
  1050     }
       
  1051 
       
  1052     /* Fix up B and re save it */
       
  1053     QVERIFY(contacts[1].removeDetail(&bad));
       
  1054     QVERIFY(cm->saveContacts(&contacts, &errorMap));
       
  1055     QVERIFY(errorMap.count() == 0);
       
  1056     QVERIFY(cm->error() == QContactManager::NoError);
       
  1057 
       
  1058     /* Now delete 3 items, but with one bad argument */
       
  1059     ids.clear();
       
  1060     ids << contacts.at(0).id().localId();
       
  1061     ids << removedIdForLater;
       
  1062     ids << contacts.at(2).id().localId();
       
  1063 
       
  1064     QVERIFY(!cm->removeContacts(&ids, &errorMap));
       
  1065     QVERIFY(cm->error() != QContactManager::NoError);
       
  1066 
       
  1067     /* Again, the backend has the choice of either removing the successful ones, or not */
       
  1068     QVERIFY(errorMap.count() > 0);
       
  1069     QVERIFY(errorMap.count() <= 3);
       
  1070 
       
  1071     // A might have gone through
       
  1072     if (errorMap.keys().contains(0)) {
       
  1073         QVERIFY(errorMap.value(0) != QContactManager::NoError);
       
  1074         QVERIFY(contacts.at(0).id() == QContactId());
       
  1075     } else {
       
  1076         QVERIFY(contacts.at(0).id() != QContactId());
       
  1077     }
       
  1078 
       
  1079     /* B should definitely have failed */
       
  1080     QVERIFY(errorMap.value(1) == QContactManager::DoesNotExistError);
       
  1081     QVERIFY(ids.at(1) == removedIdForLater);
       
  1082 
       
  1083     // A might have gone through
       
  1084     if (errorMap.keys().contains(2)) {
       
  1085         QVERIFY(errorMap.value(2) != QContactManager::NoError);
       
  1086         QVERIFY(contacts.at(2).id() == QContactId());
       
  1087     } else {
       
  1088         QVERIFY(contacts.at(2).id() != QContactId());
       
  1089     }
       
  1090 }
       
  1091 
       
  1092 void tst_QContactManager::invalidManager()
       
  1093 {
       
  1094     /* Create an invalid manager */
       
  1095     QContactManager manager("this should never work");
       
  1096     QVERIFY(manager.managerName() == "invalid");
       
  1097     QVERIFY(manager.managerVersion() == 0);
       
  1098 
       
  1099     /* also, test the other ctor behaviour is sane also */
       
  1100     QContactManager anotherManager("this should never work", 15);
       
  1101     QVERIFY(anotherManager.managerName() == "invalid");
       
  1102     QVERIFY(anotherManager.managerVersion() == 0);
       
  1103 
       
  1104     /* Now test that all the operations fail */
       
  1105     QVERIFY(manager.contactIds().count() == 0);
       
  1106     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1107 
       
  1108     QContact foo;
       
  1109     QContactName nf;
       
  1110     nf.setLastName("Lastname");
       
  1111     foo.saveDetail(&nf);
       
  1112 
       
  1113     QVERIFY(manager.synthesizedDisplayLabel(foo).isEmpty());
       
  1114     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1115 
       
  1116     QVERIFY(manager.saveContact(&foo) == false);
       
  1117     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1118     QVERIFY(foo.id() == QContactId());
       
  1119     QVERIFY(manager.contactIds().count() == 0);
       
  1120 
       
  1121     QVERIFY(manager.contact(foo.id().localId()).id() == QContactId());
       
  1122     QVERIFY(manager.contact(foo.id().localId()).isEmpty());
       
  1123     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1124 
       
  1125     QVERIFY(manager.removeContact(foo.id().localId()) == false);
       
  1126     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1127 
       
  1128     QMap<int, QContactManager::Error> errorMap;
       
  1129     errorMap.insert(0, QContactManager::NoError);
       
  1130     QVERIFY(!manager.saveContacts(0, &errorMap));
       
  1131     QVERIFY(errorMap.count() == 0);
       
  1132     QVERIFY(manager.error() == QContactManager::BadArgumentError);
       
  1133 
       
  1134     /* filters */
       
  1135     QContactFilter f; // matches everything
       
  1136     QContactDetailFilter df;
       
  1137     df.setDetailDefinitionName(QContactDisplayLabel::DefinitionName, QContactDisplayLabel::FieldLabel);
       
  1138     QVERIFY(manager.contactIds(QContactFilter()).count() == 0);
       
  1139     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1140     QVERIFY(manager.contactIds(df).count() == 0);
       
  1141     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1142     QVERIFY(manager.contactIds(f | f).count() == 0);
       
  1143     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1144     QVERIFY(manager.contactIds(df | df).count() == 0);
       
  1145     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1146 
       
  1147     QVERIFY(manager.isFilterSupported(f) == false);
       
  1148     QVERIFY(manager.isFilterSupported(df) == false);
       
  1149 
       
  1150     QList<QContact> list;
       
  1151     list << foo;
       
  1152 
       
  1153     QVERIFY(!manager.saveContacts(&list, &errorMap));
       
  1154     QVERIFY(errorMap.count() == 1);
       
  1155     QVERIFY(errorMap.value(0) == QContactManager::NotSupportedError);
       
  1156     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1157 
       
  1158     QVERIFY(!manager.removeContacts(0, &errorMap));
       
  1159     QVERIFY(errorMap.count() == 0);
       
  1160     QVERIFY(manager.error() == QContactManager::BadArgumentError);
       
  1161 
       
  1162     QList<QContactLocalId> idlist;
       
  1163     idlist << foo.id().localId();
       
  1164     QVERIFY(!manager.removeContacts(&idlist, &errorMap));
       
  1165     QVERIFY(errorMap.count() == 1);
       
  1166     QVERIFY(errorMap.value(0) == QContactManager::NotSupportedError);
       
  1167     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1168 
       
  1169     /* Detail definitions */
       
  1170     QVERIFY(manager.detailDefinitions().count() == 0);
       
  1171     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1172 
       
  1173     QContactDetailDefinition def;
       
  1174     def.setUnique(true);
       
  1175     def.setName("new field");
       
  1176     QMap<QString, QContactDetailFieldDefinition> fields;
       
  1177     QContactDetailFieldDefinition currField;
       
  1178     currField.setDataType(QVariant::String);
       
  1179     fields.insert("value", currField);
       
  1180     def.setFields(fields);
       
  1181 
       
  1182     QVERIFY(manager.saveDetailDefinition(def, QContactType::TypeContact) == false);
       
  1183     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1184     QVERIFY(manager.saveDetailDefinition(def) == false);
       
  1185     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1186     QVERIFY(manager.detailDefinitions().count(QContactType::TypeContact) == 0);
       
  1187     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1188     QVERIFY(manager.detailDefinitions().count() == 0);
       
  1189     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1190     QVERIFY(manager.detailDefinition("new field").name() == QString());
       
  1191     QVERIFY(manager.removeDetailDefinition(def.name(), QContactType::TypeContact) == false);
       
  1192     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1193     QVERIFY(manager.removeDetailDefinition(def.name()) == false);
       
  1194     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1195     QVERIFY(manager.detailDefinitions().count() == 0);
       
  1196     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::InvalidContactTypeError);
       
  1197 
       
  1198     /* Self contact id */
       
  1199     QVERIFY(!manager.setSelfContactId(QContactLocalId(12)));
       
  1200     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1201     QVERIFY(manager.selfContactId() == QContactLocalId());
       
  1202     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::DoesNotExistError);
       
  1203 
       
  1204     /* Relationships */
       
  1205     QContactId idOne, idTwo;
       
  1206     idOne.setLocalId(QContactLocalId(15));
       
  1207     idOne.setManagerUri(QString());
       
  1208     idTwo.setLocalId(QContactLocalId(22));
       
  1209     idTwo.setManagerUri(QString());
       
  1210     QContactRelationship invalidRel;
       
  1211     invalidRel.setFirst(idOne);
       
  1212     invalidRel.setSecond(idTwo);
       
  1213     QList<QContactRelationship> invalidRelList;
       
  1214     invalidRelList << invalidRel;
       
  1215     QVERIFY(!manager.saveRelationship(&invalidRel));
       
  1216     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1217     QVERIFY(manager.relationships().isEmpty());
       
  1218     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1219     manager.saveRelationships(&invalidRelList);
       
  1220     QVERIFY(manager.error() == QContactManager::NotSupportedError);
       
  1221     manager.removeRelationships(invalidRelList);
       
  1222     QVERIFY(manager.error() == QContactManager::NotSupportedError || manager.error() == QContactManager::DoesNotExistError);
       
  1223 
       
  1224     /* Capabilities */
       
  1225     QVERIFY(manager.supportedDataTypes().count() == 0);
       
  1226     QVERIFY(!manager.hasFeature(QContactManager::ActionPreferences));
       
  1227     QVERIFY(!manager.hasFeature(QContactManager::MutableDefinitions));
       
  1228 }
       
  1229 
       
  1230 void tst_QContactManager::memoryManager()
       
  1231 {
       
  1232     QMap<QString, QString> params;
       
  1233     QContactManager m1("memory");
       
  1234     params.insert("random", "shouldNotBeUsed");
       
  1235     QContactManager m2("memory", params);
       
  1236     params.insert("id", "shouldBeUsed");
       
  1237     QContactManager m3("memory", params);
       
  1238     QContactManager m4("memory", params);
       
  1239     params.insert("id", QString(""));
       
  1240     QContactManager m5("memory", params); // should be another anonymous
       
  1241 
       
  1242     QVERIFY(m1.hasFeature(QContactManager::ActionPreferences));
       
  1243     QVERIFY(m1.hasFeature(QContactManager::MutableDefinitions));
       
  1244     QVERIFY(m1.hasFeature(QContactManager::Anonymous));
       
  1245 
       
  1246     // add a contact to each of m1, m2, m3
       
  1247     QContact c;
       
  1248     QContactName nc;
       
  1249     nc.setFirstName("John");
       
  1250     nc.setLastName("Civilian");
       
  1251     c.saveDetail(&nc);
       
  1252     m1.saveContact(&c);
       
  1253     c.setId(QContactId());
       
  1254     QContact c2;
       
  1255     QContactName nc2 = c2.detail(QContactName::DefinitionName);
       
  1256     c2 = c;
       
  1257     nc2.setMiddleName("Public");
       
  1258     c2.saveDetail(&nc2);
       
  1259     m2.saveContact(&c2);            // save c2 first; c will be given a higher id
       
  1260     m2.saveContact(&c);             // save c to m2
       
  1261     c.setId(QContactId());
       
  1262     nc.setSuffix("MD");
       
  1263     c.saveDetail(&nc);
       
  1264     m3.saveContact(&c);
       
  1265 
       
  1266     /* test that m1 != m2 != m3 and that m3 == m4 */
       
  1267 
       
  1268     // check the counts are correct - especially note m4 and m3.
       
  1269     QCOMPARE(m1.contactIds().count(), 1);
       
  1270     QCOMPARE(m2.contactIds().count(), 2);
       
  1271     QCOMPARE(m3.contactIds().count(), 1);
       
  1272     QCOMPARE(m4.contactIds().count(), 1);
       
  1273     QCOMPARE(m5.contactIds().count(), 0);
       
  1274 
       
  1275     // remove c2 from m2 - ensure that this doesn't affect any other manager.
       
  1276     m2.removeContact(c2.id().localId());
       
  1277     QCOMPARE(m1.contactIds().count(), 1);
       
  1278     QCOMPARE(m2.contactIds().count(), 1);
       
  1279     QCOMPARE(m3.contactIds().count(), 1);
       
  1280     QCOMPARE(m4.contactIds().count(), 1);
       
  1281     QCOMPARE(m5.contactIds().count(), 0);
       
  1282 
       
  1283     // check that the contacts contained within are different.
       
  1284     // note that in the m1->m2 case, only the id will be different!
       
  1285     QVERIFY(m1.contact(m1.contactIds().at(0)) != m2.contact(m2.contactIds().at(0)));
       
  1286     QVERIFY(m1.contact(m1.contactIds().at(0)) != m3.contact(m3.contactIds().at(0)));
       
  1287     QVERIFY(m2.contact(m2.contactIds().at(0)) != m3.contact(m3.contactIds().at(0)));
       
  1288     QVERIFY(m3.contact(m3.contactIds().at(0)) == m4.contact(m4.contactIds().at(0)));
       
  1289 
       
  1290     // now, we should be able to remove from m4, and have m3 empty
       
  1291     QVERIFY(m4.removeContact(c.id().localId()));
       
  1292     QCOMPARE(m3.contactIds().count(), 0);
       
  1293     QCOMPARE(m4.contactIds().count(), 0);
       
  1294     QCOMPARE(m5.contactIds().count(), 0);
       
  1295 }
       
  1296 
       
  1297 void tst_QContactManager::nameSynthesis_data()
       
  1298 {
       
  1299     QTest::addColumn<QString>("expected");
       
  1300 
       
  1301     QTest::addColumn<bool>("addname");
       
  1302     QTest::addColumn<QString>("prefix");
       
  1303     QTest::addColumn<QString>("first");
       
  1304     QTest::addColumn<QString>("middle");
       
  1305     QTest::addColumn<QString>("last");
       
  1306     QTest::addColumn<QString>("suffix");
       
  1307 
       
  1308     QTest::addColumn<bool>("addcompany");
       
  1309     QTest::addColumn<QString>("company");
       
  1310 
       
  1311     QTest::addColumn<bool>("addname2");
       
  1312     QTest::addColumn<QString>("secondprefix");
       
  1313     QTest::addColumn<QString>("secondfirst");
       
  1314     QTest::addColumn<QString>("secondmiddle");
       
  1315     QTest::addColumn<QString>("secondlast");
       
  1316     QTest::addColumn<QString>("secondsuffix");
       
  1317 
       
  1318     QTest::addColumn<bool>("addcompany2");
       
  1319     QTest::addColumn<QString>("secondcompany");
       
  1320 
       
  1321     QString e; // empty string.. gets a work out
       
  1322 
       
  1323     /* Various empty ones */
       
  1324     QTest::newRow("empty contact") << e
       
  1325             << false << e << e << e << e << e
       
  1326             << false << e
       
  1327             << false << e << e << e << e << e
       
  1328             << false << e;
       
  1329     QTest::newRow("empty name") << e
       
  1330             << true << e << e << e << e << e
       
  1331             << false << e
       
  1332             << false << e << e << e << e << e
       
  1333             << false << e;
       
  1334     QTest::newRow("empty names") << e
       
  1335             << true << e << e << e << e << e
       
  1336             << false << e
       
  1337             << true << e << e << e << e << e
       
  1338             << false << e;
       
  1339     QTest::newRow("empty org") << e
       
  1340             << false << e << e << e << e << e
       
  1341             << true << e
       
  1342             << false << e << e << e << e << e
       
  1343             << true << e;
       
  1344     QTest::newRow("empty orgs") << e
       
  1345             << false << e << e << e << e << e
       
  1346             << true << e
       
  1347             << false << e << e << e << e << e
       
  1348             << true << e;
       
  1349     QTest::newRow("empty orgs and names") << e
       
  1350             << true << e << e << e << e << e
       
  1351             << true << e
       
  1352             << true << e << e << e << e << e
       
  1353             << true << e;
       
  1354 
       
  1355     /* Single values */
       
  1356     QTest::newRow("prefix") << "Prefix"
       
  1357             << true << "Prefix" << e << e << e << e
       
  1358             << false << e
       
  1359             << false << e << e << e << e << e
       
  1360             << false << e;
       
  1361     QTest::newRow("first") << "First"
       
  1362             << true << e << "First" << e << e << e
       
  1363             << false << e
       
  1364             << false << e << e << e << e << e
       
  1365             << false << e;
       
  1366     QTest::newRow("middle") << "Middle"
       
  1367             << true << e << e << "Middle" << e << e
       
  1368             << false << e
       
  1369             << false << e << e << e << e << e
       
  1370             << false << e;
       
  1371     QTest::newRow("last") << "Last"
       
  1372             << true << e << e << e << "Last" << e
       
  1373             << false << e
       
  1374             << false << e << e << e << e << e
       
  1375             << false << e;
       
  1376     QTest::newRow("suffix") << "Suffix"
       
  1377             << true << e << e << e << e << "Suffix"
       
  1378             << false << e
       
  1379             << false << e << e << e << e << e
       
  1380             << false << e;
       
  1381 
       
  1382     /* Single values in the second name */
       
  1383     QTest::newRow("prefix in second") << "Prefix"
       
  1384             << false << "Prefix" << e << e << e << e
       
  1385             << false << e
       
  1386             << true << "Prefix" << e << e << e << e
       
  1387             << false << e;
       
  1388     QTest::newRow("first in second") << "First"
       
  1389             << false << e << "First" << e << e << e
       
  1390             << false << e
       
  1391             << true << e << "First" << e << e << e
       
  1392             << false << e;
       
  1393     QTest::newRow("middle in second") << "Middle"
       
  1394             << false << e << e << "Middle" << e << e
       
  1395             << false << e
       
  1396             << true << e << e << "Middle" << e << e
       
  1397             << false << e;
       
  1398     QTest::newRow("last in second") << "Last"
       
  1399             << false << e << e << e << "Last" << e
       
  1400             << false << e
       
  1401             << true << e << e << e << "Last" << e
       
  1402             << false << e;
       
  1403     QTest::newRow("suffix in second") << "Suffix"
       
  1404             << false << e << e << e << e << "Suffix"
       
  1405             << false << e
       
  1406             << true << e << e << e << e << "Suffix"
       
  1407             << false << e;
       
  1408 
       
  1409     /* Multiple name values */
       
  1410     QTest::newRow("prefix first") << "Prefix First"
       
  1411             << true << "Prefix" << "First" << e << e << e
       
  1412             << false << e
       
  1413             << false << e << e << e << e << e
       
  1414             << false << e;
       
  1415     QTest::newRow("prefix middle") << "Prefix Middle"
       
  1416             << true << "Prefix" << e << "Middle" << e << e
       
  1417             << false << e
       
  1418             << false << e << e << e << e << e
       
  1419             << false << e;
       
  1420     QTest::newRow("prefix last") << "Prefix Last"
       
  1421             << true << "Prefix" << e << e << "Last" << e
       
  1422             << false << e
       
  1423             << false << e << e << e << e << e
       
  1424             << false << e;
       
  1425     QTest::newRow("prefix suffix") << "Prefix Suffix"
       
  1426             << true << "Prefix" << e << e << e << "Suffix"
       
  1427             << false << e
       
  1428             << false << e << e << e << e << e
       
  1429             << false << e;
       
  1430     QTest::newRow("first middle") << "First Middle"
       
  1431             << true << e << "First" << "Middle" << e << e
       
  1432             << false << e
       
  1433             << false << e << e << e << e << e
       
  1434             << false << e;
       
  1435     QTest::newRow("first last") << "First Last"
       
  1436             << true << e << "First" << e << "Last" << e
       
  1437             << false << e
       
  1438             << false << e << e << e << e << e
       
  1439             << false << e;
       
  1440     QTest::newRow("first suffix") << "First Suffix"
       
  1441             << true << e << "First" << e << e << "Suffix"
       
  1442             << false << e
       
  1443             << false << e << e << e << e << e
       
  1444             << false << e;
       
  1445     QTest::newRow("middle last") << "Middle Last"
       
  1446             << true << e << e << "Middle" << "Last" << e
       
  1447             << false << e
       
  1448             << false << e << e << e << e << e
       
  1449             << false << e;
       
  1450     QTest::newRow("middle suffix") << "Middle Suffix"
       
  1451             << true << e << e << "Middle" << e << "Suffix"
       
  1452             << false << e
       
  1453             << false << e << e << e << e << e
       
  1454             << false << e;
       
  1455     QTest::newRow("last suffix") << "Last Suffix"
       
  1456             << true << e << e << e << "Last" << "Suffix"
       
  1457             << false << e
       
  1458             << false << e << e << e << e << e
       
  1459             << false << e;
       
  1460 
       
  1461     /* Everything.. */
       
  1462     QTest::newRow("all name") << "Prefix First Middle Last Suffix"
       
  1463             << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
       
  1464             << false << e
       
  1465             << false << e << e << e << e << e
       
  1466             << false << e;
       
  1467     QTest::newRow("all name second") << "Prefix First Middle Last Suffix"
       
  1468             << false << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
       
  1469             << false << e
       
  1470             << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
       
  1471             << false << e;
       
  1472 
       
  1473     /* Org */
       
  1474     QTest::newRow("org") << "Company"
       
  1475             << false << e << e << e << e << e
       
  1476             << true << "Company"
       
  1477             << false << e << e << e << e << e
       
  1478             << false << e;
       
  1479     QTest::newRow("second org") << "Company"
       
  1480             << false << e << e << e << e << e
       
  1481             << false << e
       
  1482             << false << e << e << e << e << e
       
  1483             << true << "Company";
       
  1484 
       
  1485     /* Mix */
       
  1486     QTest::newRow("org and empty name") << "Company"
       
  1487             << true << e << e << e << e << e
       
  1488             << true << "Company"
       
  1489             << false << e << e << e << e << e
       
  1490             << false << e;
       
  1491 
       
  1492     QTest::newRow("name and empty org") << "Prefix First Middle Last Suffix"
       
  1493             << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
       
  1494             << false << e
       
  1495             << false << e << e << e << e << e
       
  1496             << false << e;
       
  1497 
       
  1498     /* names are preferred to orgs */
       
  1499     QTest::newRow("name and org") << "Prefix First Middle Last Suffix"
       
  1500             << true << "Prefix" << "First" << "Middle" << "Last" << "Suffix"
       
  1501             << true << "Company"
       
  1502             << false << e << e << e << e << e
       
  1503             << false << e;
       
  1504 
       
  1505 }
       
  1506 
       
  1507 void tst_QContactManager::nameSynthesis()
       
  1508 {
       
  1509     QContactManager cm("memory");
       
  1510 
       
  1511     QFETCH(QString, expected);
       
  1512 
       
  1513     QFETCH(QString, prefix);
       
  1514     QFETCH(QString, first);
       
  1515     QFETCH(QString, middle);
       
  1516     QFETCH(QString, last);
       
  1517     QFETCH(QString, suffix);
       
  1518     QFETCH(QString, company);
       
  1519 
       
  1520     QFETCH(QString, secondprefix);
       
  1521     QFETCH(QString, secondfirst);
       
  1522     QFETCH(QString, secondmiddle);
       
  1523     QFETCH(QString, secondlast);
       
  1524     QFETCH(QString, secondsuffix);
       
  1525     QFETCH(QString, secondcompany);
       
  1526 
       
  1527     QFETCH(bool, addname);
       
  1528     QFETCH(bool, addname2);
       
  1529     QFETCH(bool, addcompany);
       
  1530     QFETCH(bool, addcompany2);
       
  1531 
       
  1532     /* Test the default name synthesis code */
       
  1533     QContact c;
       
  1534 
       
  1535     QContactName name, name2;
       
  1536     QContactOrganization org, org2;
       
  1537 
       
  1538     name.setPrefix(prefix);
       
  1539     name.setFirstName(first);
       
  1540     name.setMiddleName(middle);
       
  1541     name.setLastName(last);
       
  1542     name.setSuffix(suffix);
       
  1543 
       
  1544     name2.setPrefix(secondprefix);
       
  1545     name2.setFirstName(secondfirst);
       
  1546     name2.setMiddleName(secondmiddle);
       
  1547     name2.setLastName(secondlast);
       
  1548     name2.setSuffix(secondsuffix);
       
  1549 
       
  1550     org.setName(company);
       
  1551     org2.setName(secondcompany);
       
  1552 
       
  1553     if (addname)
       
  1554         c.saveDetail(&name);
       
  1555     if (addname2)
       
  1556         c.saveDetail(&name2);
       
  1557     if (addcompany)
       
  1558         c.saveDetail(&org);
       
  1559     if (addcompany2)
       
  1560         c.saveDetail(&org2);
       
  1561 
       
  1562     // Finally!
       
  1563     QCOMPARE(cm.synthesizedDisplayLabel(c), expected);
       
  1564 }
       
  1565 
       
  1566 void tst_QContactManager::contactValidation()
       
  1567 {
       
  1568     /* Use the memory engine as a reference (validation is not engine specific) */
       
  1569     QScopedPointer<QContactManager> cm(new QContactManager("memory"));
       
  1570     QContact c;
       
  1571 
       
  1572     /*
       
  1573      * Add some definitions for testing:
       
  1574      *
       
  1575      * 1) a unique detail
       
  1576      * 2) a detail with restricted values
       
  1577      * 3) a create only detail
       
  1578      * 4) a unique create only detail
       
  1579      */
       
  1580     QContactDetailDefinition uniqueDef;
       
  1581     QMap<QString, QContactDetailFieldDefinition> fields;
       
  1582     QContactDetailFieldDefinition field;
       
  1583     field.setDataType(QVariant::String);
       
  1584     fields.insert("value", field);
       
  1585 
       
  1586     uniqueDef.setName("UniqueDetail");
       
  1587     uniqueDef.setFields(fields);
       
  1588     uniqueDef.setUnique(true);
       
  1589 
       
  1590     QVERIFY(cm->saveDetailDefinition(uniqueDef));
       
  1591 
       
  1592     QContactDetailDefinition restrictedDef;
       
  1593     restrictedDef.setName("RestrictedDetail");
       
  1594     fields.clear();
       
  1595     field.setAllowableValues(QVariantList() << "One" << "Two" << "Three");
       
  1596     fields.insert("value", field);
       
  1597     restrictedDef.setFields(fields);
       
  1598 
       
  1599     QVERIFY(cm->saveDetailDefinition(restrictedDef));
       
  1600 
       
  1601     // first, test an invalid definition
       
  1602     QContactDetail d1 = QContactDetail("UnknownDefinition");
       
  1603     d1.setValue("test", "test");
       
  1604     c.saveDetail(&d1);
       
  1605     QVERIFY(!cm->saveContact(&c));
       
  1606     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  1607     c.removeDetail(&d1);
       
  1608 
       
  1609     // second, test an invalid uniqueness constraint
       
  1610     QContactDetail d2 = QContactDetail("UniqueDetail");
       
  1611     d2.setValue("value", "test");
       
  1612     c.saveDetail(&d2);
       
  1613 
       
  1614     // One unique should be ok
       
  1615     QVERIFY(cm->saveContact(&c));
       
  1616     QCOMPARE(cm->error(), QContactManager::NoError);
       
  1617 
       
  1618     // Two uniques should not be ok
       
  1619     QContactDetail d3 = QContactDetail("UniqueDetail");
       
  1620     d3.setValue("value", "test2");
       
  1621     c.saveDetail(&d3);
       
  1622     QVERIFY(!cm->saveContact(&c));
       
  1623     QCOMPARE(cm->error(), QContactManager::AlreadyExistsError);
       
  1624     c.removeDetail(&d3);
       
  1625     c.removeDetail(&d2);
       
  1626 
       
  1627     // third, test an invalid field name
       
  1628     QContactDetail d4 = QContactDetail(QContactPhoneNumber::DefinitionName);
       
  1629     d4.setValue("test", "test");
       
  1630     c.saveDetail(&d4);
       
  1631     QVERIFY(!cm->saveContact(&c));
       
  1632     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  1633     c.removeDetail(&d4);
       
  1634 
       
  1635     // fourth, test an invalid field data type
       
  1636     QContactDetail d5 = QContactDetail(QContactPhoneNumber::DefinitionName);
       
  1637     d5.setValue(QContactPhoneNumber::FieldNumber, QDateTime::currentDateTime());
       
  1638     c.saveDetail(&d5);
       
  1639     QVERIFY(!cm->saveContact(&c));
       
  1640     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  1641     c.removeDetail(&d5);
       
  1642 
       
  1643     // fifth, test an invalid field value (not in the allowed list)
       
  1644     QContactDetail d6 = QContactDetail("RestrictedDetail");
       
  1645     d6.setValue("value", "Seven"); // not in One, Two or Three
       
  1646     c.saveDetail(&d6);
       
  1647     QVERIFY(!cm->saveContact(&c));
       
  1648     QCOMPARE(cm->error(), QContactManager::InvalidDetailError);
       
  1649     c.removeDetail(&d6);
       
  1650 
       
  1651     /* Now a valid value */
       
  1652     d6.setValue("value", "Two");
       
  1653     c.saveDetail(&d6);
       
  1654     QVERIFY(cm->saveContact(&c));
       
  1655     QCOMPARE(cm->error(), QContactManager::NoError);
       
  1656     c.removeDetail(&d6);
       
  1657 
       
  1658     // Test a completely valid one.
       
  1659     QContactDetail d7 = QContactDetail(QContactPhoneNumber::DefinitionName);
       
  1660     d7.setValue(QContactPhoneNumber::FieldNumber, "0123456");
       
  1661     c.saveDetail(&d7);
       
  1662     QVERIFY(cm->saveContact(&c));
       
  1663     QCOMPARE(cm->error(), QContactManager::NoError);
       
  1664     c.removeDetail(&d7);
       
  1665 }
       
  1666 
       
  1667 void tst_QContactManager::signalEmission()
       
  1668 {
       
  1669     QFETCH(QString, uri);
       
  1670     QScopedPointer<QContactManager> m1(QContactManager::fromUri(uri));
       
  1671     QScopedPointer<QContactManager> m2(QContactManager::fromUri(uri));
       
  1672 
       
  1673     QVERIFY(m1->hasFeature(QContactManager::Anonymous) ==
       
  1674         m2->hasFeature(QContactManager::Anonymous));
       
  1675 
       
  1676     qRegisterMetaType<QContactLocalId>("QContactLocalId");
       
  1677     qRegisterMetaType<QList<QContactLocalId> >("QList<QContactLocalId>");
       
  1678     QSignalSpy spyCA(m1.data(), SIGNAL(contactsAdded(QList<QContactLocalId>)));
       
  1679     QSignalSpy spyCM(m1.data(), SIGNAL(contactsChanged(QList<QContactLocalId>)));
       
  1680     QSignalSpy spyCR(m1.data(), SIGNAL(contactsRemoved(QList<QContactLocalId>)));
       
  1681 
       
  1682     QList<QVariant> args;
       
  1683     QContact c;
       
  1684     QContactLocalId temp;
       
  1685     QList<QContact> batchAdd;
       
  1686     QList<QContactLocalId> batchRemove;
       
  1687     QList<QContactLocalId> sigids;
       
  1688     int addSigCount = 0; // the expected signal counts.
       
  1689     int modSigCount = 0;
       
  1690     int remSigCount = 0;
       
  1691 
       
  1692     // verify add emits signal added
       
  1693     QContactName nc;
       
  1694     nc.setFirstName("John");
       
  1695     c.saveDetail(&nc);
       
  1696     m1->saveContact(&c);
       
  1697     addSigCount += 1;
       
  1698     QTRY_COMPARE(spyCA.count(), addSigCount);
       
  1699     args = spyCA.takeFirst();
       
  1700     addSigCount -= 1;
       
  1701     QVERIFY(args.count() == 1);
       
  1702     temp = QContactLocalId(args.at(0).value<quint32>());
       
  1703 
       
  1704     // verify save modified emits signal changed
       
  1705     nc.setLastName("Citizen");
       
  1706     c.saveDetail(&nc);
       
  1707     m1->saveContact(&c);
       
  1708     modSigCount += 1;
       
  1709     QTRY_COMPARE(spyCM.count(), modSigCount);
       
  1710     args = spyCM.takeFirst();
       
  1711     modSigCount -= 1;
       
  1712     QVERIFY(args.count() == 1);
       
  1713     QCOMPARE(temp, QContactLocalId(args.at(0).value<quint32>()));
       
  1714 
       
  1715     // verify remove emits signal removed
       
  1716     m1->removeContact(c.id().localId());
       
  1717     remSigCount += 1;
       
  1718     QTRY_COMPARE(spyCR.count(), remSigCount);
       
  1719     args = spyCR.takeFirst();
       
  1720     remSigCount -= 1;
       
  1721     QVERIFY(args.count() == 1);
       
  1722     QCOMPARE(temp, QContactLocalId(args.at(0).value<quint32>()));
       
  1723 
       
  1724     // verify multiple adds works as advertised
       
  1725     QContact c2, c3;
       
  1726     QContactName nc2, nc3;
       
  1727     nc2.setFirstName("Mark");
       
  1728     nc3.setFirstName("Garry");
       
  1729     c2.saveDetail(&nc2);
       
  1730     c3.saveDetail(&nc3);
       
  1731     QVERIFY(!m1->saveContact(&c)); // saving contact with nonexistent id fails
       
  1732     QVERIFY(m1->saveContact(&c2));
       
  1733     addSigCount += 1;
       
  1734     QVERIFY(m1->saveContact(&c3));
       
  1735     addSigCount += 1;
       
  1736     QTRY_COMPARE(spyCM.count(), modSigCount);
       
  1737     QTRY_COMPARE(spyCA.count(), addSigCount);
       
  1738 
       
  1739     // verify multiple modifies works as advertised
       
  1740     nc2.setLastName("M.");
       
  1741     c2.saveDetail(&nc2);
       
  1742     QVERIFY(m1->saveContact(&c2));
       
  1743     modSigCount += 1;
       
  1744     nc2.setPrefix("Mr.");
       
  1745     nc3.setLastName("G.");
       
  1746     c2.saveDetail(&nc2);
       
  1747     c3.saveDetail(&nc3);
       
  1748     QVERIFY(m1->saveContact(&c2));
       
  1749     modSigCount += 1;
       
  1750     QVERIFY(m1->saveContact(&c3));
       
  1751     modSigCount += 1;
       
  1752     QTRY_COMPARE(spyCM.count(), modSigCount);
       
  1753 
       
  1754     // verify multiple removes works as advertised
       
  1755     m1->removeContact(c3.id().localId());
       
  1756     remSigCount += 1;
       
  1757     m1->removeContact(c2.id().localId());
       
  1758     remSigCount += 1;
       
  1759     QTRY_COMPARE(spyCR.count(), remSigCount);
       
  1760 
       
  1761     QVERIFY(!m1->removeContact(c.id().localId())); // not saved.
       
  1762 
       
  1763     /* Now test the batch equivalents */
       
  1764     spyCA.clear();
       
  1765     spyCM.clear();
       
  1766     spyCR.clear();
       
  1767 
       
  1768     /* Batch adds - set ids to zero so add succeeds. */
       
  1769     c.setId(QContactId());
       
  1770     c2.setId(QContactId());
       
  1771     c3.setId(QContactId());
       
  1772     batchAdd << c << c2 << c3;
       
  1773     QMap<int, QContactManager::Error> errorMap;
       
  1774     QVERIFY(m1->saveContacts(&batchAdd, &errorMap));
       
  1775 
       
  1776     QVERIFY(batchAdd.count() == 3);
       
  1777     c = batchAdd.at(0);
       
  1778     c2 = batchAdd.at(1);
       
  1779     c3 = batchAdd.at(2);
       
  1780 
       
  1781     /* We basically loop, processing events, until we've seen an Add signal for each contact */
       
  1782     sigids.clear();
       
  1783 
       
  1784     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()));
       
  1785     QTRY_COMPARE(spyCM.count(), 0);
       
  1786     QTRY_COMPARE(spyCR.count(), 0);
       
  1787 
       
  1788     /* Batch modifies */
       
  1789     QContactDetailDefinition nameDef = m1->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
       
  1790     QContactName modifiedName = c.detail(QContactName::DefinitionName);
       
  1791     setContactName(nameDef, modifiedName, "This is modified number 1");
       
  1792     c.saveDetail(&modifiedName);
       
  1793     modifiedName = c2.detail(QContactName::DefinitionName);
       
  1794     setContactName(nameDef, modifiedName, "This is modified number 2");
       
  1795     c2.saveDetail(&modifiedName);
       
  1796     modifiedName = c3.detail(QContactName::DefinitionName);
       
  1797     setContactName(nameDef, modifiedName, "This is modified number 3");
       
  1798     c3.saveDetail(&modifiedName);
       
  1799 
       
  1800     batchAdd.clear();
       
  1801     batchAdd << c << c2 << c3;
       
  1802     QVERIFY(m1->saveContacts(&batchAdd, &errorMap));
       
  1803 
       
  1804     sigids.clear();
       
  1805     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()));
       
  1806 
       
  1807     /* Batch removes */
       
  1808     batchRemove << c.id().localId() << c2.id().localId() << c3.id().localId();
       
  1809     QVERIFY(m1->removeContacts(&batchRemove, &errorMap));
       
  1810 
       
  1811     sigids.clear();
       
  1812     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()));
       
  1813 
       
  1814     QTRY_COMPARE(spyCA.count(), 0);
       
  1815     QTRY_COMPARE(spyCM.count(), 0);
       
  1816 
       
  1817     /* Now some cross manager testing */
       
  1818     if (!m1->hasFeature(QContactManager::Anonymous)) {
       
  1819         // verify that signals are emitted for modifications made to other managers (same id).
       
  1820         QContactName ncs = c.detail(QContactName::DefinitionName);
       
  1821         ncs.setSuffix("Test");
       
  1822         c.saveDetail(&ncs);
       
  1823         c.setId(QContactId()); // reset id so save can succeed.
       
  1824         m2->saveContact(&c);
       
  1825         ncs.setPrefix("Test2");
       
  1826         c.saveDetail(&ncs);
       
  1827         m2->saveContact(&c);
       
  1828         QTRY_COMPARE(spyCA.count(), 1); // check that we received the update signals.
       
  1829         QTRY_COMPARE(spyCM.count(), 1); // check that we received the update signals.
       
  1830         m2->removeContact(c.localId());
       
  1831         QTRY_COMPARE(spyCR.count(), 1); // check that we received the remove signal.
       
  1832     }
       
  1833 }
       
  1834 
       
  1835 void tst_QContactManager::errorStayingPut()
       
  1836 {
       
  1837     /* Make sure that when we clone a manager, we don't clone the error */
       
  1838     QMap<QString, QString> params;
       
  1839     params.insert("id", "error isolation test");
       
  1840     QContactManager m1("memory",params);
       
  1841 
       
  1842     QVERIFY(m1.error() == QContactManager::NoError);
       
  1843 
       
  1844     /* Remove an invalid contact to get an error */
       
  1845     QVERIFY(m1.removeContact(0) == false);
       
  1846     QVERIFY(m1.error() == QContactManager::DoesNotExistError);
       
  1847 
       
  1848     /* Create a new manager with hopefully the same backend */
       
  1849     QContactManager m2("memory", params);
       
  1850 
       
  1851     QVERIFY(m1.error() == QContactManager::DoesNotExistError);
       
  1852     QVERIFY(m2.error() == QContactManager::NoError);
       
  1853 
       
  1854     /* Cause an error on the other ones and check the first is not affected */
       
  1855     m2.saveContacts(0, 0);
       
  1856     QVERIFY(m1.error() == QContactManager::DoesNotExistError);
       
  1857     QVERIFY(m2.error() == QContactManager::BadArgumentError);
       
  1858 
       
  1859     QContact c;
       
  1860     QContactDetail d("This does not exist and if it does this will break");
       
  1861     d.setValue("Value that also doesn't exist", 5);
       
  1862     c.saveDetail(&d);
       
  1863 
       
  1864     QVERIFY(m1.saveContact(&c) == false);
       
  1865     QVERIFY(m1.error() == QContactManager::InvalidDetailError);
       
  1866     QVERIFY(m2.error() == QContactManager::BadArgumentError);
       
  1867 }
       
  1868 
       
  1869 void tst_QContactManager::detailDefinitions()
       
  1870 {
       
  1871     QFETCH(QString, uri);
       
  1872     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  1873     QMap<QString, QContactDetailDefinition> defs = cm->detailDefinitions();
       
  1874 
       
  1875     /* Validate the existing definitions */
       
  1876 
       
  1877     // Do some sanity checking on the definitions first
       
  1878     if (defs.keys().count() != defs.uniqueKeys().count()) {
       
  1879         qDebug() << "ERROR - duplicate definitions with the same name:";
       
  1880 
       
  1881         QList<QString> defkeys = defs.keys();
       
  1882         foreach(QString uniq, defs.uniqueKeys()) {
       
  1883             if (defkeys.count(uniq) > 1) {
       
  1884                 qDebug() << QString(" %1").arg(uniq).toAscii().constData();
       
  1885                 defkeys.removeAll(uniq);
       
  1886             }
       
  1887         }
       
  1888         QVERIFY(defs.keys().count() == defs.uniqueKeys().count());
       
  1889     }
       
  1890 
       
  1891     foreach(QContactDetailDefinition def, defs.values()) {
       
  1892         QMap<QString, QContactDetailFieldDefinition> fields = def.fields();
       
  1893 
       
  1894         // Again some sanity checking
       
  1895         if (fields.keys().count() != fields.uniqueKeys().count()) {
       
  1896             qDebug() << "ERROR - duplicate fields with the same name:";
       
  1897 
       
  1898             QList<QString> defkeys = fields.keys();
       
  1899             foreach(QString uniq, fields.uniqueKeys()) {
       
  1900                 if (defkeys.count(uniq) > 1) {
       
  1901                     qDebug() << QString(" %2::%1").arg(uniq).arg(def.name()).toAscii().constData();
       
  1902                     defkeys.removeAll(uniq);
       
  1903                 }
       
  1904             }
       
  1905             QVERIFY(fields.keys().count() == fields.uniqueKeys().count());
       
  1906         }
       
  1907 
       
  1908         foreach(QContactDetailFieldDefinition field, def.fields().values()) {
       
  1909             // Sanity check the allowed values
       
  1910             if (field.allowableValues().count() > 0) {
       
  1911                 if (field.dataType() == QVariant::StringList) {
       
  1912                     // We accept QString or QStringList allowed values
       
  1913                     foreach(QVariant var, field.allowableValues()) {
       
  1914                         if (var.type() != QVariant::String && var.type() != QVariant::StringList) {
       
  1915                             QString foo;
       
  1916                             QDebug dbg(&foo);
       
  1917                             dbg.nospace() << var;
       
  1918                             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());
       
  1919                         }
       
  1920                         QVERIFY(var.type() == QVariant::String || var.type() == QVariant::StringList);
       
  1921                     }
       
  1922                 } else if (field.dataType() == QVariant::List || field.dataType() == QVariant::Map || field.dataType() == (QVariant::Type) qMetaTypeId<QVariant>()) {
       
  1923                     // Well, anything goes
       
  1924                 } else {
       
  1925                     // The type of each allowed value must match the data type
       
  1926                     foreach(QVariant var, field.allowableValues()) {
       
  1927                         if (var.type() != field.dataType()) {
       
  1928                             QString foo;
       
  1929                             QDebug dbg(&foo);
       
  1930                             dbg.nospace() << var;
       
  1931                             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());
       
  1932                         }
       
  1933                         QVERIFY(var.type() == field.dataType());
       
  1934                     }
       
  1935                 }
       
  1936             }
       
  1937         }
       
  1938     }
       
  1939 
       
  1940 
       
  1941     /* Try to make a credible definition */
       
  1942     QContactDetailDefinition newDef;
       
  1943     QContactDetailFieldDefinition field;
       
  1944     QMap<QString, QContactDetailFieldDefinition> fields;
       
  1945     field.setDataType(cm->supportedDataTypes().value(0));
       
  1946     fields.insert("New Value", field);
       
  1947     newDef.setName("New Definition");
       
  1948     newDef.setFields(fields);
       
  1949 
       
  1950     /* Updated version of an existing definition */
       
  1951     QContactDetailDefinition updatedDef = defs.begin().value(); // XXX TODO Fixme
       
  1952     fields = updatedDef.fields();
       
  1953     fields.insert("New Value", field);
       
  1954     updatedDef.setFields(fields);
       
  1955 
       
  1956     /* A detail definition with valid allowed values (or really just one) */
       
  1957     QContactDetailDefinition allowedDef = newDef;
       
  1958     field.setAllowableValues(field.allowableValues() << (QVariant(field.dataType())));
       
  1959     fields.clear();
       
  1960     fields.insert("Restricted value", field);
       
  1961     allowedDef.setFields(fields);
       
  1962 
       
  1963     /* Many invalid definitions */
       
  1964     QContactDetailDefinition noIdDef;
       
  1965     noIdDef.setFields(fields);
       
  1966 
       
  1967     QContactDetailDefinition noFieldsDef;
       
  1968     noFieldsDef.setName("No fields");
       
  1969 
       
  1970     QContactDetailDefinition invalidFieldKeyDef;
       
  1971     invalidFieldKeyDef.setName("Invalid field key");
       
  1972     QMap<QString, QContactDetailFieldDefinition> badfields;
       
  1973     badfields.insert(QString(), field);
       
  1974     invalidFieldKeyDef.setFields(badfields);
       
  1975 
       
  1976     QContactDetailDefinition invalidFieldTypeDef;
       
  1977     invalidFieldTypeDef.setName("Invalid field type");
       
  1978     badfields.clear();
       
  1979     QContactDetailFieldDefinition badfield;
       
  1980     badfield.setDataType((QVariant::Type) qMetaTypeId<UnsupportedMetatype>());
       
  1981     badfields.insert("Bad type", badfield);
       
  1982     invalidFieldTypeDef.setFields(badfields);
       
  1983 
       
  1984     QContactDetailDefinition invalidAllowedValuesDef;
       
  1985     invalidAllowedValuesDef.setName("Invalid field allowed values");
       
  1986     badfields.clear();
       
  1987     badfield.setDataType(field.dataType()); // use a supported type
       
  1988     badfield.setAllowableValues(QList<QVariant>() << "String" << 5); // but unsupported value
       
  1989     badfields.insert("Bad allowed", badfield);
       
  1990     invalidAllowedValuesDef.setFields(badfields);
       
  1991 
       
  1992     /* XXX Multiply defined fields.. depends on semantics. */
       
  1993 
       
  1994     if (cm->hasFeature(QContactManager::MutableDefinitions)) {
       
  1995         /* First do some negative testing */
       
  1996 
       
  1997         /* Bad add class */
       
  1998         QVERIFY(cm->saveDetailDefinition(QContactDetailDefinition()) == false);
       
  1999         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2000 
       
  2001         /* Bad remove string */
       
  2002         QVERIFY(cm->removeDetailDefinition(QString()) == false);
       
  2003         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2004 
       
  2005         QVERIFY(cm->saveDetailDefinition(noIdDef) == false);
       
  2006         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2007 
       
  2008         QVERIFY(cm->saveDetailDefinition(noFieldsDef) == false);
       
  2009         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2010 
       
  2011         QVERIFY(cm->saveDetailDefinition(invalidFieldKeyDef) == false);
       
  2012         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2013 
       
  2014         QVERIFY(cm->saveDetailDefinition(invalidFieldTypeDef) == false);
       
  2015         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2016 
       
  2017         QVERIFY(cm->saveDetailDefinition(invalidAllowedValuesDef) == false);
       
  2018         QVERIFY(cm->error() == QContactManager::BadArgumentError);
       
  2019 
       
  2020         /* Check that our new definition doesn't already exist */
       
  2021         QVERIFY(cm->detailDefinition(newDef.name()).isEmpty());
       
  2022         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2023 
       
  2024         QVERIFY(cm->removeDetailDefinition(newDef.name()) == false);
       
  2025         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2026 
       
  2027         /* Add a new definition */
       
  2028         QVERIFY(cm->saveDetailDefinition(newDef) == true);
       
  2029         QVERIFY(cm->error() == QContactManager::NoError);
       
  2030 
       
  2031         /* Now retrieve it */
       
  2032         QContactDetailDefinition def = cm->detailDefinition(newDef.name());
       
  2033         QVERIFY(def == newDef);
       
  2034 
       
  2035         /* Update it */
       
  2036         QMap<QString, QContactDetailFieldDefinition> newFields = def.fields();
       
  2037         newFields.insert("Another new value", field);
       
  2038         newDef.setFields(newFields);
       
  2039 
       
  2040         QVERIFY(cm->saveDetailDefinition(newDef) == true);
       
  2041         QVERIFY(cm->error() == QContactManager::NoError);
       
  2042 
       
  2043         QVERIFY(cm->detailDefinition(newDef.name()) == newDef);
       
  2044 
       
  2045         /* Remove it */
       
  2046         QVERIFY(cm->removeDetailDefinition(newDef.name()) == true);
       
  2047         QVERIFY(cm->error() == QContactManager::NoError);
       
  2048 
       
  2049         /* and make sure it does not exist any more */
       
  2050         QVERIFY(cm->detailDefinition(newDef.name()) == QContactDetailDefinition());
       
  2051         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2052 
       
  2053         /* Add the other good one */
       
  2054         QVERIFY(cm->saveDetailDefinition(allowedDef) == true);
       
  2055         QVERIFY(cm->error() == QContactManager::NoError);
       
  2056 
       
  2057         QVERIFY(allowedDef == cm->detailDefinition(allowedDef.name()));
       
  2058 
       
  2059         /* and remove it */
       
  2060         QVERIFY(cm->removeDetailDefinition(allowedDef.name()) == true);
       
  2061         QVERIFY(cm->detailDefinition(allowedDef.name()) == QContactDetailDefinition());
       
  2062         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2063 
       
  2064     } else {
       
  2065         /* Bad add class */
       
  2066         QVERIFY(cm->saveDetailDefinition(QContactDetailDefinition()) == false);
       
  2067         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2068 
       
  2069         /* Make sure we can't add/remove/modify detail definitions */
       
  2070         QVERIFY(cm->removeDetailDefinition(QString()) == false);
       
  2071         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2072 
       
  2073         /* Try updating an existing definition */
       
  2074         QVERIFY(cm->saveDetailDefinition(updatedDef) == false);
       
  2075         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2076 
       
  2077         /* Try removing an existing definition */
       
  2078         QVERIFY(cm->removeDetailDefinition(updatedDef.name()) == false);
       
  2079         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2080     }
       
  2081 }
       
  2082 
       
  2083 void tst_QContactManager::displayName()
       
  2084 {
       
  2085     QFETCH(QString, uri);
       
  2086     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2087 
       
  2088     /*
       
  2089      * Very similar to the tst_QContact functions, except we test
       
  2090      * saving and retrieving contacts updates the display label
       
  2091      */
       
  2092 
       
  2093     /* Try to make this a bit more consistent by using a single name */
       
  2094     QContact d;
       
  2095     QContactName name;
       
  2096     setContactName(cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact), name, "Wesley");
       
  2097 
       
  2098     QVERIFY(d.displayLabel().isEmpty());
       
  2099     QVERIFY(d.saveDetail(&name));
       
  2100 
       
  2101     QString synth = cm->synthesizedDisplayLabel(d);
       
  2102 
       
  2103     /*
       
  2104      * The display label is not updated until you save the contact.
       
  2105      */
       
  2106     QVERIFY(cm->saveContact(&d));
       
  2107     d = cm->contact(d.id().localId());
       
  2108     QVERIFY(!d.isEmpty());
       
  2109     QCOMPARE(d.displayLabel(), synth);
       
  2110 
       
  2111     /* Remove the detail via removeDetail */
       
  2112     QContactDisplayLabel old;
       
  2113     int count = d.details().count();
       
  2114     QVERIFY(!d.removeDetail(&old)); // should fail.
       
  2115     QVERIFY(d.isEmpty() == false);
       
  2116     QVERIFY(d.details().count() == count); // it should not be removed!
       
  2117 
       
  2118     /* Save the contact again */
       
  2119     QVERIFY(cm->saveContact(&d));
       
  2120     d = cm->contact(d.id().localId());
       
  2121     QVERIFY(!d.isEmpty());
       
  2122 
       
  2123     /* Make sure the label is still the synth version */
       
  2124     QCOMPARE(d.displayLabel(), synth);
       
  2125 
       
  2126     /* And delete the contact */
       
  2127     QVERIFY(cm->removeContact(d.id().localId()));
       
  2128 }
       
  2129 
       
  2130 void tst_QContactManager::actionPreferences()
       
  2131 {
       
  2132     QFETCH(QString, uri);
       
  2133     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2134 
       
  2135     // early out if the manager doesn't support action preference saving.
       
  2136     if (!cm->hasFeature(QContactManager::ActionPreferences)) {
       
  2137         QSKIP("Manager does not support action preferences", SkipSingle);
       
  2138     }
       
  2139 
       
  2140     // create a sample contact
       
  2141     QContactAvatar a;
       
  2142     a.setAvatar("test.png");
       
  2143     QContactPhoneNumber p1;
       
  2144     p1.setNumber("12345");
       
  2145     QContactPhoneNumber p2;
       
  2146     p2.setNumber("34567");
       
  2147     QContactPhoneNumber p3;
       
  2148     p3.setNumber("56789");
       
  2149     QContactUrl u;
       
  2150     u.setUrl("http://test.nokia.com");
       
  2151     QContactName n;
       
  2152     setContactName(cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact), n, "TestContact");
       
  2153 
       
  2154     QContact c;
       
  2155     c.saveDetail(&a);
       
  2156     c.saveDetail(&p1);
       
  2157     c.saveDetail(&p2);
       
  2158     c.saveDetail(&p3);
       
  2159     c.saveDetail(&u);
       
  2160     c.saveDetail(&n);
       
  2161 
       
  2162     // set a preference for dialing a particular saved phonenumber.
       
  2163     c.setPreferredDetail("Dial", p2);
       
  2164 
       
  2165     QVERIFY(cm->saveContact(&c));          // save the contact
       
  2166     QContact loaded = cm->contact(c.id().localId()); // reload the contact
       
  2167 
       
  2168     // test that the preference was saved correctly.
       
  2169     QContactDetail pref = loaded.preferredDetail("Dial");
       
  2170     QVERIFY(pref == p2);
       
  2171 
       
  2172     cm->removeContact(c.id().localId());
       
  2173 }
       
  2174 
       
  2175 void tst_QContactManager::changeSet()
       
  2176 {
       
  2177     QContactLocalId id(1);
       
  2178 
       
  2179     QContactChangeSet cs;
       
  2180     QVERIFY(cs.addedContacts().isEmpty());
       
  2181     QVERIFY(cs.changedContacts().isEmpty());
       
  2182     QVERIFY(cs.removedContacts().isEmpty());
       
  2183 
       
  2184     cs.addedContacts().insert(id);
       
  2185     QVERIFY(!cs.addedContacts().isEmpty());
       
  2186     QVERIFY(cs.changedContacts().isEmpty());
       
  2187     QVERIFY(cs.removedContacts().isEmpty());
       
  2188     QVERIFY(cs.addedContacts().contains(id));
       
  2189 
       
  2190     cs.changedContacts().insert(id);
       
  2191     cs.changedContacts().insert(id);
       
  2192     QVERIFY(cs.changedContacts().size() == 1); // set, should only be added once.
       
  2193     QVERIFY(!cs.addedContacts().isEmpty());
       
  2194     QVERIFY(!cs.changedContacts().isEmpty());
       
  2195     QVERIFY(cs.removedContacts().isEmpty());
       
  2196     QVERIFY(cs.changedContacts().contains(id));
       
  2197 
       
  2198     QVERIFY(cs.dataChanged() == false);
       
  2199     QContactChangeSet cs2;
       
  2200     cs2 = cs;
       
  2201     QVERIFY(cs.addedContacts() == cs2.addedContacts());
       
  2202     cs.emitSignals(0);
       
  2203 
       
  2204     cs2.clear();
       
  2205     QVERIFY(cs.addedContacts() != cs2.addedContacts());
       
  2206 
       
  2207     QContactChangeSet cs3(cs2);
       
  2208     QVERIFY(cs.addedContacts() != cs3.addedContacts());
       
  2209     QVERIFY(cs2.addedContacts() == cs3.addedContacts());
       
  2210 
       
  2211     cs.setDataChanged(true);
       
  2212     QVERIFY(cs.dataChanged() == true);
       
  2213     QVERIFY(cs.dataChanged() != cs2.dataChanged());
       
  2214     QVERIFY(cs.dataChanged() != cs3.dataChanged());
       
  2215     cs.emitSignals(0);
       
  2216 
       
  2217     cs.addedRelationshipsContacts().insert(id);
       
  2218     cs.emitSignals(0);
       
  2219     cs.removedRelationshipsContacts().insert(id);
       
  2220     cs.emitSignals(0);
       
  2221 
       
  2222     cs.oldAndNewSelfContactId() = QPair<QContactLocalId, QContactLocalId>(QContactLocalId(0), id);
       
  2223     cs2 = cs;
       
  2224     QVERIFY(cs2.addedRelationshipsContacts() == cs.addedRelationshipsContacts());
       
  2225     QVERIFY(cs2.removedRelationshipsContacts() == cs.removedRelationshipsContacts());
       
  2226     QVERIFY(cs2.oldAndNewSelfContactId() == cs.oldAndNewSelfContactId());
       
  2227     cs.emitSignals(0);
       
  2228     cs.oldAndNewSelfContactId() = QPair<QContactLocalId, QContactLocalId>(id, QContactLocalId(0));
       
  2229     QVERIFY(cs2.oldAndNewSelfContactId() != cs.oldAndNewSelfContactId());
       
  2230     cs.setDataChanged(true);
       
  2231     cs.emitSignals(0);
       
  2232 }
       
  2233 
       
  2234 void tst_QContactManager::selfContactId()
       
  2235 {
       
  2236     QFETCH(QString, uri);
       
  2237     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2238 
       
  2239     // early out if the manager doesn't support self contact id saving
       
  2240     QContactLocalId selfContact = cm->selfContactId();
       
  2241     if (!cm->hasFeature(QContactManager::SelfContact)) {
       
  2242         // ensure that the error codes / return values are meaningful failures.
       
  2243         QVERIFY(cm->error() == QContactManager::DoesNotExistError);
       
  2244         QVERIFY(!cm->setSelfContactId(QContactLocalId(123)));
       
  2245         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2246         QSKIP("Manager does not support the concept of a self-contact", SkipSingle);
       
  2247     }
       
  2248 
       
  2249     // create a new "self" contact and retrieve its Id
       
  2250     QVERIFY(cm->error() == QContactManager::NoError || cm->error() == QContactManager::DoesNotExistError);
       
  2251     QContact self;
       
  2252     QContactPhoneNumber selfPhn;
       
  2253     selfPhn.setNumber("12345");
       
  2254     self.saveDetail(&selfPhn);
       
  2255     if (!cm->saveContact(&self)) {
       
  2256         QSKIP("Unable to save the generated self contact", SkipSingle);
       
  2257     }
       
  2258     QContactLocalId newSelfContact = self.localId();
       
  2259 
       
  2260     // Setup signal spy
       
  2261     qRegisterMetaType<QContactLocalId>("QContactLocalId");
       
  2262     QSignalSpy spy(cm.data(), SIGNAL(selfContactIdChanged(QContactLocalId,QContactLocalId)));
       
  2263 
       
  2264     // Set new self contact
       
  2265     QVERIFY(cm->setSelfContactId(newSelfContact));
       
  2266     QVERIFY(cm->error() == QContactManager::NoError);
       
  2267     QTRY_VERIFY(spy.count() == 1);
       
  2268     QVERIFY(spy.at(0).count() == 2);
       
  2269     // note: for some reason qvariant_cast<QContactLocalId>(spy.at(0).at(0)) returns always zero
       
  2270     // because the type is not recognized. Hence the ugly casting below.
       
  2271     QVERIFY(*((const QContactLocalId*) spy.at(0).at(0).constData()) == selfContact);
       
  2272     QVERIFY(*((const QContactLocalId*) spy.at(0).at(1).constData()) == newSelfContact);
       
  2273     QVERIFY(cm->selfContactId() == newSelfContact);
       
  2274 
       
  2275     // Remove self contact
       
  2276     if(!cm->removeContact(self.localId())) {
       
  2277         QSKIP("Unable to remove self contact", SkipSingle);
       
  2278     }
       
  2279     QTRY_VERIFY(spy.count() == 2);
       
  2280     QVERIFY(spy.at(1).count() == 2);
       
  2281     QVERIFY(*((const QContactLocalId*) spy.at(1).at(0).constData()) == newSelfContact);
       
  2282     QVERIFY(*((const QContactLocalId*) spy.at(1).at(1).constData()) == QContactLocalId(0));
       
  2283     QVERIFY(cm->selfContactId() == QContactLocalId(0)); // ensure reset after removed.
       
  2284 
       
  2285     // reset to original state.
       
  2286     cm->setSelfContactId(selfContact);
       
  2287 }
       
  2288 
       
  2289 QList<QContactDetail> tst_QContactManager::removeAllDefaultDetails(const QList<QContactDetail>& details)
       
  2290 {
       
  2291     QList<QContactDetail> newlist;
       
  2292     foreach (const QContactDetail d, details) {
       
  2293         if (d.definitionName() != QContactDisplayLabel::DefinitionName
       
  2294                 && d.definitionName() != QContactType::DefinitionName
       
  2295                 && d.definitionName() != QContactTimestamp::DefinitionName) {
       
  2296             newlist << d;
       
  2297         }
       
  2298     }
       
  2299     return newlist;
       
  2300 }
       
  2301 
       
  2302 void tst_QContactManager::detailOrders()
       
  2303 {
       
  2304     QFETCH(QString, uri);
       
  2305     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2306 
       
  2307     if (!cm->hasFeature(QContactManager::DetailOrdering))
       
  2308         QSKIP("Skipping: This manager does not support detail ordering!", SkipSingle);
       
  2309 
       
  2310     QContact a;
       
  2311     //phone numbers
       
  2312 
       
  2313     QContactDetailDefinition d = cm->detailDefinition(QContactPhoneNumber::DefinitionName, QContactType::TypeContact);
       
  2314     QContactDetailFieldDefinition supportedContexts = d.fields().value(QContactDetail::FieldContext);
       
  2315     QString contextOther = QContactDetail::ContextOther;
       
  2316     if (!supportedContexts.allowableValues().contains(contextOther)) {
       
  2317         contextOther = QString();
       
  2318     }    
       
  2319     
       
  2320     QContactPhoneNumber number1, number2, number3;
       
  2321     
       
  2322     number1.setNumber("11111111");
       
  2323     number1.setContexts(QContactPhoneNumber::ContextHome);
       
  2324 
       
  2325     number2.setNumber("22222222");
       
  2326     number2.setContexts(QContactPhoneNumber::ContextWork);
       
  2327 
       
  2328     number3.setNumber("33333333");
       
  2329     if (!contextOther.isEmpty())
       
  2330         number3.setContexts(contextOther);
       
  2331 
       
  2332     a.saveDetail(&number1);
       
  2333     a.saveDetail(&number2);
       
  2334     a.saveDetail(&number3);
       
  2335 
       
  2336     QVERIFY(cm->saveContact(&a));
       
  2337     a = cm->contact(a.id().localId());
       
  2338     
       
  2339     QList<QContactDetail> details = a.details(QContactPhoneNumber::DefinitionName);
       
  2340     QVERIFY(details.count() == 3);
       
  2341     QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
       
  2342     QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextWork);
       
  2343     QVERIFY(details.at(2).value(QContactPhoneNumber::FieldContext) == contextOther);
       
  2344     
       
  2345     QVERIFY(a.removeDetail(&number2));
       
  2346     QVERIFY(cm->saveContact(&a));
       
  2347     a = cm->contact(a.id().localId());
       
  2348     details = a.details(QContactPhoneNumber::DefinitionName);
       
  2349     QVERIFY(details.count() == 2);
       
  2350     QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
       
  2351     QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == contextOther);
       
  2352 
       
  2353     a.saveDetail(&number2);
       
  2354     QVERIFY(cm->saveContact(&a));
       
  2355     a = cm->contact(a.id().localId());
       
  2356     
       
  2357     details = a.details(QContactPhoneNumber::DefinitionName);
       
  2358     QVERIFY(details.count() == 3);
       
  2359     QVERIFY(details.at(0).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextHome);
       
  2360     QVERIFY(details.at(1).value(QContactPhoneNumber::FieldContext) == contextOther);
       
  2361     QVERIFY(details.at(2).value(QContactPhoneNumber::FieldContext) == QContactPhoneNumber::ContextWork);
       
  2362 
       
  2363     //addresses
       
  2364     
       
  2365     d = cm->detailDefinition(QContactAddress::DefinitionName, QContactType::TypeContact);
       
  2366     supportedContexts = d.fields().value(QContactDetail::FieldContext);
       
  2367     contextOther = QString(QLatin1String(QContactDetail::ContextOther));
       
  2368     if (!supportedContexts.allowableValues().contains(contextOther)) {
       
  2369         contextOther = QString();
       
  2370     }     
       
  2371     
       
  2372     QContactAddress address1, address2, address3;
       
  2373     
       
  2374     address1.setStreet("Brandl St");
       
  2375     address1.setRegion("Brisbane");
       
  2376     address3 = address2 = address1;
       
  2377 
       
  2378     address1.setContexts(QContactAddress::ContextHome);
       
  2379     address2.setContexts(QContactAddress::ContextWork);
       
  2380     if (!contextOther.isEmpty())
       
  2381         address3.setContexts(contextOther);
       
  2382 
       
  2383     a.saveDetail(&address1);
       
  2384     a.saveDetail(&address2);
       
  2385     a.saveDetail(&address3);
       
  2386 
       
  2387     QVERIFY(cm->saveContact(&a));
       
  2388     a = cm->contact(a.id().localId());
       
  2389     
       
  2390     details = a.details(QContactAddress::DefinitionName);
       
  2391     QVERIFY(details.count() == 3);
       
  2392     
       
  2393     QVERIFY(details.at(0).value(QContactAddress::FieldContext) == QContactAddress::ContextHome);
       
  2394     QVERIFY(details.at(1).value(QContactAddress::FieldContext) == QContactAddress::ContextWork);
       
  2395     QVERIFY(details.at(2).value(QContactAddress::FieldContext) == contextOther);
       
  2396 
       
  2397     QVERIFY(a.removeDetail(&address2));
       
  2398     QVERIFY(cm->saveContact(&a));
       
  2399     a = cm->contact(a.id().localId());
       
  2400     details = a.details(QContactAddress::DefinitionName);
       
  2401     QVERIFY(details.count() == 2);
       
  2402     QVERIFY(details.at(0).value(QContactAddress::FieldContext) == QContactAddress::ContextHome);
       
  2403     QVERIFY(details.at(1).value(QContactAddress::FieldContext) == contextOther);
       
  2404 
       
  2405     a.saveDetail(&address2);
       
  2406     QVERIFY(cm->saveContact(&a));
       
  2407     a = cm->contact(a.id().localId());
       
  2408     
       
  2409     details = a.details(QContactAddress::DefinitionName);
       
  2410     QVERIFY(details.count() == 3);
       
  2411     QVERIFY(details.at(0).value(QContactAddress::FieldContext) == QContactAddress::ContextHome);
       
  2412     QVERIFY(details.at(1).value(QContactAddress::FieldContext) == contextOther);
       
  2413     QVERIFY(details.at(2).value(QContactAddress::FieldContext) == QContactAddress::ContextWork);
       
  2414 
       
  2415 
       
  2416     //emails
       
  2417     d = cm->detailDefinition(QContactEmailAddress::DefinitionName, QContactType::TypeContact);
       
  2418     supportedContexts = d.fields().value(QContactDetail::FieldContext);
       
  2419     contextOther = QString(QLatin1String(QContactDetail::ContextOther));
       
  2420     if (!supportedContexts.allowableValues().contains(contextOther)) {
       
  2421         contextOther = QString();
       
  2422     }      
       
  2423     
       
  2424     QContactEmailAddress email1, email2, email3;
       
  2425 
       
  2426     email1.setEmailAddress("aaron@example.com");
       
  2427     email3 = email2 = email1;
       
  2428     email1.setContexts(QContactEmailAddress::ContextHome);
       
  2429     email2.setContexts(QContactEmailAddress::ContextWork);
       
  2430     if (!contextOther.isEmpty())
       
  2431         email3.setContexts(contextOther);
       
  2432 
       
  2433     a.saveDetail(&email1);
       
  2434     a.saveDetail(&email2);
       
  2435     a.saveDetail(&email3);
       
  2436 
       
  2437     QVERIFY(cm->saveContact(&a));
       
  2438     a = cm->contact(a.id().localId());
       
  2439     
       
  2440     details = a.details(QContactEmailAddress::DefinitionName);
       
  2441     QVERIFY(details.count() == 3);
       
  2442     
       
  2443     QVERIFY(details.at(0).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextHome);
       
  2444     QVERIFY(details.at(1).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextWork);
       
  2445     QVERIFY(details.at(2).value(QContactEmailAddress::FieldContext) == contextOther);
       
  2446 
       
  2447     QVERIFY(a.removeDetail(&email2));
       
  2448     QVERIFY(cm->saveContact(&a));
       
  2449     a = cm->contact(a.id().localId());
       
  2450     details = a.details(QContactEmailAddress::DefinitionName);
       
  2451     QVERIFY(details.count() == 2);
       
  2452     QVERIFY(details.at(0).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextHome);
       
  2453     QVERIFY(details.at(1).value(QContactEmailAddress::FieldContext) == contextOther);
       
  2454 
       
  2455     a.saveDetail(&email2);
       
  2456     QVERIFY(cm->saveContact(&a));
       
  2457     a = cm->contact(a.id().localId());
       
  2458     
       
  2459     details = a.details(QContactEmailAddress::DefinitionName);
       
  2460     QVERIFY(details.count() == 3);
       
  2461     QVERIFY(details.at(0).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextHome);
       
  2462     QVERIFY(details.at(1).value(QContactEmailAddress::FieldContext) == contextOther);
       
  2463     QVERIFY(details.at(2).value(QContactEmailAddress::FieldContext) == QContactEmailAddress::ContextWork);
       
  2464 
       
  2465     QVERIFY(cm->removeContact(a.id().localId()));
       
  2466     QVERIFY(cm->error() == QContactManager::NoError);
       
  2467 }
       
  2468 
       
  2469 void tst_QContactManager::relationships()
       
  2470 {
       
  2471     QFETCH(QString, uri);
       
  2472     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2473 
       
  2474     // save some contacts
       
  2475     QContact source;
       
  2476     QContact dest1, dest2, dest3, dest4;
       
  2477     QContactPhoneNumber n1, n2, n3, n4;
       
  2478     n1.setNumber("1");
       
  2479     n2.setNumber("2");
       
  2480     n3.setNumber("3");
       
  2481     n4.setNumber("4");
       
  2482 
       
  2483     dest1.saveDetail(&n1);
       
  2484     dest2.saveDetail(&n2);
       
  2485     dest3.saveDetail(&n3);
       
  2486     dest4.saveDetail(&n3);
       
  2487 
       
  2488     cm->saveContact(&source);
       
  2489     cm->saveContact(&dest1);
       
  2490     cm->saveContact(&dest2);
       
  2491     cm->saveContact(&dest3);
       
  2492     cm->saveContact(&dest4);
       
  2493 
       
  2494     // check if manager supports relationships
       
  2495     if (!cm->hasFeature(QContactManager::Relationships)) {
       
  2496         // ensure that the operations all fail as required.
       
  2497         QContactRelationship r1, r2, r3;
       
  2498         r1.setFirst(source.id());
       
  2499         r1.setSecond(dest1.id());
       
  2500         r1.setRelationshipType(QContactRelationship::HasManager);
       
  2501         r2.setFirst(source.id());
       
  2502         r2.setSecond(dest2.id());
       
  2503         r2.setRelationshipType(QContactRelationship::HasManager);
       
  2504         r3.setFirst(source.id());
       
  2505         r3.setSecond(dest3.id());
       
  2506         r3.setRelationshipType(QContactRelationship::HasManager);
       
  2507 
       
  2508         QList<QContactRelationship> batchList;
       
  2509         batchList << r2 << r3;
       
  2510 
       
  2511         // test save and remove
       
  2512         QVERIFY(!cm->saveRelationship(&r1));
       
  2513         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2514         QVERIFY(!cm->removeRelationship(r1));
       
  2515         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2516         QVERIFY(cm->saveRelationships(&batchList).isEmpty());
       
  2517         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2518         QVERIFY(cm->removeRelationships(batchList).isEmpty());
       
  2519         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2520 
       
  2521         // test retrieval
       
  2522         QList<QContactRelationship> retrieveList;
       
  2523         retrieveList = cm->relationships(source.id(), QContactRelationshipFilter::First);
       
  2524         QVERIFY(retrieveList.isEmpty());
       
  2525         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2526         retrieveList = cm->relationships(source.id(), QContactRelationshipFilter::Second);
       
  2527         QVERIFY(retrieveList.isEmpty());
       
  2528         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2529         retrieveList = cm->relationships(source.id()); // Either
       
  2530         QVERIFY(retrieveList.isEmpty());
       
  2531         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2532 
       
  2533 
       
  2534         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id(), QContactRelationshipFilter::First);
       
  2535         QVERIFY(retrieveList.isEmpty());
       
  2536         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2537         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id(), QContactRelationshipFilter::Second);
       
  2538         QVERIFY(retrieveList.isEmpty());
       
  2539         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2540         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id(), QContactRelationshipFilter::Either);
       
  2541         QVERIFY(retrieveList.isEmpty());
       
  2542         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2543         retrieveList = cm->relationships(QContactRelationship::HasManager, source.id());
       
  2544         QVERIFY(retrieveList.isEmpty());
       
  2545         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2546         retrieveList = cm->relationships(QContactRelationship::HasManager);
       
  2547         QVERIFY(retrieveList.isEmpty());
       
  2548         QVERIFY(cm->error() == QContactManager::NotSupportedError);
       
  2549         return;
       
  2550     }
       
  2551     
       
  2552     // Get supported relationship types
       
  2553     QStringList availableRelationshipTypes = cm->supportedRelationshipTypes();
       
  2554     
       
  2555     // Check arbitary relationship support
       
  2556     if (cm->hasFeature(QContactManager::ArbitraryRelationshipTypes)) {
       
  2557         // add some arbitary type for testing
       
  2558         if (availableRelationshipTypes.count())
       
  2559             availableRelationshipTypes.insert(0, "test-arbitrary-relationship-type");
       
  2560         else {
       
  2561             availableRelationshipTypes.append("test-arbitrary-relationship-type");
       
  2562             availableRelationshipTypes.append(QContactRelationship::HasMember);
       
  2563             availableRelationshipTypes.append(QContactRelationship::HasAssistant);
       
  2564         }
       
  2565     }
       
  2566     
       
  2567     // Verify that we have relationship types. If there are none then the manager
       
  2568     // is saying it supports relationships but does not actually implement any 
       
  2569     // relationship type.
       
  2570     QVERIFY(!availableRelationshipTypes.isEmpty());
       
  2571     
       
  2572     // Some backends (eg. symbian) require that when type is "HasMember" 
       
  2573     // then "first" contact must be a group.
       
  2574     if (availableRelationshipTypes.at(0) == QContactRelationship::HasMember) {
       
  2575         cm->removeContact(source.localId());
       
  2576         source.setId(QContactId());
       
  2577         source.setType(QContactType::TypeGroup);
       
  2578         cm->saveContact(&source);
       
  2579     }
       
  2580 
       
  2581     // Create some common contact id's for testing
       
  2582     QContactId dest1Uri = dest1.id();
       
  2583     QContactId dest1EmptyUri;
       
  2584     dest1EmptyUri.setManagerUri(QString());
       
  2585     dest1EmptyUri.setLocalId(dest1.id().localId());
       
  2586     QContactId dest2Uri = dest2.id();
       
  2587     QContactId dest3Uri = dest3.id();
       
  2588     QContactId dest3EmptyUri;
       
  2589     dest3EmptyUri.setManagerUri(QString());
       
  2590     dest3EmptyUri.setLocalId(dest3.id().localId());
       
  2591 
       
  2592     // build our relationship - source is the manager all of the dest contacts.
       
  2593     QContactRelationship customRelationshipOne;
       
  2594     customRelationshipOne.setFirst(source.id());
       
  2595     customRelationshipOne.setSecond(dest1EmptyUri);
       
  2596     customRelationshipOne.setRelationshipType(availableRelationshipTypes.at(0));
       
  2597     QCOMPARE(customRelationshipOne.first(), source.id());
       
  2598     QCOMPARE(customRelationshipOne.second(), dest1EmptyUri);
       
  2599     QVERIFY(customRelationshipOne.relationshipType() == availableRelationshipTypes.at(0));
       
  2600 
       
  2601     // save the relationship
       
  2602     int managerRelationshipsCount = cm->relationships(availableRelationshipTypes.at(0)).count();
       
  2603     QVERIFY(cm->saveRelationship(&customRelationshipOne));
       
  2604     // test that the empty manager URI has been updated.
       
  2605     QCOMPARE(customRelationshipOne.second(), dest1Uri); // updated with correct manager URI
       
  2606 
       
  2607     // test our accessors.
       
  2608     QCOMPARE(cm->relationships(availableRelationshipTypes.at(0)).count(), (managerRelationshipsCount + 1));
       
  2609     QVERIFY(cm->relationships(availableRelationshipTypes.at(0), source.id()).count() == 1);
       
  2610 
       
  2611     // remove the dest1 contact, relationship should be removed.
       
  2612     cm->removeContact(dest1.localId());
       
  2613     QCOMPARE(cm->relationships(availableRelationshipTypes.at(0), dest1Uri, QContactRelationshipFilter::Second).count(), 0);
       
  2614 
       
  2615     // modify and save the relationship
       
  2616     customRelationshipOne.setSecond(dest2Uri);
       
  2617     QVERIFY(cm->saveRelationship(&customRelationshipOne));
       
  2618 
       
  2619     // attempt to save the relationship again.  XXX TODO: what should the result be?  currently succeeds (overwrites)
       
  2620     int relationshipsCount = cm->relationships().count();
       
  2621     QVERIFY(cm->saveRelationship(&customRelationshipOne));    // succeeds, but just overwrites
       
  2622     QCOMPARE(relationshipsCount, cm->relationships().count()); // shouldn't change; save should have overwritten.
       
  2623 
       
  2624     // removing the source contact should result in removal of the relationship.
       
  2625     QVERIFY(cm->removeContact(source.id().localId()));
       
  2626     QCOMPARE(cm->relationships().count(), relationshipsCount - 1); // the relationship should have been removed.
       
  2627 
       
  2628     // now ensure that qcontact relationship caching works as required - perhaps this should be in tst_QContact?
       
  2629     source.setId(QContactId());         // reset id so we can resave
       
  2630     QVERIFY(cm->saveContact(&source));  // save source again.
       
  2631     customRelationshipOne.setFirst(source.id());
       
  2632     customRelationshipOne.setSecond(dest2.id());
       
  2633     QVERIFY(cm->saveRelationship(&customRelationshipOne));
       
  2634 
       
  2635     // Add a second relationship
       
  2636     QContactRelationship customRelationshipTwo;
       
  2637     customRelationshipTwo.setFirst(source.id());
       
  2638     if (availableRelationshipTypes.count() > 1)
       
  2639         customRelationshipTwo.setRelationshipType(availableRelationshipTypes.at(1));
       
  2640     else
       
  2641         customRelationshipTwo.setRelationshipType(availableRelationshipTypes.at(0));
       
  2642     customRelationshipTwo.setSecond(dest3.id());
       
  2643     QVERIFY(cm->saveRelationship(&customRelationshipTwo));
       
  2644 
       
  2645     // currently, the contacts are "stale" - no cached relationships
       
  2646     QVERIFY(dest3.relatedContacts().isEmpty());
       
  2647     QVERIFY(dest3.relationships().isEmpty());
       
  2648     QVERIFY(dest2.relatedContacts().isEmpty());
       
  2649     QVERIFY(dest2.relationships().isEmpty());
       
  2650 
       
  2651     // now refresh the contacts
       
  2652     dest3 = cm->contact(dest3.localId());
       
  2653     dest2 = cm->contact(dest2.localId());
       
  2654     source = cm->contact(source.localId());
       
  2655 
       
  2656     // and test again.
       
  2657     QVERIFY(source.relatedContacts(QString(), QContactRelationshipFilter::First).isEmpty()); // source is always the first, so this should be empty.
       
  2658     QVERIFY(source.relatedContacts(QString(), QContactRelationshipFilter::Second).contains(dest2.id()));
       
  2659     QVERIFY(source.relatedContacts(QString(), QContactRelationshipFilter::Either).contains(dest2.id()));
       
  2660     QVERIFY(source.relatedContacts(QString(), QContactRelationshipFilter::Second).contains(dest3.id()));
       
  2661     QVERIFY(source.relatedContacts(QString(), QContactRelationshipFilter::Either).contains(dest3.id()));
       
  2662     QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationshipFilter::Second).contains(dest2.id()));
       
  2663     QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationshipFilter::First).isEmpty());
       
  2664 
       
  2665     QVERIFY(dest2.relatedContacts().contains(source.id()));
       
  2666     QVERIFY(dest2.relationships().contains(customRelationshipOne));
       
  2667     QVERIFY(!dest2.relationships().contains(customRelationshipTwo));
       
  2668     QVERIFY(dest2.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipOne));
       
  2669     QVERIFY(!dest2.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipTwo));
       
  2670     QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0)).contains(source.id()));
       
  2671     QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationshipFilter::First).contains(source.id()));
       
  2672     QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationshipFilter::Second).isEmpty());
       
  2673     QVERIFY(!dest2.relatedContacts(availableRelationshipTypes.at(0), QContactRelationshipFilter::Second).contains(source.id()));
       
  2674     
       
  2675     QVERIFY(dest3.relatedContacts().contains(source.id()));
       
  2676     QVERIFY(!dest3.relationships().contains(customRelationshipOne));
       
  2677     QVERIFY(dest3.relationships().contains(customRelationshipTwo));
       
  2678     QVERIFY(!dest3.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipOne));
       
  2679 
       
  2680     // Test iteration
       
  2681     QList<QContactRelationship> relats = source.relationships();
       
  2682     QList<QContactRelationship>::iterator it = relats.begin();
       
  2683 
       
  2684     while (it != relats.end()) {
       
  2685         QContactId firstId = it->first();
       
  2686         QVERIFY(firstId == source.id());
       
  2687         QVERIFY(it->second() == dest2.id() || it->second() == dest3.id());
       
  2688         it++;
       
  2689     }
       
  2690     
       
  2691     if (availableRelationshipTypes.count() > 1) {
       
  2692         QVERIFY(source.relatedContacts(availableRelationshipTypes.at(1), QContactRelationshipFilter::Second).contains(dest3.id()));
       
  2693         QVERIFY(source.relatedContacts(availableRelationshipTypes.at(1), QContactRelationshipFilter::First).isEmpty());
       
  2694         
       
  2695         QVERIFY(dest2.relationships(availableRelationshipTypes.at(1)).isEmpty());
       
  2696         
       
  2697         QVERIFY(!dest3.relationships(availableRelationshipTypes.at(0)).contains(customRelationshipTwo));
       
  2698         QVERIFY(dest3.relationships(availableRelationshipTypes.at(1)).contains(customRelationshipTwo));
       
  2699         QVERIFY(!dest3.relationships(availableRelationshipTypes.at(1)).contains(customRelationshipOne));
       
  2700         QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1)).contains(source.id()));
       
  2701         QVERIFY(!dest3.relatedContacts(availableRelationshipTypes.at(0)).contains(source.id()));
       
  2702         QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1)).contains(source.id())); // role = either
       
  2703         QVERIFY(!dest3.relatedContacts(availableRelationshipTypes.at(1), QContactRelationshipFilter::Second).contains(source.id()));
       
  2704         QVERIFY(dest3.relatedContacts(availableRelationshipTypes.at(1), QContactRelationshipFilter::First).contains(source.id()));
       
  2705         QVERIFY(dest2.relatedContacts(availableRelationshipTypes.at(1)).isEmpty());
       
  2706     }
       
  2707     else {
       
  2708         QVERIFY(source.relatedContacts(availableRelationshipTypes.at(0), QContactRelationshipFilter::Second).contains(dest3.id()));
       
  2709     }
       
  2710     
       
  2711     // Cleanup a bit
       
  2712     QVERIFY(cm->removeRelationship(customRelationshipOne));
       
  2713     QVERIFY(cm->removeRelationship(customRelationshipTwo));
       
  2714 
       
  2715     // test batch API and ordering in contacts
       
  2716     QList<QContactRelationship> currentRelationships = cm->relationships(source.id(), QContactRelationshipFilter::First);
       
  2717     QList<QContactRelationship> batchList;
       
  2718     QContactRelationship br1, br2, br3;
       
  2719     br1.setFirst(source.id());
       
  2720     br1.setSecond(dest2.id());
       
  2721     br1.setRelationshipType(availableRelationshipTypes.at(0));    
       
  2722     br2.setFirst(source.id());
       
  2723     br2.setSecond(dest3.id());
       
  2724     br2.setRelationshipType(availableRelationshipTypes.at(0));
       
  2725     if (availableRelationshipTypes.count() > 1)
       
  2726     {
       
  2727         br3.setFirst(source.id());
       
  2728         br3.setSecond(dest3.id());
       
  2729         br3.setRelationshipType(availableRelationshipTypes.at(1));
       
  2730     }
       
  2731     else
       
  2732     {
       
  2733         br3.setFirst(source.id());
       
  2734         br3.setSecond(dest4.id());
       
  2735         br3.setRelationshipType(availableRelationshipTypes.at(0));
       
  2736     }
       
  2737     batchList << br1 << br2 << br3;
       
  2738 
       
  2739     // ensure that the batch save works properly
       
  2740     cm->saveRelationships(&batchList);
       
  2741     QVERIFY(cm->error() == QContactManager::NoError);
       
  2742     QList<QContactRelationship> batchRetrieve = cm->relationships(source.id(), QContactRelationshipFilter::First);
       
  2743     QVERIFY(batchRetrieve.contains(br1));
       
  2744     QVERIFY(batchRetrieve.contains(br2));
       
  2745     QVERIFY(batchRetrieve.contains(br3));
       
  2746     
       
  2747     // Check relationship ordering support
       
  2748     if (cm->hasFeature(QContactManager::RelationshipOrdering))
       
  2749     {   
       
  2750         // test relationship ordering in the contact
       
  2751         source = cm->contact(source.localId());
       
  2752         QList<QContactRelationship> cachedRelationships = source.relationships();
       
  2753         QList<QContactRelationship> orderedRelationships = source.relationshipOrder();
       
  2754         QCOMPARE(cachedRelationships, orderedRelationships); // initially, should be the same
       
  2755         QVERIFY(orderedRelationships.contains(br1));
       
  2756         QVERIFY(orderedRelationships.contains(br2));
       
  2757         QVERIFY(orderedRelationships.contains(br3));    
       
  2758      
       
  2759         // ensure that the reordering works as required.
       
  2760         QContactRelationship temp1 = orderedRelationships.takeAt(0); // now fiddle with the order
       
  2761         QContactRelationship temp2 = orderedRelationships.at(0);     // this is the new first relationship
       
  2762         orderedRelationships.insert(2, temp1);                       // and save the old first back at position 3.
       
  2763         source.setRelationshipOrder(orderedRelationships);           // set the new relationship order
       
  2764         cm->saveContact(&source);                                    // save the contact to persist the new order
       
  2765         source = cm->contact(source.localId());                      // reload the contact
       
  2766         QCOMPARE(source.relationshipOrder(), orderedRelationships);  // ensure that it was persisted.
       
  2767     
       
  2768         // now lets try a negative reordering test: adding relationships which don't exist in the database.
       
  2769         QContactRelationship invalidRel;
       
  2770         invalidRel.setFirst(source.id());
       
  2771         invalidRel.setSecond(dest2.id());
       
  2772         invalidRel.setRelationshipType("test-nokia-invalid-relationship-type");
       
  2773         orderedRelationships << invalidRel;
       
  2774         source.setRelationshipOrder(orderedRelationships);
       
  2775         QVERIFY(!cm->saveContact(&source));
       
  2776         QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  2777         orderedRelationships.removeOne(br3);
       
  2778         source.setRelationshipOrder(orderedRelationships);
       
  2779         QVERIFY(!cm->saveContact(&source));
       
  2780         QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  2781         source.setRelationshipOrder(QList<QContactRelationship>());
       
  2782         QVERIFY(!cm->saveContact(&source));
       
  2783         QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  2784     }
       
  2785 
       
  2786     // remove a single relationship
       
  2787     QVERIFY(cm->removeRelationship(br3));
       
  2788     batchRetrieve = cm->relationships(source.id(), QContactRelationshipFilter::First);
       
  2789     QVERIFY(batchRetrieve.contains(br1));
       
  2790     QVERIFY(batchRetrieve.contains(br2));
       
  2791     QVERIFY(!batchRetrieve.contains(br3)); // has already been removed.
       
  2792 
       
  2793     // now ensure that the batch remove works and we get returned to the original state.
       
  2794     batchList.removeOne(br3);
       
  2795     cm->removeRelationships(batchList);
       
  2796     QVERIFY(cm->error() == QContactManager::NoError);
       
  2797     QCOMPARE(cm->relationships(source.id(), QContactRelationshipFilter::First), currentRelationships);
       
  2798 
       
  2799     // attempt to save relationships between an existing source but non-existent destination
       
  2800     QContactId nonexistentDest;
       
  2801     quint32 idSeed = 0x5544;
       
  2802     QContactLocalId nonexistentLocalId = QContactLocalId(idSeed);
       
  2803     nonexistentDest.setManagerUri(cm->managerUri());
       
  2804     while (true) {
       
  2805         nonexistentLocalId = cm->contact(nonexistentLocalId).localId();
       
  2806         if (nonexistentLocalId == QContactLocalId(0)) {
       
  2807             // found a "spare" local id (no contact with that id)
       
  2808             break;
       
  2809         }
       
  2810 
       
  2811         // keep looking...
       
  2812         idSeed += 1;
       
  2813         nonexistentLocalId = QContactLocalId(idSeed);
       
  2814         QVERIFY(nonexistentLocalId != QContactLocalId(0)); // integer overflow check.
       
  2815     }
       
  2816     nonexistentDest.setLocalId(nonexistentLocalId);
       
  2817     QContactRelationship maliciousRel;
       
  2818     maliciousRel.setFirst(source.id());
       
  2819     maliciousRel.setSecond(nonexistentDest);
       
  2820     maliciousRel.setRelationshipType("nokia-test-invalid-relationship-type");
       
  2821     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  2822 
       
  2823     // attempt to save a circular relationship
       
  2824     maliciousRel.setFirst(source.id());
       
  2825     maliciousRel.setSecond(source.id());
       
  2826     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  2827     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  2828 
       
  2829     // more negative testing, but force manager to recognise the empty URI
       
  2830     QContactId circularId = source.id();
       
  2831     circularId.setManagerUri(QString());
       
  2832     maliciousRel.setFirst(circularId);
       
  2833     maliciousRel.setSecond(circularId);
       
  2834     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  2835     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  2836     maliciousRel.setFirst(source.id());
       
  2837     maliciousRel.setSecond(circularId);
       
  2838     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  2839     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  2840     maliciousRel.setFirst(circularId);
       
  2841     maliciousRel.setSecond(source.id());
       
  2842     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  2843     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  2844 
       
  2845     // attempt to save a relationship where the source contact comes from another manager
       
  2846     circularId.setManagerUri("test-nokia-invalid-manager-uri");
       
  2847     maliciousRel.setFirst(circularId);   // an invalid source contact
       
  2848     maliciousRel.setSecond(dest2.id());       // a valid destination contact
       
  2849     maliciousRel.setRelationshipType(availableRelationshipTypes.at(0));
       
  2850     QVERIFY(!cm->saveRelationship(&maliciousRel));
       
  2851 
       
  2852     // remove the nonexistent relationship
       
  2853     relationshipsCount = cm->relationships().count();
       
  2854     QVERIFY(!cm->removeRelationship(maliciousRel));         // does not exist; fail remove.
       
  2855     QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
       
  2856     QCOMPARE(cm->relationships().count(), relationshipsCount); // should be unchanged.
       
  2857 
       
  2858     // now clean up and remove our dests.
       
  2859     QVERIFY(cm->removeContact(source.localId()));
       
  2860     QVERIFY(cm->removeContact(dest2.localId()));
       
  2861     QVERIFY(cm->removeContact(dest3.localId()));
       
  2862 
       
  2863     // attempt to save relationships with nonexistent contacts
       
  2864     QVERIFY(!cm->saveRelationship(&br1));
       
  2865     QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  2866     cm->saveRelationships(&batchList);
       
  2867     QVERIFY(cm->error() == QContactManager::InvalidRelationshipError);
       
  2868     QVERIFY(!cm->removeRelationship(br1));
       
  2869     QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
       
  2870     cm->removeRelationships(batchList);
       
  2871     QVERIFY(cm->error() == QContactManager::DoesNotExistError || cm->error() == QContactManager::InvalidRelationshipError);
       
  2872 }
       
  2873 
       
  2874 void tst_QContactManager::contactType()
       
  2875 {
       
  2876     QFETCH(QString, uri);
       
  2877     QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
       
  2878 
       
  2879     if (!cm->hasFeature(QContactManager::Groups))
       
  2880         QSKIP("Skipping: This manager does not support group contacts!", SkipSingle);
       
  2881 
       
  2882     QContact g1, g2, c;
       
  2883     g1.setType(QContactType::TypeGroup);
       
  2884     g2.setType(QContactType::TypeGroup);
       
  2885 
       
  2886     QContactPhoneNumber g1p, g2p, cp;
       
  2887     g1p.setNumber("22222");
       
  2888     g2p.setNumber("11111");
       
  2889     cp.setNumber("33333");
       
  2890 
       
  2891     g1.saveDetail(&g1p);
       
  2892     g2.saveDetail(&g2p);
       
  2893     c.saveDetail(&cp);
       
  2894 
       
  2895     QVERIFY(cm->saveContact(&g1));
       
  2896     QVERIFY(cm->saveContact(&g2));
       
  2897     QVERIFY(cm->saveContact(&c));
       
  2898 
       
  2899     // test that the accessing by type works properly
       
  2900     QContactDetailFilter groupFilter;
       
  2901     groupFilter.setDetailDefinitionName(QContactType::DefinitionName, QContactType::FieldType);
       
  2902     groupFilter.setValue(QString(QLatin1String(QContactType::TypeGroup)));
       
  2903     QVERIFY(cm->contactIds(groupFilter).contains(g1.localId()));
       
  2904     QVERIFY(cm->contactIds(groupFilter).contains(g2.localId()));
       
  2905     QVERIFY(!cm->contactIds(groupFilter).contains(c.localId()));
       
  2906 
       
  2907     QList<QContactSortOrder> sortOrders;
       
  2908     QContactSortOrder byPhoneNumber;
       
  2909     byPhoneNumber.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
       
  2910     sortOrders.append(byPhoneNumber);
       
  2911 
       
  2912     // and ensure that sorting works properly with typed contacts also
       
  2913     QList<QContactLocalId> sortedIds = cm->contactIds(groupFilter, sortOrders);
       
  2914     QVERIFY(sortedIds.indexOf(g2.localId()) < sortedIds.indexOf(g1.localId()));
       
  2915 
       
  2916     cm->removeContact(g1.localId());
       
  2917     cm->removeContact(g2.localId());
       
  2918     cm->removeContact(c.localId());
       
  2919 }
       
  2920 
       
  2921 QTEST_MAIN(tst_QContactManager)
       
  2922 #include "tst_qcontactmanager.moc"