--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qtcontactsmobility/tests/auto/qcontactasync/unittest/tst_qcontactasync.cpp Fri Mar 19 09:27:18 2010 +0200
@@ -0,0 +1,2167 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QCoreApplication>
+#include "qtcontacts.h"
+#include "qcontactmanagerdataholder.h" //QContactManagerDataHolder
+
+QTM_USE_NAMESPACE
+
+class tst_QContactAsync : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QContactAsync();
+ virtual ~tst_QContactAsync();
+
+public slots:
+ void init();
+ void cleanup();
+
+private:
+ void addManagers(); // add standard managers to the data
+
+private slots:
+ void testDestructor();
+ void testDestructor_data() { addManagers(); }
+
+ void contactFetch();
+ void contactFetch_data() { addManagers(); }
+ void contactIdFetch();
+ void contactIdFetch_data() { addManagers(); }
+ void contactRemove();
+ void contactRemove_data() { addManagers(); }
+ void contactSave();
+ void contactSave_data() { addManagers(); }
+
+ void definitionFetch();
+ void definitionFetch_data() { addManagers(); }
+ void definitionRemove();
+ void definitionRemove_data() { addManagers(); }
+ void definitionSave();
+ void definitionSave_data() { addManagers(); }
+
+ void relationshipFetch();
+ void relationshipFetch_data() { addManagers(); }
+ void relationshipRemove();
+ void relationshipRemove_data() { addManagers(); }
+ void relationshipSave();
+ void relationshipSave_data() { addManagers(); }
+
+ void maliciousManager(); // uses it's own custom data (manager)
+
+ void threadDelivery();
+ void progressReceived(QContactFetchRequest* request, bool appendOnly);
+ void threadDelivery_data() { addManagers(); }
+
+private:
+ bool containsIgnoringTimestamps(const QList<QContact>& list, const QContact& c);
+ bool compareIgnoringTimestamps(const QContact& ca, const QContact& cb);
+ bool prepareModel(const QString &uri, QContactManager *&cm);
+ bool prepareModel(const QString &uri, QContactManager *&cm, QList<QContact> &contacts, QList<QContactRelationship> &relationships);
+
+ Qt::HANDLE m_mainThreadId;
+ Qt::HANDLE m_progressSlotThreadId;
+ QContactManagerDataHolder managerDataHolder;
+};
+
+typedef QList<QContactLocalId> QContactLocalIdList;
+Q_DECLARE_METATYPE(QContactLocalIdList);
+
+tst_QContactAsync::tst_QContactAsync()
+{
+ // ensure we can load all of the plugins we need to.
+ QString path = QApplication::applicationDirPath() + "/dummyplugin/plugins";
+ QApplication::addLibraryPath(path);
+
+ qRegisterMetaType<QContactLocalIdList>("QList<QContactLocalId>");
+}
+
+tst_QContactAsync::~tst_QContactAsync()
+{
+ QString path = QApplication::applicationDirPath() + "/dummyplugin/plugins";
+ QApplication::removeLibraryPath(path);
+}
+
+void tst_QContactAsync::init()
+{
+}
+
+void tst_QContactAsync::cleanup()
+{
+}
+
+bool tst_QContactAsync::containsIgnoringTimestamps(const QList<QContact>& list, const QContact& c)
+{
+ QList<QContact> cl = list;
+ QContact a(c);
+ for (int i = 0; i < cl.size(); i++) {
+ QContact b(cl.at(i));
+ if (compareIgnoringTimestamps(a, b))
+ return true;
+ }
+
+ return false;
+}
+
+bool tst_QContactAsync::compareIgnoringTimestamps(const QContact& ca, const QContact& cb)
+{
+ // Compares two contacts, ignoring any timestamp details
+ QContact a(ca);
+ QContact b(cb);
+ QList<QContactDetail> aDetails = a.details();
+ QList<QContactDetail> bDetails = b.details();
+
+ // They can be in any order, so loop
+ // First remove any matches, and any timestamps
+ foreach (QContactDetail d, aDetails) {
+ foreach (QContactDetail d2, bDetails) {
+ if (d == d2) {
+ a.removeDetail(&d);
+ b.removeDetail(&d2);
+ break;
+ }
+
+ if (d.definitionName() == QContactTimestamp::DefinitionName) {
+ a.removeDetail(&d);
+ }
+
+ if (d2.definitionName() == QContactTimestamp::DefinitionName) {
+ b.removeDetail(&d2);
+ }
+ }
+ }
+
+ if (a == b)
+ return true;
+ return false;
+}
+
+void tst_QContactAsync::testDestructor()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ QContactFetchRequest* req = new QContactFetchRequest;
+ req->setManager(cm);
+
+ QContactManager* cm2(0);
+ QVERIFY(prepareModel(uri, cm2));
+ QContactFetchRequest* req2 = new QContactFetchRequest;
+ req2->setManager(cm2);
+
+ // first, delete manager then request
+ delete cm;
+ delete req;
+
+ // second, delete request then manager
+ delete req2;
+ delete cm2;
+}
+
+void tst_QContactAsync::contactFetch()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ QContactFetchRequest cfr;
+ QVERIFY(cfr.type() == QContactAbstractRequest::ContactFetchRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!cfr.isActive());
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+ QVERIFY(!cfr.waitForProgress());
+
+ // "all contacts" retrieval
+ QContactFilter fil;
+ cfr.setManager(cm);
+ QCOMPARE(cfr.manager(), cm);
+ QVERIFY(!cfr.isActive());
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+ QVERIFY(!cfr.waitForProgress());
+ qRegisterMetaType<QContactFetchRequest*>("QContactFetchRequest*");
+ QSignalSpy spy(&cfr, SIGNAL(progress(QContactFetchRequest*, bool)));
+ cfr.setFilter(fil);
+ QCOMPARE(cfr.filter(), fil);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ QList<QContactLocalId> contactIds = cm->contacts();
+ QList<QContact> contacts = cfr.contacts();
+ QCOMPARE(contactIds.size(), contacts.size());
+ for (int i = 0; i < contactIds.size(); i++) {
+ QContact curr = cm->contact(contactIds.at(i));
+ QVERIFY(contacts.at(i) == curr);
+ }
+
+ // asynchronous detail filtering
+ QContactDetailFilter dfil;
+ dfil.setDetailDefinitionName(QContactUrl::DefinitionName, QContactUrl::FieldUrl);
+ cfr.setFilter(dfil);
+ QVERIFY(cfr.filter() == dfil);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ contactIds = cm->contacts(dfil);
+ contacts = cfr.contacts();
+ QCOMPARE(contactIds.size(), contacts.size());
+ for (int i = 0; i < contactIds.size(); i++) {
+ QContact curr = cm->contact(contactIds.at(i));
+ QVERIFY(contacts.at(i) == curr);
+ }
+
+ // sort order
+ QContactSortOrder sortOrder;
+ sortOrder.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
+ QList<QContactSortOrder> sorting;
+ sorting.append(sortOrder);
+ cfr.setFilter(fil);
+ cfr.setSorting(sorting);
+ QCOMPARE(cfr.sorting(), sorting);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ contactIds = cm->contacts(sorting);
+ contacts = cfr.contacts();
+ QCOMPARE(contactIds.size(), contacts.size());
+ for (int i = 0; i < contactIds.size(); i++) {
+ QContact curr = cm->contact(contactIds.at(i));
+ QVERIFY(contacts.at(i) == curr);
+ }
+
+ // restrictions
+ sorting.clear();
+ cfr.setFilter(fil);
+ cfr.setSorting(sorting);
+ cfr.setDefinitionRestrictions(QStringList(QContactName::DefinitionName));
+ QCOMPARE(cfr.definitionRestrictions(), QStringList(QContactName::DefinitionName));
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ contactIds = cm->contacts(sorting);
+ contacts = cfr.contacts();
+ QCOMPARE(contactIds.size(), contacts.size());
+ for (int i = 0; i < contactIds.size(); i++) {
+ // create a contact from the restricted data only (id + display label)
+ QContact currFull = cm->contact(contactIds.at(i));
+ QContact currRestricted;
+ currRestricted.setId(currFull.id());
+ QList<QContactName> names = currFull.details<QContactName>();
+ foreach (const QContactName& name, names) {
+ QContactName fullName = name;
+ if (!fullName.isEmpty()) {
+ currRestricted.saveDetail(&fullName);
+ }
+ }
+
+ // now find the contact in the retrieved list which our restricted contact mimics
+ QContact retrievedRestricted;
+ bool found = false;
+ foreach (const QContact& retrieved, contacts) {
+ if (retrieved.id() == currRestricted.id()) {
+ retrievedRestricted = retrieved;
+ found = true;
+ }
+ }
+
+ QVERIFY(found); // must exist or fail.
+
+ // ensure that the contact is the same (except synth fields)
+ QList<QContactDetail> fdets = retrievedRestricted.details();
+ QList<QContactDetail> rdets = currRestricted.details();
+ foreach (const QContactDetail& det, fdets) {
+ // ignore backend synthesised details
+ // again, this requires a "default contact details" function to work properly.
+ if (det.definitionName() == QContactDisplayLabel::DefinitionName
+ || det.definitionName() == QContactTimestamp::DefinitionName) {
+ continue;
+ }
+
+ // everything else must exist in both.
+ if(!rdets.contains(det)) {
+ qWarning("A detail exists in retrieved contact which doesn't exist in restricted contact! This could be due to backend synthesization, or represent a bug! (Definition name: %s)", det.definitionName().toAscii().constData());
+ }
+ }
+ }
+
+ // cancelling
+ sorting.clear();
+ cfr.setFilter(fil);
+ cfr.setSorting(sorting);
+ cfr.setDefinitionRestrictions(QStringList());
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(cfr.cancel());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(cfr.isActive()); // still cancelling
+ QVERIFY(!cfr.isFinished()); // not finished cancelling
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelled);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(cfr.cancel());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(cfr.isActive()); // still cancelling
+ QVERIFY(!cfr.isFinished()); // not finished cancelling
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelled);
+
+ delete cm;
+}
+
+void tst_QContactAsync::contactIdFetch()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ QContactLocalIdFetchRequest cfr;
+ QVERIFY(cfr.type() == QContactAbstractRequest::ContactLocalIdFetchRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!cfr.isActive());
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+ QVERIFY(!cfr.waitForProgress());
+
+ // "all contacts" retrieval
+ QContactFilter fil;
+ cfr.setManager(cm);
+ QCOMPARE(cfr.manager(), cm);
+ QVERIFY(!cfr.isActive());
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+ QVERIFY(!cfr.waitForProgress());
+ qRegisterMetaType<QContactLocalIdFetchRequest*>("QContactLocalIdFetchRequest*");
+ QSignalSpy spy(&cfr, SIGNAL(progress(QContactLocalIdFetchRequest*, bool)));
+ cfr.setFilter(fil);
+ QCOMPARE(cfr.filter(), fil);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ QList<QContactLocalId> contactIds = cm->contacts();
+ QList<QContactLocalId> result = cfr.ids();
+ QCOMPARE(contactIds, result);
+
+ // asynchronous detail filtering
+ QContactDetailFilter dfil;
+ dfil.setDetailDefinitionName(QContactUrl::DefinitionName, QContactUrl::FieldUrl);
+ cfr.setFilter(dfil);
+ QVERIFY(cfr.filter() == dfil);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ contactIds = cm->contacts(dfil);
+ result = cfr.ids();
+ QCOMPARE(contactIds, result);
+
+ // sort order
+ QContactSortOrder sortOrder;
+ sortOrder.setDetailDefinitionName(QContactPhoneNumber::DefinitionName, QContactPhoneNumber::FieldNumber);
+ QList<QContactSortOrder> sorting;
+ sorting.append(sortOrder);
+ cfr.setFilter(fil);
+ cfr.setSorting(sorting);
+ QCOMPARE(cfr.sorting(), sorting);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+
+ contactIds = cm->contacts(sorting);
+ result = cfr.ids();
+ QCOMPARE(contactIds, result);
+
+ // cancelling
+ sorting.clear();
+ cfr.setFilter(fil);
+ cfr.setSorting(sorting);
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(cfr.cancel());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(cfr.isActive()); // still cancelling
+ QVERIFY(!cfr.isFinished()); // not finished cancelling
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelled);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!cfr.cancel()); // not started
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(cfr.cancel());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(cfr.isActive()); // still cancelling
+ QVERIFY(!cfr.isFinished()); // not finished cancelling
+ QVERIFY(!cfr.start()); // already started.
+ QVERIFY(cfr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(cfr.isFinished());
+ QVERIFY(!cfr.isActive());
+ QVERIFY(cfr.status() == QContactAbstractRequest::Cancelled);
+
+ delete cm;
+}
+
+void tst_QContactAsync::contactRemove()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ QContactRemoveRequest crr;
+ QVERIFY(crr.type() == QContactAbstractRequest::ContactRemoveRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!crr.isActive());
+ QVERIFY(!crr.isFinished());
+ QVERIFY(!crr.start());
+ QVERIFY(!crr.cancel());
+ QVERIFY(!crr.waitForFinished());
+ QVERIFY(!crr.waitForProgress());
+
+ // specific contact removal
+ int originalCount = cm->contacts().size();
+ QContactDetailFilter dfil;
+ dfil.setDetailDefinitionName(QContactUrl::DefinitionName, QContactUrl::FieldUrl);
+ crr.setFilter(dfil);
+ crr.setManager(cm);
+ QCOMPARE(crr.manager(), cm);
+ QVERIFY(!crr.isActive());
+ QVERIFY(!crr.isFinished());
+ QVERIFY(!crr.cancel());
+ QVERIFY(!crr.waitForFinished());
+ QVERIFY(!crr.waitForProgress());
+ qRegisterMetaType<QContactRemoveRequest*>("QContactRemoveRequest*");
+ QSignalSpy spy(&crr, SIGNAL(progress(QContactRemoveRequest*)));
+ QVERIFY(crr.filter() == dfil);
+ QVERIFY(!crr.cancel()); // not started
+ QVERIFY(crr.start());
+ QVERIFY(crr.isActive());
+ QVERIFY(crr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!crr.isFinished());
+ QVERIFY(!crr.start()); // already started.
+ QVERIFY(crr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(crr.isFinished());
+ QVERIFY(!crr.isActive());
+
+ QCOMPARE(cm->contacts().size(), originalCount - 1);
+ QVERIFY(cm->contacts(dfil).isEmpty());
+
+ // remove all contacts
+ dfil.setDetailDefinitionName(QContactDisplayLabel::DefinitionName); // delete everything.
+ crr.setFilter(dfil);
+ QVERIFY(crr.filter() == dfil);
+ QVERIFY(!crr.cancel()); // not started
+ QVERIFY(crr.start());
+ QVERIFY(crr.isActive());
+ QVERIFY(crr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!crr.isFinished());
+ QVERIFY(!crr.start()); // already started.
+ QVERIFY(crr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(crr.isFinished());
+ QVERIFY(!crr.isActive());
+
+ QCOMPARE(cm->contacts().size(), 0); // no contacts should be left.
+
+ // cancelling
+ QContact temp;
+ QContactName nameDetail;
+ nameDetail.setFirst("Should not be removed");
+ temp.saveDetail(&nameDetail);
+ cm->saveContact(&temp);
+ crr.setFilter(dfil);
+ QVERIFY(!crr.cancel()); // not started
+ QVERIFY(crr.start());
+ QVERIFY(crr.isActive());
+ QVERIFY(crr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!crr.isFinished());
+ QVERIFY(crr.cancel());
+ QVERIFY(crr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(crr.isActive()); // still cancelling
+ QVERIFY(!crr.isFinished()); // not finished cancelling
+ QVERIFY(!crr.start()); // already started.
+ QVERIFY(crr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(crr.isFinished());
+ QVERIFY(!crr.isActive());
+ QVERIFY(crr.status() == QContactAbstractRequest::Cancelled);
+
+ QCOMPARE(cm->contacts().size(), 1);
+ QCOMPARE(cm->contact(cm->contacts().first()), temp);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!crr.cancel()); // not started
+ QVERIFY(crr.start());
+ QVERIFY(crr.isActive());
+ QVERIFY(crr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!crr.isFinished());
+ QVERIFY(crr.cancel());
+ QVERIFY(crr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(crr.isActive()); // still cancelling
+ QVERIFY(!crr.isFinished()); // not finished cancelling
+ QVERIFY(!crr.start()); // already started.
+ QVERIFY(crr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(crr.isFinished());
+ QVERIFY(!crr.isActive());
+ QVERIFY(crr.status() == QContactAbstractRequest::Cancelled);
+
+ QCOMPARE(cm->contacts().size(), 1);
+ QCOMPARE(cm->contact(cm->contacts().first()), temp);
+ cm->removeContact(temp.localId()); // clean up
+
+ delete cm;
+}
+
+void tst_QContactAsync::contactSave()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ QContactSaveRequest csr;
+ QVERIFY(csr.type() == QContactAbstractRequest::ContactSaveRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!csr.isActive());
+ QVERIFY(!csr.isFinished());
+ QVERIFY(!csr.start());
+ QVERIFY(!csr.cancel());
+ QVERIFY(!csr.waitForFinished());
+ QVERIFY(!csr.waitForProgress());
+
+ // save a new contact
+ int originalCount = cm->contacts().size();
+ QContact testContact;
+ QContactName nameDetail;
+ nameDetail.setFirst("Test Contact");
+ testContact.saveDetail(&nameDetail);
+ QList<QContact> saveList;
+ saveList << testContact;
+ csr.setManager(cm);
+ QCOMPARE(csr.manager(), cm);
+ QVERIFY(!csr.isActive());
+ QVERIFY(!csr.isFinished());
+ QVERIFY(!csr.cancel());
+ QVERIFY(!csr.waitForFinished());
+ QVERIFY(!csr.waitForProgress());
+ qRegisterMetaType<QContactSaveRequest*>("QContactSaveRequest*");
+ QSignalSpy spy(&csr, SIGNAL(progress(QContactSaveRequest*)));
+ csr.setContacts(saveList);
+ QCOMPARE(csr.contacts(), saveList);
+ QVERIFY(!csr.cancel()); // not started
+ QVERIFY(csr.start());
+ QVERIFY(csr.isActive());
+ QVERIFY(csr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!csr.isFinished());
+ QVERIFY(!csr.start()); // already started.
+ QVERIFY(csr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(csr.isFinished());
+ QVERIFY(!csr.isActive());
+
+ QList<QContact> expected;
+ expected << cm->contact(cm->contacts().last());
+ QList<QContact> result = csr.contacts();
+ QCOMPARE(expected, result);
+ QCOMPARE(cm->contacts().size(), originalCount + 1);
+
+ // update a previously saved contact
+ QContactPhoneNumber phn;
+ phn.setNumber("12345678");
+ testContact = expected.first();
+ testContact.saveDetail(&phn);
+ saveList.clear();
+ saveList << testContact;
+ csr.setContacts(saveList);
+ QCOMPARE(csr.contacts(), saveList);
+ QVERIFY(!csr.cancel()); // not started
+ QVERIFY(csr.start());
+ QVERIFY(csr.isActive());
+ QVERIFY(csr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!csr.isFinished());
+ QVERIFY(!csr.start()); // already started.
+ QVERIFY(csr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(csr.isFinished());
+ QVERIFY(!csr.isActive());
+
+ expected.clear();
+ expected << cm->contact(cm->contacts().last());
+ result = csr.contacts();
+ QCOMPARE(expected, result);
+
+ //here we can't compare the whole contact details, testContact would be updated by async call because we just use QSignalSpy to receive signals.
+ //QVERIFY(containsIgnoringTimestamps(expected, testContact));
+ QVERIFY(expected.at(0).detail<QContactPhoneNumber>().number() == phn.number());
+
+ QCOMPARE(cm->contacts().size(), originalCount + 1);
+
+ // cancelling
+ QContact temp = testContact;
+ QContactUrl url;
+ url.setUrl("should not get saved");
+ temp.saveDetail(&url);
+ saveList.clear();
+ saveList << temp;
+ csr.setContacts(saveList);
+ QVERIFY(!csr.cancel()); // not started
+ QVERIFY(csr.start());
+ QVERIFY(csr.isActive());
+ QVERIFY(csr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!csr.isFinished());
+ QVERIFY(csr.cancel());
+ QVERIFY(csr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(csr.isActive()); // still cancelling
+ QVERIFY(!csr.isFinished()); // not finished cancelling
+ QVERIFY(!csr.start()); // already started.
+ QVERIFY(csr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(csr.isFinished());
+ QVERIFY(!csr.isActive());
+ QVERIFY(csr.status() == QContactAbstractRequest::Cancelled);
+
+ // verify that the changes were not saved
+ expected.clear();
+ QList<QContactLocalId> allContacts = cm->contacts();
+ for (int i = 0; i < allContacts.size(); i++) {
+ expected.append(cm->contact(allContacts.at(i)));
+ }
+ QVERIFY(!expected.contains(temp));
+ QCOMPARE(cm->contacts().size(), originalCount + 1);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!csr.cancel()); // not started
+ QVERIFY(csr.start());
+ QVERIFY(csr.isActive());
+ QVERIFY(csr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!csr.isFinished());
+ QVERIFY(csr.cancel());
+ QVERIFY(csr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(csr.isActive()); // still cancelling
+ QVERIFY(!csr.isFinished()); // not finished cancelling
+ QVERIFY(!csr.start()); // already started.
+ QVERIFY(csr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(csr.isFinished());
+ QVERIFY(!csr.isActive());
+ QVERIFY(csr.status() == QContactAbstractRequest::Cancelled);
+
+ // verify that the changes were not saved
+ expected.clear();
+ allContacts = cm->contacts();
+ for (int i = 0; i < allContacts.size(); i++) {
+ expected.append(cm->contact(allContacts.at(i)));
+ }
+ QVERIFY(!expected.contains(temp));
+ QCOMPARE(cm->contacts().size(), originalCount + 1);
+
+ delete cm;
+}
+
+void tst_QContactAsync::definitionFetch()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ QContactDetailDefinitionFetchRequest dfr;
+ QVERIFY(dfr.type() == QContactAbstractRequest::DetailDefinitionFetchRequest);
+ dfr.setContactType(QContactType::TypeContact);
+ QVERIFY(dfr.contactType() == QString(QLatin1String(QContactType::TypeContact)));
+
+ // initial state - not started, no manager.
+ QVERIFY(!dfr.isActive());
+ QVERIFY(!dfr.isFinished());
+ QVERIFY(!dfr.start());
+ QVERIFY(!dfr.cancel());
+ QVERIFY(!dfr.waitForFinished());
+ QVERIFY(!dfr.waitForProgress());
+
+ // "all definitions" retrieval
+ dfr.setManager(cm);
+ QCOMPARE(dfr.manager(), cm);
+ QVERIFY(!dfr.isActive());
+ QVERIFY(!dfr.isFinished());
+ QVERIFY(!dfr.cancel());
+ QVERIFY(!dfr.waitForFinished());
+ QVERIFY(!dfr.waitForProgress());
+ qRegisterMetaType<QContactDetailDefinitionFetchRequest*>("QContactDetailDefinitionFetchRequest*");
+ QSignalSpy spy(&dfr, SIGNAL(progress(QContactDetailDefinitionFetchRequest*, bool)));
+ dfr.setNames(QStringList());
+ QVERIFY(!dfr.cancel()); // not started
+ QVERIFY(dfr.start());
+ QVERIFY(dfr.isActive());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dfr.isFinished());
+ QVERIFY(!dfr.start()); // already started.
+ QVERIFY(dfr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(dfr.isFinished());
+ QVERIFY(!dfr.isActive());
+
+ QMap<QString, QContactDetailDefinition> defs = cm->detailDefinitions();
+ QMap<QString, QContactDetailDefinition> result = dfr.definitions();
+ QCOMPARE(defs, result);
+
+ // specific definition retrieval
+ QStringList specific;
+ specific << QContactUrl::DefinitionName;
+ dfr.setNames(specific);
+ QVERIFY(!dfr.cancel()); // not started
+ QVERIFY(dfr.start());
+ QVERIFY(dfr.isActive());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dfr.isFinished());
+ QVERIFY(!dfr.start()); // already started.
+ QVERIFY(dfr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(dfr.isFinished());
+ QVERIFY(!dfr.isActive());
+
+ defs.clear();
+ defs.insert(QContactUrl::DefinitionName, cm->detailDefinition(QContactUrl::DefinitionName));
+ result = dfr.definitions();
+ QCOMPARE(defs, result);
+
+ // cancelling
+ dfr.setNames(QStringList());
+ QVERIFY(!dfr.cancel()); // not started
+ QVERIFY(dfr.start());
+ QVERIFY(dfr.isActive());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dfr.isFinished());
+ QVERIFY(dfr.cancel());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(dfr.isActive()); // still cancelling
+ QVERIFY(!dfr.isFinished()); // not finished cancelling
+ QVERIFY(!dfr.start()); // already started.
+ QVERIFY(dfr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(dfr.isFinished());
+ QVERIFY(!dfr.isActive());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Cancelled);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!dfr.cancel()); // not started
+ QVERIFY(dfr.start());
+ QVERIFY(dfr.isActive());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dfr.isFinished());
+ QVERIFY(dfr.cancel());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(dfr.isActive()); // still cancelling
+ QVERIFY(!dfr.isFinished()); // not finished cancelling
+ QVERIFY(!dfr.start()); // already started.
+ QVERIFY(dfr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(dfr.isFinished());
+ QVERIFY(!dfr.isActive());
+ QVERIFY(dfr.status() == QContactAbstractRequest::Cancelled);
+
+ delete cm;
+}
+
+void tst_QContactAsync::definitionRemove()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ if (!cm->hasFeature(QContactManager::MutableDefinitions, QContactType::TypeContact)) {
+ QSKIP("This contact manager doest not support mutable definitions, can't remove a definition!", SkipSingle);
+ }
+ QContactDetailDefinitionRemoveRequest drr;
+ QVERIFY(drr.type() == QContactAbstractRequest::DetailDefinitionRemoveRequest);
+ drr.setContactType(QContactType::TypeContact);
+ QVERIFY(drr.contactType() == QString(QLatin1String(QContactType::TypeContact)));
+
+ // initial state - not started, no manager.
+ QVERIFY(!drr.isActive());
+ QVERIFY(!drr.isFinished());
+ QVERIFY(!drr.start());
+ QVERIFY(!drr.cancel());
+ QVERIFY(!drr.waitForFinished());
+ QVERIFY(!drr.waitForProgress());
+
+ // specific group removal
+ int originalCount = cm->detailDefinitions().keys().size();
+ QStringList removeIds;
+ removeIds << cm->detailDefinitions().keys().first();
+ drr.setNames(removeIds);
+ drr.setManager(cm);
+ QCOMPARE(drr.manager(), cm);
+ QVERIFY(!drr.isActive());
+ QVERIFY(!drr.isFinished());
+ QVERIFY(!drr.cancel());
+ QVERIFY(!drr.waitForFinished());
+ QVERIFY(!drr.waitForProgress());
+ qRegisterMetaType<QContactDetailDefinitionRemoveRequest*>("QContactDetailDefinitionRemoveRequest*");
+ QSignalSpy spy(&drr, SIGNAL(progress(QContactDetailDefinitionRemoveRequest*)));
+ QVERIFY(drr.names() == removeIds);
+ QVERIFY(!drr.cancel()); // not started
+ QVERIFY(drr.start());
+ QVERIFY(drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!drr.isFinished());
+ QVERIFY(!drr.start()); // already started.
+ QVERIFY(drr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(drr.isFinished());
+ QVERIFY(!drr.isActive());
+
+ QCOMPARE(cm->detailDefinitions().keys().size(), originalCount - 1);
+ cm->detailDefinition(removeIds.first()); // check that it has already been removed.
+ QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
+
+ // remove (asynchronously) a nonexistent group - should fail.
+ drr.setNames(removeIds);
+ QVERIFY(!drr.cancel()); // not started
+ QVERIFY(drr.start());
+ QVERIFY(drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!drr.isFinished());
+ QVERIFY(!drr.start()); // already started.
+ QVERIFY(drr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(drr.isFinished());
+ QVERIFY(!drr.isActive());
+
+ QCOMPARE(cm->detailDefinitions().keys().size(), originalCount - 1); // hasn't changed
+ QCOMPARE(drr.error(), QContactManager::DoesNotExistError);
+
+ // remove with list containing one valid and one invalid id.
+ removeIds << cm->detailDefinitions().keys().first();
+ drr.setNames(removeIds);
+ QVERIFY(!drr.cancel()); // not started
+ QVERIFY(drr.start());
+ QVERIFY(drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!drr.isFinished());
+ QVERIFY(!drr.start()); // already started.
+ QVERIFY(drr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(drr.isFinished());
+ QVERIFY(!drr.isActive());
+
+ QCOMPARE(cm->detailDefinitions().keys().size(), originalCount - 2); // only one more has been removed
+ QCOMPARE(drr.errors().first(), QContactManager::DoesNotExistError);
+ QCOMPARE(drr.errors().at(1), QContactManager::NoError);
+
+ // remove with empty list - nothing should happen.
+ removeIds.clear();
+ drr.setNames(removeIds);
+ QVERIFY(!drr.cancel()); // not started
+ QVERIFY(drr.start());
+ QVERIFY(drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!drr.isFinished());
+ QVERIFY(!drr.start()); // already started.
+ QVERIFY(drr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(drr.isFinished());
+ QVERIFY(!drr.isActive());
+
+ QCOMPARE(cm->detailDefinitions().keys().size(), originalCount - 2); // hasn't changed
+ QCOMPARE(drr.error(), QContactManager::NoError); // no error but no effect.
+
+ // cancelling
+ removeIds.clear();
+ removeIds << cm->detailDefinitions().keys().first();
+ drr.setNames(removeIds);
+ QVERIFY(!drr.cancel()); // not started
+ QVERIFY(drr.start());
+ QVERIFY(drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!drr.isFinished());
+ QVERIFY(drr.cancel());
+ QVERIFY(drr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(drr.isActive()); // still cancelling
+ QVERIFY(!drr.isFinished()); // not finished cancelling
+ QVERIFY(!drr.start()); // already started.
+ QVERIFY(drr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(drr.isFinished());
+ QVERIFY(!drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Cancelled);
+
+ QCOMPARE(cm->detailDefinitions().keys().size(), originalCount - 2); // hasn't changed
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!drr.cancel()); // not started
+ QVERIFY(drr.start());
+ QVERIFY(drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!drr.isFinished());
+ QVERIFY(drr.cancel());
+ QVERIFY(drr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(drr.isActive()); // still cancelling
+ QVERIFY(!drr.isFinished()); // not finished cancelling
+ QVERIFY(!drr.start()); // already started.
+ QVERIFY(drr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(drr.isFinished());
+ QVERIFY(!drr.isActive());
+ QVERIFY(drr.status() == QContactAbstractRequest::Cancelled);
+
+ QCOMPARE(cm->detailDefinitions().keys().size(), originalCount - 2); // hasn't changed
+
+ delete cm;
+}
+
+void tst_QContactAsync::definitionSave()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QVERIFY(prepareModel(uri, cm));
+
+ if (!cm->hasFeature(QContactManager::MutableDefinitions, QContactType::TypeContact)) {
+ QSKIP("This contact manager doest not support mutable definitions, can't save a definition!", SkipSingle);
+ }
+
+ QContactDetailDefinitionSaveRequest dsr;
+ QVERIFY(dsr.type() == QContactAbstractRequest::DetailDefinitionSaveRequest);
+ dsr.setContactType(QContactType::TypeContact);
+ QVERIFY(dsr.contactType() == QString(QLatin1String(QContactType::TypeContact)));
+
+ // initial state - not started, no manager.
+ QVERIFY(!dsr.isActive());
+ QVERIFY(!dsr.isFinished());
+ QVERIFY(!dsr.start());
+ QVERIFY(!dsr.cancel());
+ QVERIFY(!dsr.waitForFinished());
+ QVERIFY(!dsr.waitForProgress());
+
+ // save a new detail definition
+ int originalCount = cm->detailDefinitions().keys().size();
+ QContactDetailDefinition testDef;
+ testDef.setName("TestDefinitionId");
+ QMap<QString, QContactDetailDefinitionField> fields;
+ QContactDetailDefinitionField f;
+ f.setDataType(QVariant::String);
+ fields.insert("TestDefinitionField", f);
+ testDef.setFields(fields);
+ QList<QContactDetailDefinition> saveList;
+ saveList << testDef;
+ dsr.setManager(cm);
+ QCOMPARE(dsr.manager(), cm);
+ QVERIFY(!dsr.isActive());
+ QVERIFY(!dsr.isFinished());
+ QVERIFY(!dsr.cancel());
+ QVERIFY(!dsr.waitForFinished());
+ QVERIFY(!dsr.waitForProgress());
+ qRegisterMetaType<QContactDetailDefinitionSaveRequest*>("QContactDetailDefinitionSaveRequest*");
+ QSignalSpy spy(&dsr, SIGNAL(progress(QContactDetailDefinitionSaveRequest*)));
+ dsr.setDefinitions(saveList);
+ QCOMPARE(dsr.definitions(), saveList);
+ QVERIFY(!dsr.cancel()); // not started
+ QVERIFY(dsr.start());
+ QVERIFY(dsr.isActive());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dsr.isFinished());
+ QVERIFY(!dsr.start()); // already started.
+ QVERIFY(dsr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(dsr.isFinished());
+ QVERIFY(!dsr.isActive());
+
+ QList<QContactDetailDefinition> expected;
+ expected << cm->detailDefinition("TestDefinitionId");
+ QList<QContactDetailDefinition> result = dsr.definitions();
+ QCOMPARE(expected, result);
+ QVERIFY(expected.contains(testDef));
+ QCOMPARE(cm->detailDefinitions().values().size(), originalCount + 1);
+
+ // update a previously saved group
+ fields.insert("TestDefinitionFieldTwo", f);
+ testDef.setFields(fields);
+ saveList.clear();
+ saveList << testDef;
+ dsr.setDefinitions(saveList);
+ QCOMPARE(dsr.definitions(), saveList);
+ QVERIFY(!dsr.cancel()); // not started
+ QVERIFY(dsr.start());
+ QVERIFY(dsr.isActive());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dsr.isFinished());
+ QVERIFY(!dsr.start()); // already started.
+ QVERIFY(dsr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(dsr.isFinished());
+ QVERIFY(!dsr.isActive());
+
+ expected.clear();
+ expected << cm->detailDefinition("TestDefinitionId");
+ result = dsr.definitions();
+ QCOMPARE(expected, result);
+ QVERIFY(expected.contains(testDef));
+ QCOMPARE(cm->detailDefinitions().values().size(), originalCount + 1);
+
+ // cancelling
+ fields.insert("TestDefinitionFieldThree - shouldn't get saved", f);
+ testDef.setFields(fields);
+ saveList.clear();
+ saveList << testDef;
+ dsr.setDefinitions(saveList);
+ QCOMPARE(dsr.definitions(), saveList);
+ QVERIFY(!dsr.cancel()); // not started
+ QVERIFY(dsr.start());
+ QVERIFY(dsr.isActive());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dsr.isFinished());
+ QVERIFY(dsr.cancel());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(dsr.isActive()); // still cancelling
+ QVERIFY(!dsr.isFinished()); // not finished cancelling
+ QVERIFY(!dsr.start()); // already started.
+ QVERIFY(dsr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(dsr.isFinished());
+ QVERIFY(!dsr.isActive());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Cancelled);
+
+ // verify that the changes were not saved
+ QList<QContactDetailDefinition> allDefs = cm->detailDefinitions().values();
+ QVERIFY(!allDefs.contains(testDef));
+ QCOMPARE(cm->detailDefinitions().values().size(), originalCount + 1);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!dsr.cancel()); // not started
+ QVERIFY(dsr.start());
+ QVERIFY(dsr.isActive());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!dsr.isFinished());
+ QVERIFY(dsr.cancel());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(dsr.isActive()); // still cancelling
+ QVERIFY(!dsr.isFinished()); // not finished cancelling
+ QVERIFY(!dsr.start()); // already started.
+ QVERIFY(dsr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(dsr.isFinished());
+ QVERIFY(!dsr.isActive());
+ QVERIFY(dsr.status() == QContactAbstractRequest::Cancelled);
+
+ // verify that the changes were not saved
+ allDefs = cm->detailDefinitions().values();
+ QVERIFY(!allDefs.contains(testDef));
+ QCOMPARE(cm->detailDefinitions().values().size(), originalCount + 1);
+
+ delete cm;
+}
+
+void tst_QContactAsync::relationshipFetch()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QList<QContact> contacts;
+ QList<QContactRelationship> relationships;
+ QVERIFY(prepareModel(uri, cm, contacts, relationships));
+ QContactRelationshipFetchRequest rfr;
+ QVERIFY(rfr.type() == QContactAbstractRequest::RelationshipFetchRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!rfr.isActive());
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start());
+ QVERIFY(!rfr.cancel());
+ QVERIFY(!rfr.waitForFinished());
+ QVERIFY(!rfr.waitForProgress());
+
+ if (!cm->hasFeature(QContactManager::Relationships))
+ {
+ // ensure manager returs errors
+ rfr.setManager(cm);
+ QCOMPARE(rfr.manager(), cm);
+ QVERIFY(!rfr.isActive());
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.cancel());
+ QVERIFY(!rfr.waitForFinished());
+ QVERIFY(!rfr.waitForProgress());
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NotSupportedError);
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ return;
+ }
+
+ // use variables to make code more readable
+ QContactId aId = contacts.at(0).id();
+ QContactId bId = contacts.at(1).id();
+ QContactId cId = contacts.at(2).id();
+ QContactId dId = contacts.at(3).id();
+ QContactId eId = contacts.at(4).id();
+ QContactId fId = contacts.at(5).id();
+ QContactRelationship adRel = relationships.at(0);
+ QContactRelationship aeRel = relationships.at(1);
+ QContactRelationship beRel = relationships.at(2);
+ QContactRelationship ceRel = relationships.at(3);
+ QContactRelationship cfRel = relationships.at(4);
+ QString relType = adRel.relationshipType();
+
+ // "all relationships" retrieval
+ rfr.setManager(cm);
+ QCOMPARE(rfr.manager(), cm);
+ QVERIFY(!rfr.isActive());
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.cancel());
+ QVERIFY(!rfr.waitForFinished());
+ QVERIFY(!rfr.waitForProgress());
+ qRegisterMetaType<QContactRelationshipFetchRequest*>("QContactRelationshipFetchRequest*");
+ QSignalSpy spy(&rfr, SIGNAL(progress(QContactRelationshipFetchRequest*, bool)));
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ QList<QContactRelationship> rels = cm->relationships();
+ QList<QContactRelationship> result = rfr.relationships();
+ QCOMPARE(rels, result);
+
+ // specific relationship type retrieval
+ rfr.setRelationshipType(relType);
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ rels = cm->relationships(relType);
+ result = rfr.relationships();
+ QCOMPARE(rels, result);
+
+ // specific source contact retrieval
+ rfr.setFirst(aId);
+ rfr.setRelationshipType(QString());
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ rels = cm->relationships(aId, QContactRelationshipFilter::First);
+ result = rfr.relationships();
+ QCOMPARE(rels, result);
+
+ // specific participant retrieval #1 - destination participant
+ rfr.setFirst(QContactId());
+ rfr.setParticipant(eId, QContactRelationshipFilter::Second);
+ QVERIFY(rfr.participantRole() == QContactRelationshipFilter::Second);
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ rels = cm->relationships(eId, QContactRelationshipFilter::Second);
+ result = rfr.relationships();
+ QCOMPARE(rels, result);
+
+ // specific participant retrieval #2 - source participant
+ rfr.setFirst(QContactId());
+ rfr.setParticipant(cId, QContactRelationshipFilter::First);
+ QVERIFY(rfr.participantRole() == QContactRelationshipFilter::First);
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ rels = cm->relationships(cId, QContactRelationshipFilter::First);
+ result = rfr.relationships();
+ QCOMPARE(rels, result);
+
+ if (relationships.count() > 4)
+ {
+ // specific participant retrieval #3 - either participant
+ rfr.setFirst(QContactId());
+ rfr.setParticipant(aId, QContactRelationshipFilter::Either);
+ QVERIFY(rfr.participantRole() == QContactRelationshipFilter::Either);
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ rels = cm->relationships(aId); // either role.
+ result = rfr.relationships();
+ QCOMPARE(rels, result);
+ }
+
+ // cancelling
+ rfr.setRelationshipType(QString());
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(rfr.cancel());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(rfr.isActive()); // still cancelling
+ QVERIFY(!rfr.isFinished()); // not finished cancelling
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForFinished());
+ QVERIFY(rfr.error() == QContactManager::NoError);
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Cancelled);
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!rfr.cancel()); // not started
+ QVERIFY(rfr.start());
+ QVERIFY(rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rfr.isFinished());
+ QVERIFY(rfr.cancel());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(rfr.isActive()); // still cancelling
+ QVERIFY(!rfr.isFinished()); // not finished cancelling
+ QVERIFY(!rfr.start()); // already started.
+ QVERIFY(rfr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(rfr.isFinished());
+ QVERIFY(!rfr.isActive());
+ QVERIFY(rfr.status() == QContactAbstractRequest::Cancelled);
+
+ delete cm;
+}
+
+void tst_QContactAsync::relationshipRemove()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QList<QContact> contacts;
+ QList<QContactRelationship> relationships;
+ QVERIFY(prepareModel(uri, cm, contacts, relationships));
+ QContactRelationshipRemoveRequest rrr;
+ QVERIFY(rrr.type() == QContactAbstractRequest::RelationshipRemoveRequest);
+
+ if (!cm->hasFeature(QContactManager::Relationships))
+ {
+ // ensure manager returns error
+ rrr.setFirst(contacts.at(0).id());
+ rrr.setManager(cm);
+ QCOMPARE(rrr.manager(), cm);
+ QVERIFY(!rrr.isActive());
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.cancel());
+ QVERIFY(!rrr.waitForFinished());
+ QVERIFY(!rrr.waitForProgress());
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QVERIFY(rrr.error() == QContactManager::NotSupportedError);
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ return;
+ }
+
+ // use variables to make code more readable
+ QContactId aId = contacts.at(0).id();
+ QContactId bId = contacts.at(1).id();
+ QContactId cId = contacts.at(2).id();
+ QContactId dId = contacts.at(3).id();
+ QContactId eId = contacts.at(4).id();
+ QContactId fId = contacts.at(5).id();
+ QContactRelationship adRel = relationships.at(0);
+ QContactRelationship aeRel = relationships.at(1);
+ QContactRelationship beRel = relationships.at(2);
+ QContactRelationship ceRel = relationships.at(3);
+ QContactRelationship cfRel = relationships.at(4);
+ QString relType = adRel.relationshipType();
+
+ // initial state - not started, no manager.
+ QVERIFY(!rrr.isActive());
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start());
+ QVERIFY(!rrr.cancel());
+ QVERIFY(!rrr.waitForFinished());
+ QVERIFY(!rrr.waitForProgress());
+
+ // specific source, destination and type removal
+ int relationshipCount = cm->relationships().count();
+ rrr.setFirst(adRel.first());
+ rrr.setSecond(adRel.second());
+ rrr.setRelationshipType(adRel.relationshipType());
+ rrr.setManager(cm);
+ qRegisterMetaType<QContactRelationshipRemoveRequest*>("QContactRelationshipRemoveRequest*");
+ QSignalSpy spy(&rrr, SIGNAL(progress(QContactRelationshipRemoveRequest*)));
+ QCOMPARE(rrr.manager(), cm);
+ QVERIFY(!rrr.isActive());
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.cancel());
+ QVERIFY(!rrr.waitForFinished());
+ QVERIFY(!rrr.waitForProgress());
+ QVERIFY(rrr.relationshipType() == adRel.relationshipType());
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QVERIFY(rrr.error() == QContactManager::NoError);
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ QCOMPARE(cm->relationships().count(), relationshipCount-1);
+
+ // remove (asynchronously) a nonexistent relationship - should fail.
+ relationshipCount = cm->relationships().count();
+ rrr.setFirst(bId);
+ rrr.setSecond(aId);
+ rrr.setRelationshipType(relType);
+ rrr.setManager(cm);
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QCOMPARE(rrr.error(), QContactManager::DoesNotExistError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ QCOMPARE(cm->relationships().count(), relationshipCount);
+
+ // specific relationship type plus source removal
+ rrr.setFirst(cId);
+ rrr.setSecond(QContactId());
+ rrr.setRelationshipType(relType);
+ rrr.setManager(cm);
+ QCOMPARE(rrr.manager(), cm);
+ QVERIFY(!rrr.isActive());
+ QVERIFY(!rrr.cancel());
+ QVERIFY(!rrr.waitForFinished());
+ QVERIFY(!rrr.waitForProgress());
+ QVERIFY(rrr.relationshipType() == relType);
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QVERIFY(rrr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ QCOMPARE(cm->relationships(relType, cId, QContactRelationshipFilter::First).size(), 0);
+ QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
+
+ // specific source removal
+ rrr.setFirst(aId);
+ rrr.setSecond(QContactId());
+ rrr.setRelationshipType(QString());
+ rrr.setManager(cm);
+ QCOMPARE(rrr.manager(), cm);
+ QVERIFY(!rrr.isActive());
+ QVERIFY(!rrr.cancel());
+ QVERIFY(!rrr.waitForFinished());
+ QVERIFY(!rrr.waitForProgress());
+ QVERIFY(rrr.relationshipType() == QString());
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QVERIFY(rrr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ QCOMPARE(cm->relationships(aId, QContactRelationshipFilter::First).size(), 0);
+ QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
+
+ // cancelling
+ rrr.setFirst(bId);
+ rrr.setSecond(QContactId());
+ rrr.setRelationshipType(QString());
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(rrr.cancel());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(rrr.isActive()); // still cancelling
+ QVERIFY(!rrr.isFinished()); // not finished cancelling
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QVERIFY(rrr.error() == QContactManager::NoError);
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Cancelled);
+ QVERIFY(cm->relationships(bId).size() != 0); // didn't remove them.
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(rrr.cancel());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(rrr.isActive()); // still cancelling
+ QVERIFY(!rrr.isFinished()); // not finished cancelling
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Cancelled);
+ QVERIFY(cm->relationships(bId).size() != 0); // didn't remove them.
+
+ // specific relationship type removal
+ rrr.setFirst(QContactId());
+ rrr.setSecond(QContactId());
+ rrr.setRelationshipType(relType);
+ rrr.setManager(cm);
+ QCOMPARE(rrr.manager(), cm);
+ QVERIFY(!rrr.isActive());
+ QVERIFY(!rrr.cancel());
+ QVERIFY(!rrr.waitForFinished());
+ QVERIFY(!rrr.waitForProgress());
+ QVERIFY(rrr.relationshipType() == relType);
+ QVERIFY(!rrr.cancel()); // not started
+ QVERIFY(rrr.start());
+ QVERIFY(rrr.isActive());
+ QVERIFY(rrr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rrr.isFinished());
+ QVERIFY(!rrr.start()); // already started.
+ QVERIFY(rrr.waitForFinished());
+ QVERIFY(rrr.error() == QContactManager::NoError);
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rrr.isFinished());
+ QVERIFY(!rrr.isActive());
+
+ QCOMPARE(cm->relationships(relType).size(), 0);
+ cm->relationships(relType); // check that it has already been removed.
+ QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
+
+ delete cm;
+}
+
+void tst_QContactAsync::relationshipSave()
+{
+ QFETCH(QString, uri);
+ QContactManager* cm(0);
+ QList<QContact> contacts;
+ QList<QContactRelationship> relationships;
+ QVERIFY(prepareModel(uri, cm, contacts, relationships));
+ QContactRelationshipSaveRequest rsr;
+ QVERIFY(rsr.type() == QContactAbstractRequest::RelationshipSaveRequest);
+
+ if (!cm->hasFeature(QContactManager::Relationships))
+ {
+ // ensure saving returns errors
+ QContactRelationship rel;
+ rel.setFirst(contacts.at(0).id());
+ rel.setSecond(contacts.at(1).id());
+ rel.setRelationshipType(QContactRelationship::HasManager);
+ QList<QContactRelationship> list;
+ list << rel;
+ rsr.setManager(cm);
+ QCOMPARE(rsr.manager(), cm);
+ QVERIFY(!rsr.isActive());
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(!rsr.cancel());
+ QVERIFY(!rsr.waitForFinished());
+ QVERIFY(!rsr.waitForProgress());
+ rsr.setRelationships(list);
+ QCOMPARE(rsr.relationships(), list);
+ QVERIFY(!rsr.cancel()); // not started
+ QVERIFY(rsr.start());
+ QVERIFY(rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(!rsr.start()); // already started.
+ QVERIFY(rsr.waitForFinished());
+ QVERIFY(rsr.error() == QContactManager::NotSupportedError);
+ QVERIFY(rsr.isFinished());
+ QVERIFY(!rsr.isActive());
+ return;
+ }
+
+ // use variables to make code more readable
+ QContactId aId = contacts.at(0).id();
+ QContactId bId = contacts.at(1).id();
+ QContactId cId = contacts.at(2).id();
+ QContactId dId = contacts.at(3).id();
+ QContactId eId = contacts.at(4).id();
+ QContactId fId = contacts.at(5).id();
+ QContactRelationship adRel = relationships.at(0);
+ QContactRelationship aeRel = relationships.at(1);
+ QContactRelationship beRel = relationships.at(2);
+ QContactRelationship ceRel = relationships.at(3);
+ QContactRelationship cfRel = relationships.at(4);
+ QString relType = adRel.relationshipType();
+
+ // initial state - not started, no manager.
+ QVERIFY(!rsr.isActive());
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(!rsr.start());
+ QVERIFY(!rsr.cancel());
+ QVERIFY(!rsr.waitForFinished());
+ QVERIFY(!rsr.waitForProgress());
+
+ // save a new relationship
+ int originalCount = cm->relationships(bId).size();
+ QContactRelationship testRel;
+ testRel.setFirst(bId);
+ testRel.setSecond(dId);
+ testRel.setRelationshipType(relType);
+ QList<QContactRelationship> saveList;
+ saveList << testRel;
+ rsr.setManager(cm);
+ QCOMPARE(rsr.manager(), cm);
+ QVERIFY(!rsr.isActive());
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(!rsr.cancel());
+ QVERIFY(!rsr.waitForFinished());
+ QVERIFY(!rsr.waitForProgress());
+ qRegisterMetaType<QContactRelationshipSaveRequest*>("QContactRelationshipSaveRequest*");
+ QSignalSpy spy(&rsr, SIGNAL(progress(QContactRelationshipSaveRequest*)));
+ rsr.setRelationships(saveList);
+ QCOMPARE(rsr.relationships(), saveList);
+ QVERIFY(!rsr.cancel()); // not started
+ QVERIFY(rsr.start());
+ QVERIFY(rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(!rsr.start()); // already started.
+ QVERIFY(rsr.waitForFinished());
+ int expectedCount = 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rsr.isFinished());
+ QVERIFY(!rsr.isActive());
+ QList<QContactRelationship> result = rsr.relationships();
+ QVERIFY(result.contains(testRel));
+ QList<QContactRelationship> bRelationships = cm->relationships(relType, bId, QContactRelationshipFilter::First);
+ QVERIFY(bRelationships.contains(testRel));
+ QCOMPARE(cm->relationships(bId).size(), originalCount + 1); // should be one extra
+
+ // save a new relationship
+ testRel.setSecond(fId);
+ saveList.clear();
+ saveList << testRel;
+ rsr.setRelationships(saveList);
+ QCOMPARE(rsr.relationships(), saveList);
+ QVERIFY(!rsr.cancel()); // not started
+ QVERIFY(rsr.start());
+ QVERIFY(rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(!rsr.start()); // already started.
+ QVERIFY(rsr.waitForFinished());
+ expectedCount += 2;
+ QCOMPARE(spy.count(), expectedCount); // active + finished progress signals.
+ QVERIFY(rsr.isFinished());
+ QVERIFY(!rsr.isActive());
+ bRelationships.clear();
+ bRelationships = cm->relationships(relType, bId, QContactRelationshipFilter::First);
+ result = rsr.relationships();
+ QCOMPARE(result, QList<QContactRelationship>() << testRel);
+ QVERIFY(bRelationships.contains(testRel));
+ QCOMPARE(cm->relationships(bId).size(), originalCount + 2); // should now be two extra
+
+ // cancelling
+ testRel.setSecond(bId); // shouldn't get saved (circular anyway)
+ saveList.clear();
+ saveList << testRel;
+ rsr.setRelationships(saveList);
+ QCOMPARE(rsr.relationships(), saveList);
+ QVERIFY(!rsr.cancel()); // not started
+ QVERIFY(rsr.start());
+ QVERIFY(rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(rsr.cancel());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(rsr.isActive()); // still cancelling
+ QVERIFY(!rsr.isFinished()); // not finished cancelling
+ QVERIFY(!rsr.start()); // already started.
+ QVERIFY(rsr.waitForFinished());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(rsr.isFinished());
+ QVERIFY(!rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Cancelled);
+
+ // verify that the changes were not saved
+ QList<QContactRelationship> aRels = cm->relationships(bId, QContactRelationshipFilter::First);
+ QVERIFY(!aRels.contains(testRel));
+ QCOMPARE(cm->relationships(bId).size(), originalCount + 2); // should still only be two extra
+
+ // restart, and wait for progress after cancel.
+ QVERIFY(!rsr.cancel()); // not started
+ QVERIFY(rsr.start());
+ QVERIFY(rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Active);
+ QVERIFY(!rsr.isFinished());
+ QVERIFY(rsr.cancel());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Cancelling);
+ QVERIFY(rsr.isActive()); // still cancelling
+ QVERIFY(!rsr.isFinished()); // not finished cancelling
+ QVERIFY(!rsr.start()); // already started.
+ QVERIFY(rsr.waitForProgress());
+ expectedCount += 3;
+ QCOMPARE(spy.count(), expectedCount); // active + cancelling + cancelled progress signals.
+ QVERIFY(rsr.isFinished());
+ QVERIFY(!rsr.isActive());
+ QVERIFY(rsr.status() == QContactAbstractRequest::Cancelled);
+
+ // verify that the changes were not saved
+ aRels = cm->relationships(bId);
+ QVERIFY(!aRels.contains(testRel));
+ QCOMPARE(cm->relationships(bId).size(), originalCount + 2); // should still only be two extra
+
+ delete cm;
+}
+
+void tst_QContactAsync::maliciousManager()
+{
+ // use the invalid manager: passes all requests through to base class
+ QContactManager cm("invalid");
+ QContactFilter fil; // matches everything
+ QContactFetchRequest cfr;
+ cfr.setFilter(fil);
+ cfr.setManager(&cm);
+ QVERIFY(!cfr.start());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+ QVERIFY(!cfr.start());
+ QVERIFY(!cfr.waitForProgress());
+
+ // ensure that the base class implementation of requestDestroyed() is called
+ QContactFetchRequest *destroyedRequest = new QContactFetchRequest;
+ destroyedRequest->setManager(&cm);
+ destroyedRequest->setFilter(fil);
+ QVERIFY(!destroyedRequest->start());
+ delete destroyedRequest;
+
+ // now use a malicious manager that deliberately calls
+ // incorrect "updateRequest" functions in base class:
+ QContactManager mcm("maliciousplugin");
+ QCOMPARE(mcm.managerName(), QString("maliciousplugin"));
+ QList<QContact> emptyCList;
+ QList<QContactLocalId> emptyIList;
+ QList<QContactDetailDefinition> emptyDList;
+ QStringList emptyDNList;
+ QMap<QString, QContactDetailDefinition> emptyDMap;
+ cfr.setFilter(fil);
+ cfr.setManager(&mcm);
+ QVERIFY(cfr.start());
+ QVERIFY(cfr.cancel());
+ QVERIFY(!cfr.waitForProgress(100));
+ QVERIFY(!cfr.waitForFinished(100));
+ QVERIFY(cfr.start());
+ QVERIFY(!cfr.waitForProgress(100));
+ QVERIFY(!cfr.waitForFinished(100));
+ QVERIFY(cfr.cancel());
+
+ QContactLocalIdFetchRequest cifr;
+ cifr.setFilter(fil);
+ cifr.setManager(&mcm);
+ QVERIFY(cifr.start());
+ QVERIFY(cifr.cancel());
+ QVERIFY(!cifr.waitForProgress(100));
+ QVERIFY(!cifr.waitForFinished(100));
+ QVERIFY(cifr.start());
+ QVERIFY(!cifr.waitForProgress(100));
+ QVERIFY(!cifr.waitForFinished(100));
+ QVERIFY(cifr.cancel());
+
+ QContactRemoveRequest crr;
+ crr.setFilter(fil);
+ crr.setManager(&mcm);
+ QVERIFY(crr.start());
+ QVERIFY(crr.cancel());
+ QVERIFY(!crr.waitForProgress(100));
+ QVERIFY(!crr.waitForFinished(100));
+ QVERIFY(crr.start());
+ QVERIFY(!crr.waitForProgress(100));
+ QVERIFY(!crr.waitForFinished(100));
+ QVERIFY(crr.cancel());
+
+ QContactSaveRequest csr;
+ csr.setContacts(emptyCList);
+ csr.setManager(&mcm);
+ QVERIFY(csr.start());
+ QVERIFY(csr.cancel());
+ QVERIFY(!csr.waitForProgress(100));
+ QVERIFY(!csr.waitForFinished(100));
+ QVERIFY(csr.start());
+ QVERIFY(!csr.waitForProgress(100));
+ QVERIFY(!csr.waitForFinished(100));
+ QVERIFY(csr.cancel());
+
+ QContactDetailDefinitionFetchRequest dfr;
+ dfr.setNames(emptyDNList);
+ dfr.setManager(&mcm);
+ QVERIFY(dfr.start());
+ QVERIFY(dfr.cancel());
+ QVERIFY(!dfr.waitForProgress(100));
+ QVERIFY(!dfr.waitForFinished(100));
+ QVERIFY(dfr.start());
+ QVERIFY(!dfr.waitForProgress(100));
+ QVERIFY(!dfr.waitForFinished(100));
+ QVERIFY(dfr.cancel());
+
+ QContactDetailDefinitionSaveRequest dsr;
+ dsr.setDefinitions(emptyDList);
+ dsr.setManager(&mcm);
+ QVERIFY(dsr.start());
+ QVERIFY(dsr.cancel());
+ QVERIFY(!dsr.waitForProgress(100));
+ QVERIFY(!dsr.waitForFinished(100));
+ QVERIFY(dsr.start());
+ QVERIFY(!dsr.waitForProgress(100));
+ QVERIFY(!dsr.waitForFinished(100));
+ QVERIFY(dsr.cancel());
+
+ QContactDetailDefinitionRemoveRequest drr;
+ drr.setNames(emptyDNList);
+ drr.setManager(&mcm);
+ QVERIFY(drr.start());
+ QVERIFY(drr.cancel());
+ QVERIFY(!drr.waitForProgress(100));
+ QVERIFY(!drr.waitForFinished(100));
+ QVERIFY(drr.start());
+ QVERIFY(!drr.waitForProgress(100));
+ QVERIFY(!drr.waitForFinished(100));
+ QVERIFY(drr.cancel());
+}
+
+void tst_QContactAsync::threadDelivery()
+{
+ QFETCH(QString, uri);
+ QContactManager *cm(0);
+ QVERIFY(prepareModel(uri, cm));
+ m_mainThreadId = cm->thread()->currentThreadId();
+ m_progressSlotThreadId = m_mainThreadId;
+
+ // now perform a fetch request and check that the progress is delivered to the correct thread.
+ QContactFetchRequest *req = new QContactFetchRequest;
+ req->setManager(cm);
+ connect(req, SIGNAL(progress(QContactFetchRequest*,bool)), this, SLOT(progressReceived(QContactFetchRequest*, bool)));
+ req->start();
+
+ int totalWaitTime = 0;
+ while (req->status() != QContactAbstractRequest::Finished) {
+ // ensure that the progress signal was delivered to the main thread.
+ QCOMPARE(m_mainThreadId, m_progressSlotThreadId);
+
+ QTest::qWait(5); // spin until done
+ totalWaitTime += 5;
+
+ // break after 30 seconds.
+ if (totalWaitTime > 30000) {
+ delete req;
+ delete cm;
+ QSKIP("Asynchronous request not complete after 30 seconds!", SkipSingle);
+ }
+ }
+
+ // ensure that the progress signal was delivered to the main thread.
+ QCOMPARE(m_mainThreadId, m_progressSlotThreadId);
+ delete req;
+ delete cm;
+}
+
+void tst_QContactAsync::progressReceived(QContactFetchRequest* request, bool appendOnly)
+{
+ Q_UNUSED(appendOnly);
+ m_progressSlotThreadId = request->thread()->currentThreadId();
+}
+
+void tst_QContactAsync::addManagers()
+{
+ QTest::addColumn<QString>("uri");
+
+ // retrieve the list of available managers
+ QStringList managers = QContactManager::availableManagers();
+
+ // remove ones that we know will not pass
+ managers.removeAll("invalid");
+ managers.removeAll("maliciousplugin");
+ managers.removeAll("testdummy");
+
+ foreach(QString mgr, managers) {
+ QMap<QString, QString> params;
+ QTest::newRow(QString("mgr='%1'").arg(mgr).toLatin1().constData()) << QContactManager::buildUri(mgr, params);
+ if (mgr == "memory") {
+ params.insert("id", "tst_QContactManager");
+ QTest::newRow(QString("mgr='%1', params").arg(mgr).toLatin1().constData()) << QContactManager::buildUri(mgr, params);
+ }
+ }
+}
+
+bool tst_QContactAsync::prepareModel(const QString &managerUri, QContactManager *&cm)
+{
+ QList<QContact> contacts;
+ QList<QContactRelationship> relationships;
+ return prepareModel(managerUri, cm, contacts, relationships);
+}
+
+bool tst_QContactAsync::prepareModel(const QString &managerUri, QContactManager *&cm, QList<QContact> &contacts, QList<QContactRelationship> &relationships)
+{
+ cm = QContactManager::fromUri(managerUri);
+
+ // XXX TODO: ensure that this is the case:
+ // there should be no contacts in the database.
+ QList<QContactLocalId> toRemove = cm->contacts();
+ foreach (const QContactLocalId& removeId, toRemove) {
+ if (!cm->removeContact(removeId))
+ return false;
+ }
+
+ QContact a, b, c, d, e, f;
+ QContactPhoneNumber n;
+ n.setNumber("1");
+ a.saveDetail(&n);
+ n.setNumber("2");
+ b.saveDetail(&n);
+ n.setNumber("3");
+ c.saveDetail(&n);
+ n.setNumber("4");
+ d.saveDetail(&n);
+ n.setNumber("5");
+ e.saveDetail(&n);
+ n.setNumber("6");
+ f.saveDetail(&n);
+
+ QContactUrl url;
+ url.setUrl("http://test.nokia.com");
+ a.saveDetail(&url);
+
+ a.setType(QContactType::TypeGroup);
+ b.setType(QContactType::TypeGroup);
+ c.setType(QContactType::TypeGroup);
+
+ if (!cm->saveContact(&a))
+ return false;
+ if (!cm->saveContact(&b))
+ return false;
+ if (!cm->saveContact(&c))
+ return false;
+ if (!cm->saveContact(&d))
+ return false;
+ if (!cm->saveContact(&e))
+ return false;
+ if (!cm->saveContact(&f))
+ return false;
+
+ contacts.append(a);
+ contacts.append(b);
+ contacts.append(c);
+ contacts.append(d);
+ contacts.append(e);
+ contacts.append(f);
+
+ if (cm->hasFeature(QContactManager::Relationships))
+ {
+ QStringList supportedRelationshipTypes = cm->supportedRelationshipTypes();
+
+ if (cm->hasFeature(QContactManager::ArbitraryRelationshipTypes)) {
+ supportedRelationshipTypes.insert(0, "some-arbitrary-relationship");
+ if (!supportedRelationshipTypes.contains(QContactRelationship::HasManager))
+ supportedRelationshipTypes.append(QContactRelationship::HasManager);
+ if (!supportedRelationshipTypes.contains(QContactRelationship::HasAssistant))
+ supportedRelationshipTypes.append(QContactRelationship::HasAssistant);
+ if (!supportedRelationshipTypes.contains(QContactRelationship::HasSpouse))
+ supportedRelationshipTypes.append(QContactRelationship::HasSpouse);
+ }
+
+ if (supportedRelationshipTypes.count() == 0)
+ return false; // should not happen
+
+ QContactRelationship adRel;
+ adRel.setFirst(a.id());
+ adRel.setSecond(d.id());
+ adRel.setRelationshipType(supportedRelationshipTypes.at(0));
+ if (!cm->saveRelationship(&adRel))
+ return false;
+ relationships.append(adRel);
+
+ QContactRelationship aeRel;
+ aeRel.setFirst(a.id());
+ aeRel.setSecond(e.id());
+ aeRel.setRelationshipType(supportedRelationshipTypes.at(0));
+ if (!cm->saveRelationship(&aeRel))
+ return false;
+ relationships.append(aeRel);
+
+ QContactRelationship beRel;
+ beRel.setFirst(b.id());
+ beRel.setSecond(e.id());
+ beRel.setRelationshipType(supportedRelationshipTypes.at(0));
+ if (!cm->saveRelationship(&beRel))
+ return false;
+ relationships.append(beRel);
+
+ QContactRelationship ceRel;
+ ceRel.setFirst(c.id());
+ ceRel.setSecond(e.id());
+ ceRel.setRelationshipType(supportedRelationshipTypes.at(0));
+ if (!cm->saveRelationship(&ceRel))
+ return false;
+ relationships.append(ceRel);
+
+ QContactRelationship cfRel;
+ cfRel.setFirst(c.id());
+ cfRel.setSecond(f.id());
+ cfRel.setRelationshipType(supportedRelationshipTypes.at(0));
+ if (!cm->saveRelationship(&cfRel))
+ return false;
+ relationships.append(cfRel);
+
+ if (supportedRelationshipTypes.count() > 1)
+ {
+ QContactRelationship daRel;
+ daRel.setFirst(d.id());
+ daRel.setSecond(a.id());
+ daRel.setRelationshipType(supportedRelationshipTypes.at(1));
+ if (!cm->saveRelationship(&daRel))
+ return false;
+ relationships.append(daRel);
+ }
+
+ if (supportedRelationshipTypes.count() > 2)
+ {
+ QContactRelationship adRel2;
+ adRel2.setFirst(a.id());
+ adRel2.setSecond(d.id());
+ adRel2.setRelationshipType(supportedRelationshipTypes.at(2));
+ if (!cm->saveRelationship(&adRel2))
+ return false;
+ relationships.append(adRel2);
+ }
+ }
+
+ return true;
+
+ // TODO: cleanup once test is complete
+}
+
+QTEST_MAIN(tst_QContactAsync)
+#include "tst_qcontactasync.moc"