From 86aa56275c33be673f60f3c2b51d4f719de9315c Mon Sep 17 00:00:00 2001 From: Renato Araujo Oliveira Filho Date: Mon, 19 Jan 2015 17:08:23 -0300 Subject: Add QContactCollection. The QContactCollection class represents a collection of contacts in a manager. This class was implemented based on QOrganizerCollection. Change-Id: I5377f9043a66726182b7a0ed7f40733ffe08b619 Reviewed-by: Matthew Vogt Reviewed-by: Christopher Adams --- tests/auto/contacts/contacts.pro | 1 + .../qcontactasync/unittest/tst_qcontactasync.cpp | 472 +++++++++++++++++++++ .../qcontactcollection/qcontactcollection.pro | 5 + .../qcontactcollection/tst_qcontactcollection.cpp | 397 +++++++++++++++++ .../contacts/qcontactfilter/tst_qcontactfilter.cpp | 94 ++++ .../qcontactmanager/tst_qcontactmanager.cpp | 166 ++++++++ tests/auto/contacts/qmlcontacts/qmlcontacts.pro | 2 + .../testcases/ContactsSavingTestCase.qml | 17 + .../testcases/tst_contact_collection_filter.qml | 161 +++++++ 9 files changed, 1315 insertions(+) create mode 100644 tests/auto/contacts/qcontactcollection/qcontactcollection.pro create mode 100644 tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp create mode 100644 tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml (limited to 'tests') diff --git a/tests/auto/contacts/contacts.pro b/tests/auto/contacts/contacts.pro index fe4cb4865..408b57e44 100644 --- a/tests/auto/contacts/contacts.pro +++ b/tests/auto/contacts/contacts.pro @@ -4,6 +4,7 @@ TEMPLATE = subdirs SUBDIRS += \ qcontact \ qcontactasync \ + qcontactcollection \ qcontactdetail \ qcontactdetails \ qcontactfilter \ diff --git a/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp b/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp index 59a584f83..885606b27 100644 --- a/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp +++ b/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp @@ -56,6 +56,13 @@ QTCONTACTS_USE_NAMESPACE fqcfr2.start(); \ fqcfr3.start(); +/* Define an innocuous request (fetch ie doesn't mutate) to "fill up" any queues */ +#define FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(manager) QContactFetchRequest fqifr1, fqifr2, fqifr3; \ + fqifr1.setManager(manager); fqifr1.start(); \ + fqifr2.setManager(manager); fqifr2.start(); \ + fqifr3.setManager(manager); fqifr3.start(); + + //TESTED_COMPONENT=src/contacts // Unfortunately the plumbing isn't in place to allow cancelling requests at arbitrary points @@ -230,6 +237,13 @@ private slots: void relationshipSave(); void relationshipSave_data() { addManagers(); } + void collectionFetch(); + void collectionFetch_data() { addManagers(); } + void collectionRemove(); + void collectionRemove_data() { addManagers(); } + void collectionSave(); + void collectionSave_data() { addManagers(); } + void maliciousManager(); // uses it's own custom data (manager) void testQuickDestruction(); @@ -245,6 +259,7 @@ private: bool compareContacts(QContact ca, QContact cb); bool containsIgnoringTimestamps(const QList& list, const QContact& c); bool compareIgnoringTimestamps(const QContact& ca, const QContact& cb); + bool containsAllCollectionIds(const QList& target, const QList& ids); QContactManager* prepareModel(const QString& uri); Qt::HANDLE m_mainThreadId; @@ -376,6 +391,18 @@ bool tst_QContactAsync::compareIgnoringTimestamps(const QContact& ca, const QCon return false; } +bool tst_QContactAsync::containsAllCollectionIds(const QList &target, const QList &ids) +{ + bool containsAllIds = true; + foreach (QContactCollectionId id, ids) { + if (!target.contains(id)) { + containsAllIds = false; + break; + } + } + return containsAllIds; +} + void tst_QContactAsync::testDestructor() { QFETCH(QString, uri); @@ -1316,6 +1343,9 @@ void tst_QContactAsync::contactSave() //QCOMPARE(result, expected); // XXX: really, we should use isSuperset() from tst_QContactManager, but this will do for now: QVERIFY(result.first().detail() == nameDetail); + + // check if the contact was saved on default collection + QCOMPARE(result.first().collectionId().toString(), cm->defaultCollection().id().toString()); QCOMPARE(cm->contactIds().size(), originalCount + 1); // update a previously saved contact @@ -2413,6 +2443,443 @@ void tst_QContactAsync::relationshipSave() } } +void tst_QContactAsync::collectionFetch() +{ + QFETCH(QString, uri); + QScopedPointer cm(prepareModel(uri)); + + QContactCollectionFetchRequest cfr; + QVERIFY(cfr.type() == QContactAbstractRequest::CollectionFetchRequest); + + // initial state - not started, no manager. + QVERIFY(!cfr.isActive()); + QVERIFY(!cfr.isFinished()); + QVERIFY(!cfr.start()); + QVERIFY(!cfr.cancel()); + QVERIFY(!cfr.waitForFinished()); + + // retrieve all collections. + cfr.setManager(cm.data()); + QCOMPARE(cfr.manager(), cm.data()); + QVERIFY(!cfr.isActive()); + QVERIFY(!cfr.isFinished()); + QVERIFY(!cfr.cancel()); + QVERIFY(!cfr.waitForFinished()); + qRegisterMetaType("QContactCollectionFetchRequest*"); + QThreadSignalSpy spy(&cfr, SIGNAL(stateChanged(QContactAbstractRequest::State))); + QVERIFY(!cfr.cancel()); // not started + + QVERIFY(cfr.start()); + //QVERIFY(cfr.isFinished() || !cfr.start()); // already started. // thread scheduling means this is untestable + QVERIFY((cfr.isActive() && cfr.state() == QContactAbstractRequest::ActiveState) || cfr.isFinished()); + QVERIFY(cfr.waitForFinished()); + QVERIFY(cfr.isFinished()); + + QVERIFY(spy.count() >= 1); // active + finished progress signals + spy.clear(); + + QList syncCols = cm->collections(); + QList cols = cfr.collections(); + QCOMPARE(cols.size(), syncCols.size()); + for (int i = 0; i < cols.size(); i++) { + QContactCollection curr = cols.at(i); + QVERIFY(syncCols.contains(curr)); + } + + // cancelling + int bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; // attempt to cancel 40 times. If it doesn't work due to threading, bail out. + while (true) { + QVERIFY(!cfr.cancel()); // not started + FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data()); + QVERIFY(cfr.start()); + if (!cfr.cancel()) { + // due to thread scheduling, async cancel might be attempted + // after the request has already finished.. so loop and try again. + spy.clear(); + cfr.waitForFinished(); + bailoutCount -= 1; + if (!bailoutCount) { +// qWarning("Unable to test cancelling due to thread scheduling!"); + bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; + break; + } + continue; + } + + // if we get here, then we are cancelling the request. + QVERIFY(cfr.waitForFinished()); + QVERIFY(cfr.isCanceled()); + + QVERIFY(spy.count() >= 1); // active + cancelled progress signals + spy.clear(); + break; + } + + // restart, and wait for progress after cancel. + while (true) { + QVERIFY(!cfr.cancel()); // not started + FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data()); + QVERIFY(cfr.start()); + if (!cfr.cancel()) { + // due to thread scheduling, async cancel might be attempted + // after the request has already finished.. so loop and try again. + cfr.waitForFinished(); + bailoutCount -= 1; + spy.clear(); + if (!bailoutCount) { + //qWarning("Unable to test cancelling due to thread scheduling!"); + bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; + break; + } + continue; + } + cfr.waitForFinished(); + QVERIFY(spy.count() >= 1); // active + cancelled progress signals + spy.clear(); + QVERIFY(!cfr.isActive()); + QVERIFY(cfr.state() == QContactAbstractRequest::CanceledState); + break; + } +} + +void tst_QContactAsync::collectionRemove() +{ + QFETCH(QString, uri); + QScopedPointer cm(prepareModel(uri)); + QContactCollectionRemoveRequest crr; + QVERIFY(crr.type() == QContactAbstractRequest::CollectionRemoveRequest); + + // initial state - not started, no manager. + QVERIFY(!crr.isActive()); + QVERIFY(!crr.isFinished()); + QVERIFY(!crr.start()); + QVERIFY(!crr.cancel()); + QVERIFY(!crr.waitForFinished()); + + // specific collection set + QContactCollectionId removeId = cm->collections().last().id(); + if (cm->defaultCollection().id() == removeId) + removeId = cm->collections().first().id(); + crr.setCollectionId(removeId); + QVERIFY(crr.collectionIds() == QList() << removeId); + int originalCount = cm->collections().size(); + crr.setManager(cm.data()); + QCOMPARE(crr.manager(), cm.data()); + QVERIFY(!crr.isActive()); + QVERIFY(!crr.isFinished()); + QVERIFY(!crr.cancel()); + QVERIFY(!crr.waitForFinished()); + qRegisterMetaType("QContactCollectionRemoveRequest*"); + QThreadSignalSpy spy(&crr, SIGNAL(stateChanged(QContactAbstractRequest::State))); + QVERIFY(!crr.cancel()); // not started + QVERIFY(crr.start()); + QVERIFY((crr.isActive() &&crr.state() == QContactAbstractRequest::ActiveState) || crr.isFinished()); + //QVERIFY(crr.isFinished() || !crr.start()); // already started. // thread scheduling means this is untestable + QVERIFY(crr.waitForFinished()); + QVERIFY(crr.isFinished()); + + QVERIFY(spy.count() >= 1); // active + finished progress signals + spy.clear(); + + QCOMPARE(cm->collections().size(), originalCount - 1); // should have removed that particular collection. + QVERIFY(crr.error() == QContactManager::NoError); + QVERIFY(crr.errorMap().isEmpty()); + + // remove all collections + QList allCollectionIds; + QList allCollections = cm->collections(); + for (int i = 0; i < allCollections.size(); ++i) + allCollectionIds << allCollections.at(i).id(); + crr.setCollectionIds(allCollectionIds); + + QVERIFY(!crr.cancel()); // not started + QVERIFY(crr.start()); + + QVERIFY((crr.isActive() && crr.state() == QContactAbstractRequest::ActiveState) || crr.isFinished()); + //QVERIFY(crr.isFinished() || !crr.start()); // already started. // thread scheduling means this is untestable + QVERIFY(crr.waitForFinished()); + QVERIFY(crr.isFinished()); + + QVERIFY(cm->collections().size() >= 1); // at least one collection must be left, since default collection cannot be removed. + QVERIFY(spy.count() >= 1); // active + finished progress signals + spy.clear(); + + // remove empty list + QList collectionIdList; + QContactCollectionRemoveRequest crr1; + crr1.setManager(cm.data()); + crr1.setCollectionIds(collectionIdList); + crr1.start(); + crr1.waitForFinished(); + QVERIFY(crr1.isFinished()); + QVERIFY(crr1.error() == QContactManager::NoError); + + // cancelling + QContactCollection temp; + temp.setMetaData(QContactCollection::KeyDescription, "Should not be removed!"); + cm->saveCollection(&temp); + crr.setCollectionId(temp.id()); + + int collectionCount = cm->collections().size(); + int bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; // attempt to cancel 40 times. If it doesn't work due to threading, bail out. + while (true) { + QVERIFY(!crr.cancel()); // not started + FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data()); + QVERIFY(spy.count() == 0); + QVERIFY(crr.start()); + if (!crr.cancel()) { + // due to thread scheduling, async cancel might be attempted + // after the request has already finished.. so loop and try again. + crr.waitForFinished(); + temp.setId(QContactCollectionId()); + if (!cm->saveCollection(&temp)) { + QSKIP("Unable to save temporary item for remove request cancellation test!"); + } + crr.setCollectionId(temp.id()); + bailoutCount -= 1; + if (!bailoutCount) { +// qWarning("Unable to test cancelling due to thread scheduling!"); + bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; + break; + } + spy.clear(); + continue; + } + + // if we get here, then we are cancelling the request. + QVERIFY(crr.waitForFinished()); + QVERIFY(crr.isCanceled()); + QCOMPARE(cm->collections().size(), collectionCount); // temp collection should not have been removed + QList removeCollectionIds; + QList removeCollections = cm->collections(); + for (int i = 0; i < removeCollections.size(); ++i) + removeCollectionIds << removeCollections.at(i).id(); + QVERIFY(containsAllCollectionIds(removeCollectionIds, crr.collectionIds())); + QVERIFY(spy.count() >= 1); // active + cancelled progress signals + spy.clear(); + break; + } + + // restart, and wait for progress after cancel. + while (true) { + QVERIFY(!crr.cancel()); // not started + FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data()); + QVERIFY(crr.start()); + if (!crr.cancel()) { + // due to thread scheduling, async cancel might be attempted + // after the request has already finished.. so loop and try again. + crr.waitForFinished(); + temp.setId(QContactCollectionId()); + if (!cm->saveCollection(&temp)) { + QSKIP("Unable to save temporary item for remove request cancellation test!"); + } + crr.setCollectionId(temp.id()); + bailoutCount -= 1; + if (!bailoutCount) { +// qWarning("Unable to test cancelling due to thread scheduling!"); + bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; + break; + } + spy.clear(); + continue; + } + crr.waitForFinished(); + QVERIFY(crr.isCanceled()); + QCOMPARE(cm->collections().size(), collectionCount); // temp collection should not have been removed + QList removeCollectionIds; + QList removeCollections = cm->collections(); + for (int i = 0; i < removeCollections.size(); ++i) + removeCollectionIds << removeCollections.at(i).id(); + QVERIFY(containsAllCollectionIds(removeCollectionIds, crr.collectionIds())); + QVERIFY(spy.count() >= 1); // active + cancelled progress signals + spy.clear(); + break; + } + + // now clean up our temp collection. + cm->removeCollection(temp.id()); + +} + +void tst_QContactAsync::collectionSave() +{ + QFETCH(QString, uri); + QScopedPointer cm(prepareModel(uri)); + QContactCollectionSaveRequest csr; + QVERIFY(csr.type() == QContactAbstractRequest::CollectionSaveRequest); + + // initial state - not started, no manager. + QVERIFY(!csr.isActive()); + QVERIFY(!csr.isFinished()); + QVERIFY(!csr.start()); + QVERIFY(!csr.cancel()); + QVERIFY(!csr.waitForFinished()); + + // save a new item + int originalCount = cm->collections().size(); + QContactCollection testCollection; + testCollection.setMetaData(QContactCollection::KeyDescription, "test description"); + testCollection.setMetaData(QContactCollection::KeyName, "New collection"); + QList saveList; + saveList << testCollection; + csr.setManager(cm.data()); + QCOMPARE(csr.manager(), cm.data()); + QVERIFY(!csr.isActive()); + QVERIFY(!csr.isFinished()); + QVERIFY(!csr.cancel()); + QVERIFY(!csr.waitForFinished()); + qRegisterMetaType("QContactCollectionSaveRequest*"); + QThreadSignalSpy spy(&csr, SIGNAL(stateChanged(QContactAbstractRequest::State))); + csr.setCollection(testCollection); + QCOMPARE(csr.collections(), saveList); + QVERIFY(!csr.cancel()); // not started + QVERIFY(csr.start()); + + QVERIFY((csr.isActive() && csr.state() == QContactAbstractRequest::ActiveState) || csr.isFinished()); + //QVERIFY(csr.isFinished() || !csr.start()); // already started. // thread scheduling means this is untestable + QVERIFY(csr.waitForFinished()); + QVERIFY(csr.isFinished()); + QVERIFY(spy.count() >= 1); // active + finished progress signals + spy.clear(); + + QList expected = csr.collections(); + QCOMPARE(expected.size(), 1); + QList result; + result << cm->collection(csr.collections().at(0).id()); + + // find the saved one, compare. + foreach (const QContactCollection &col, result) + QVERIFY(col.id() == expected.at(0).id()); + + // update a previously saved collection + QVERIFY(!result.isEmpty()); // make sure that we were able to retrieve the required collection. + testCollection = result.first(); + testCollection.setMetaData(QContactCollection::KeyName, "test name"); + saveList.clear(); + saveList << testCollection; + csr.setCollections(saveList); + QCOMPARE(csr.collections(), saveList); + QVERIFY(!csr.cancel()); // not started + QVERIFY(csr.start()); + + QVERIFY((csr.isActive() && csr.state() == QContactAbstractRequest::ActiveState) || csr.isFinished()); + //QVERIFY(csr.isFinished() || !csr.start()); // already started. // thread scheduling means this is untestable + QVERIFY(csr.waitForFinished()); + + QVERIFY(csr.isFinished()); + QVERIFY(spy.count() >= 1); // active + finished progress signals + spy.clear(); + + expected = csr.collections(); + result.clear(); + result = cm->collections(); + // find the saved one, compare. + foreach (const QContactCollection& col, result) { + if (col.id() == expected.at(0).id()) { + QVERIFY(col == expected.at(0)); // XXX TODO: if we change the semantic so that save merely updates the id...? + } + } + QCOMPARE(cm->collections().size(), originalCount + 1); // ie shouldn't have added an extra one (would be +2) + QVERIFY(csr.error() == QContactManager::NoError); + QVERIFY(csr.errorMap().isEmpty()); + + // save empty list + QList collectionList; + QContactCollectionSaveRequest csr1; + csr1.setManager(cm.data()); + csr1.setCollections(collectionList); + csr1.start(); + csr1.waitForFinished(); + QVERIFY(csr1.isFinished()); + QVERIFY(csr1.error() == QContactManager::NoError); + + // cancelling + QContactCollection temp; + temp.setMetaData(testCollection.metaData()); + temp.setExtendedMetaData("test", "shouldn't be saved"); + saveList.clear(); + saveList << temp; + csr.setCollections(saveList); + + int bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; // attempt to cancel 40 times. If it doesn't work due to threading, bail out. + while (true) { + QVERIFY(!csr.cancel()); // not started + FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data()); + QVERIFY(csr.start()); + if (!csr.cancel()) { + // due to thread scheduling, async cancel might be attempted + // after the request has already finished.. so loop and try again. + csr.waitForFinished(); + saveList = csr.collections(); + if (cm->collections().size() > (originalCount + 1) && !cm->removeCollection(saveList.at(0).id())) { + QSKIP("Unable to remove saved collection to test cancellation of collection save request"); + } + saveList.clear(); + saveList << temp; + csr.setCollections(saveList); + bailoutCount -= 1; + if (!bailoutCount) { +// qWarning("Unable to test cancelling due to thread scheduling!"); + bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; + break; + } + spy.clear(); + continue; + } + + // if we get here, then we are cancelling the request. + QVERIFY(csr.waitForFinished()); + QVERIFY(csr.isCanceled()); + QVERIFY(spy.count() >= 1); // active + cancelled progress signals + spy.clear(); + + // verify that the changes were not saved + expected.clear(); + QList allCollections = cm->collections(); + QVERIFY(!allCollections.contains(temp)); // should NOT contain it since it was cancelled. + QCOMPARE(allCollections.size(), originalCount + 1); + break; + } + // restart, and wait for progress after cancel. + + while (true) { + QVERIFY(!csr.cancel()); // not started + FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data()); + QVERIFY(csr.start()); + if (!csr.cancel()) { + // due to thread scheduling, async cancel might be attempted + // after the request has already finished.. so loop and try again. + csr.waitForFinished(); + saveList = csr.collections(); + if (cm->collections().size() > (originalCount + 1) && !cm->removeCollection(saveList.at(0).id())) { + QSKIP("Unable to remove saved item to test cancellation of item save request"); + } + saveList.clear(); + saveList << temp; + csr.setCollections(saveList); + bailoutCount -= 1; + if (!bailoutCount) { +// qWarning("Unable to test cancelling due to thread scheduling!"); + bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; + break; + } + spy.clear(); + continue; + } + csr.waitForFinished(); // now wait until finished (if it hasn't already). + QVERIFY(csr.isCanceled()); + QVERIFY(spy.count() >= 1); // active + cancelled progress signals + spy.clear(); + + // verify that the changes were not saved + expected.clear(); + QList allCollections = cm->collections(); + QVERIFY(!allCollections.contains(temp)); + QCOMPARE(cm->collections().size(), originalCount + 1); + break; + } +} + void tst_QContactAsync::maliciousManager() { // use the invalid manager: passes all requests through to base class @@ -2655,6 +3122,11 @@ QContactManager* tst_QContactAsync::prepareModel(const QString& managerUri) crb.setRelationshipType(QContactRelationship::IsSameAs()); cm->saveRelationship(&crb); + QContactCollection testCollection; + testCollection.setMetaData(QContactCollection::KeyName, "Test Collection"); + testCollection.setMetaData(QContactCollection::KeyDescription, "test collection"); + cm->saveCollection(&testCollection); + return cm; // TODO: cleanup once test is complete diff --git a/tests/auto/contacts/qcontactcollection/qcontactcollection.pro b/tests/auto/contacts/qcontactcollection/qcontactcollection.pro new file mode 100644 index 000000000..bb6599776 --- /dev/null +++ b/tests/auto/contacts/qcontactcollection/qcontactcollection.pro @@ -0,0 +1,5 @@ +include(../../auto.pri) + +QT += contacts + +SOURCES += tst_qcontactcollection.cpp diff --git a/tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp b/tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp new file mode 100644 index 000000000..d36f36c48 --- /dev/null +++ b/tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Canonical Ltd +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +#include + + +QTCONTACTS_USE_NAMESPACE + +static inline QContactCollectionId makeId(const QString &managerName, uint id) +{ + return QContactCollectionId(QStringLiteral("qtcontacts:%1:").arg(managerName), QByteArray(reinterpret_cast(&id), sizeof(uint))); +} + +class tst_QContactCollection: public QObject +{ +Q_OBJECT + +public: + tst_QContactCollection(); + virtual ~tst_QContactCollection(); + +private slots: + void metaData(); + void compare(); + void idComparison(); + void idHash(); + void idStringFunctions(); + void hash(); + void datastream(); + void traits(); + void idTraits(); +}; + +tst_QContactCollection::tst_QContactCollection() +{ +} + +tst_QContactCollection::~tst_QContactCollection() +{ +} + +void tst_QContactCollection::metaData() +{ + QContactCollection c; + QVERIFY(c.metaData().isEmpty()); + c.setExtendedMetaData(QString(QStringLiteral("test")), 5); + QCOMPARE(c.extendedMetaData(QString(QStringLiteral("test"))).toInt(), 5); + + QMap mdm; + mdm.insert(QContactCollection::KeyName, QString(QStringLiteral("test2"))); + c.setMetaData(mdm); + QCOMPARE(c.metaData(), mdm); + QCOMPARE(c.metaData(QContactCollection::KeyName).toString(), QString(QStringLiteral("test2"))); +} + +void tst_QContactCollection::compare() +{ + QContactCollection c, c2; + QVERIFY(c == c2); + c.setExtendedMetaData(QStringLiteral("test"), 5); + QVERIFY(c != c2); + c2.setExtendedMetaData(QStringLiteral("test"), 5); + QVERIFY(c == c2); + + QMap mdm; + mdm.insert(QContactCollection::KeyName, QStringLiteral("test2")); + c.setMetaData(mdm); + QVERIFY(c != c2); + c2.setMetaData(mdm); + QVERIFY(c == c2); + + c2 = QContactCollection(); + QVERIFY(c != c2); + c2 = c; + QVERIFY(c == c2); + + c.setId(makeId(QStringLiteral("a"), 1)); + QVERIFY(c != c2); + c2.setId(makeId(QStringLiteral("a"), 1)); + QVERIFY(c == c2); + c.setId(makeId(QStringLiteral("b"), 1)); + QVERIFY(c != c2); + c2.setId(c.id()); + QVERIFY(c == c2); + c.setId(makeId(QStringLiteral("b"), 2)); +} + +void tst_QContactCollection::idComparison() +{ + QContactCollectionId id1(makeId("a", 1)); + QContactCollectionId id2(makeId("a", 1)); + QVERIFY(!(id1 < id2)); + QVERIFY(!(id2 < id1)); + QVERIFY(id1 == id2); + + QContactCollectionId id3(makeId("a", 2)); + QContactCollectionId id4(makeId("b", 1)); + QContactCollectionId id5(makeId("b", 2)); + QVERIFY((((id1 < id3) && !(id3 < id1)) || ((id3 < id1) && !(id1 < id3))) && (id1 != id3)); + QVERIFY((((id1 < id4) && !(id4 < id1)) || ((id4 < id1) && !(id1 < id4))) && (id1 != id4)); + QVERIFY((((id3 < id4) && !(id4 < id3)) || ((id4 < id3) && !(id3 < id4))) && (id3 != id4)); + QVERIFY((((id1 < id5) && !(id5 < id1)) || ((id5 < id1) && !(id1 < id5))) && (id3 != id4)); + + QContactCollectionId id6; + QContactCollectionId id7(QString(), "1"); + QContactCollectionId id8(QString(), "2"); + QContactCollectionId id9(QStringLiteral("qtcontacts:basic:"), QByteArray()); + QVERIFY(id6.isNull()); + QVERIFY(id7.isNull()); + QVERIFY(id8.isNull()); + QVERIFY(id9.isNull()); + QVERIFY(id6 == id7); + QVERIFY(!(id6 < id7)); + QVERIFY(id7 == id6); + QVERIFY(!(id7 < id6)); + QVERIFY(id7 == id8); + QVERIFY(!(id7 < id8)); + QVERIFY(id8 == id7); + QVERIFY(!(id9 < id8)); + QVERIFY(id8 == id9); + QVERIFY(!(id8 < id9)); + QVERIFY(id9 == id8); + QVERIFY(!(id9 < id8)); + + QVERIFY(!(id1 == id6)); + QVERIFY(!(id1 < id6)); + QVERIFY(id6 < id1); + QVERIFY(!(id1 == id7)); + QVERIFY(!(id1 < id7)); + QVERIFY(id7 < id1); + QVERIFY(!(id1 == id8)); + QVERIFY(!(id1 < id8)); + QVERIFY(id8 < id1); + QVERIFY(!(id1 == id9)); + QVERIFY(!(id1 < id9)); + QVERIFY(id9 < id1); +} + +void tst_QContactCollection::idHash() +{ + QContactCollectionId id1(makeId("a", 1)); + QContactCollectionId id2(makeId("a", 1)); + QContactCollectionId id3(makeId("b", 1)); + QContactCollectionId id4(makeId("a", 2)); + // note that the hash function ignores the managerUri + QCOMPARE(qHash(id1), qHash(id2)); + QCOMPARE(qHash(id1), qHash(id3)); + QVERIFY(qHash(id1) != qHash(id4)); + + QSet set; + set.insert(id1); + set.insert(id2); + set.insert(id3); + set.insert(id4); + QCOMPARE(set.size(), 3); +} + +void tst_QContactCollection::idStringFunctions() +{ + // TODO: review test + QContactCollectionId id1(makeId("a", 1)); + QContactCollectionId id2(makeId("a", 1)); + QContactCollectionId id3(makeId("b", 1)); + QContactCollectionId id4(makeId("a", 2)); + QVERIFY(qHash(id1) == qHash(id2)); + QVERIFY(qHash(id1) != qHash(id4)); + + // note that the toString and fromString functions are + // engine and id specific. This test merely checks that + // the API is hooked up correctly. + + QVERIFY(id1.toString() == id2.toString()); + QVERIFY(id1.toString() != id3.toString()); + QVERIFY(id1.toString() != id4.toString()); + QVERIFY(id3.toString() != id4.toString()); + + // this should "work" -- string of the correct format + const uint numericId2 = 2u; + const QByteArray localId2 = QByteArray(reinterpret_cast(&numericId2), sizeof(uint)); + QString prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString("::") + localId2.toHex(); + QContactCollectionId rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid == id4); + QVERIFY(rebuiltid.localId() == id4.localId()); + + // this string has the right format and one parameter, but requires a working backend + prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + QString("key=value") + QString(":") + localId2.toHex(); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid != id4); + QVERIFY(rebuiltid.localId() == id4.localId()); + + // this string has the right format and some parameters, but requires a working backend + prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + QString("key=value&key2=value2") + QString(":") + localId2.toHex(); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid != id4); + QVERIFY(rebuiltid.localId() == id4.localId()); + + // this string has the right format but misses the value for a parameter + prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + QString("key=value&key2=") + QString(":") + localId2.toHex(); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid != id4); + QVERIFY(rebuiltid.localId() == id4.localId()); + + // this string misses a field (the parameters) + prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + localId2.toHex(); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null. + + // this string misses two fields (params plus manager uri) + prebuiltidstring = QString("qtcontacts") + QString(":") + QString::number(2); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null. + + // this string misses the prefix (qtorganizer) + prebuiltidstring = QString("notorganizer") + QString(":") + QString("a") + QString("::") + localId2.toHex(); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null. + + // this string misses the manager uri + prebuiltidstring = QString("notorganizer") + QString(":::") + localId2.toHex(); + rebuiltid = QContactCollectionId::fromString(prebuiltidstring); + QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null. +} + +void tst_QContactCollection::hash() +{ + // TODO: review tests + QContactCollectionId id(makeId("a", 1)); + QContactCollection c1; + c1.setId(id); + c1.setExtendedMetaData("key", "value"); + QContactCollection c2; + c2.setId(id); + c2.setExtendedMetaData("key", "value"); + QContactCollection c3; + c3.setId(id); + c3.setExtendedMetaData("key", "another value"); + QContactCollection c4; // no details + c4.setId(id); + QContactCollection c5; + c5.setId(id); + c5.setExtendedMetaData("key", "value"); + QVERIFY(qHash(c1) == qHash(c2)); + QVERIFY(qHash(c1) != qHash(c3)); + QVERIFY(qHash(c1) != qHash(c4)); + QVERIFY(qHash(c1) == qHash(c5)); +} + +void tst_QContactCollection::datastream() +{ + // collection datastreaming + QByteArray buffer; + QContactCollection collectionIn; + collectionIn.setExtendedMetaData("key", "value"); + QContactCollection collectionOut; + QContactCollectionId originalId; + + // first, stream an item with a complete id + { + QDataStream stream1(&buffer, QIODevice::WriteOnly); + QContactManager om("memory"); + QVERIFY(om.saveCollection(&collectionIn)); // fill in its ID + originalId = collectionIn.id(); + stream1 << collectionIn; + QVERIFY(buffer.size() > 0); + QDataStream stream2(buffer); + stream2 >> collectionOut; + QCOMPARE(collectionOut, collectionIn); // can use QCOMPARE for collections, since no detail keys. + } + + // second, stream an item with an id with the mgr uri set, local id null + { + QDataStream stream1(&buffer, QIODevice::WriteOnly); + collectionIn.setId(QContactCollectionId()); + stream1 << collectionIn; + QVERIFY(buffer.size() > 0); + QDataStream stream2(buffer); + stream2 >> collectionOut; + QCOMPARE(collectionOut, collectionIn); // can use QCOMPARE for collections, since no detail keys. + } + + // third, stream an item with a null id + { + QDataStream stream1(&buffer, QIODevice::WriteOnly); + collectionIn.setId(QContactCollectionId()); + stream1 << collectionIn; + QVERIFY(buffer.size() > 0); + QDataStream stream2(buffer); + stream2 >> collectionOut; + QVERIFY(collectionOut.metaData() == collectionIn.metaData()); + QVERIFY(collectionOut.id() == collectionIn.id()); // should both be null ids. + } + + // id datastreaming + buffer.clear(); + QContactCollectionId inputId; + QContactCollectionId outputId; + + // first, stream the whole id (mgr uri set, local id set) + { + inputId = originalId; + QString serializedId = inputId.toString(); + outputId = QContactCollectionId::fromString(serializedId); + QCOMPARE(inputId, outputId); + + inputId = originalId; + buffer.clear(); + QDataStream stream1(&buffer, QIODevice::WriteOnly); + stream1 << inputId; + QVERIFY(buffer.size() > 0); + QDataStream stream2(buffer); + stream2 >> outputId; + QCOMPARE(inputId, outputId); + } + + // second, stream a null id + { + inputId = QContactCollectionId(); + QString serializedId = inputId.toString(); + outputId = QContactCollectionId::fromString(serializedId); + QCOMPARE(inputId, outputId); + + inputId = QContactCollectionId(); + buffer.clear(); + QDataStream stream1(&buffer, QIODevice::WriteOnly); + stream1 << inputId; + QVERIFY(buffer.size() > 0); + QDataStream stream2(buffer); + stream2 >> outputId; + QCOMPARE(inputId, outputId); + } +} + +void tst_QContactCollection::traits() +{ + QCOMPARE(sizeof(QContactCollection), sizeof(void *)); + QVERIFY(QTypeInfo::isComplex); + QVERIFY(!QTypeInfo::isStatic); + QVERIFY(!QTypeInfo::isLarge); + QVERIFY(!QTypeInfo::isPointer); + QVERIFY(!QTypeInfo::isDummy); +} + +void tst_QContactCollection::idTraits() +{ + QCOMPARE(sizeof(QContactCollectionId), 2*sizeof(void *)); + QVERIFY(QTypeInfo::isComplex); + QVERIFY(!QTypeInfo::isStatic); + QVERIFY(QTypeInfo::isLarge); + QVERIFY(!QTypeInfo::isPointer); + QVERIFY(!QTypeInfo::isDummy); +} + +QTEST_MAIN(tst_QContactCollection) +#include "tst_qcontactcollection.moc" diff --git a/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp b/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp index e347c3fdd..4df9a25f3 100644 --- a/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp +++ b/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp @@ -55,6 +55,11 @@ static inline QContactId makeId(const QString &managerName, uint id) return QContactId(QStringLiteral("qtcontacts:basic%1:").arg(managerName), QByteArray(reinterpret_cast(&id), sizeof(uint))); } +static inline QContactCollectionId makeCollectionId(uint id) +{ + return QContactCollectionId(QStringLiteral("qtcontacts:basic:"), QByteArray(reinterpret_cast(&id), sizeof(uint))); +} + class tst_QContactFilter : public QObject { Q_OBJECT @@ -81,9 +86,12 @@ private slots: void canonicalizedFilter_data(); void testFilter(); void testFilter_data(); + void collectionFilter(); void datastream(); void datastream_data(); + void testDebugStreamOut(); + void testDebugStreamOut_data(); void traits(); }; @@ -1210,6 +1218,40 @@ void tst_QContactFilter::testFilter_data() } } +void tst_QContactFilter::collectionFilter() +{ + QContactCollectionFilter icf; + + QVERIFY(icf.collectionIds().isEmpty()); + + QContactCollectionId id1 = makeCollectionId(5); + QContactCollectionId id2 = makeCollectionId(6); + QContactCollectionId id3 = makeCollectionId(7); + QContactCollectionId id4 = makeCollectionId(12); + QSet ids; + ids << id1 << id2 << id3; + + icf.setCollectionIds(ids); + QVERIFY(icf.collectionIds() == ids); + + icf.setCollectionId(id4); + ids.clear(); + ids << id4; + QVERIFY(icf.collectionIds() == ids); + + QContactCollectionFilter icf2; + icf2 = icf; + QVERIFY(icf2.collectionIds() == ids); + + QContactFilter fil; + fil = icf; + QVERIFY(fil.type() == QContactFilter::CollectionFilter); + + QContactCollectionFilter icf3(fil); + QVERIFY(fil.type() == QContactFilter::CollectionFilter); + QVERIFY(icf3.collectionIds() == ids); +} + void tst_QContactFilter::datastream() { QFETCH(QContactFilter, filterIn); @@ -1286,6 +1328,58 @@ void tst_QContactFilter::datastream_data() } } +void tst_QContactFilter::testDebugStreamOut() +{ + QFETCH(QContactFilter, filterIn); + QFETCH(QString, messageExpected); + + QTest::ignoreMessage(QtDebugMsg, messageExpected.toUtf8()); + qDebug() << filterIn; +} + +void tst_QContactFilter::testDebugStreamOut_data() +{ + QTest::addColumn("filterIn"); + QTest::addColumn("messageExpected"); + + { + QContactCollectionFilter filter; + QContactCollectionId id1 = makeCollectionId(5); + QContactCollectionId id2 = makeCollectionId(6); + QContactCollectionId id3 = makeCollectionId(7); + QContactCollectionId id4 = makeCollectionId(12); + QSet ids; + ids << id1 << id2 << id3; + filter.setCollectionIds(ids); + // Testing method setCollectionIds + QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::05000000), QContactCollectionId(qtcontacts:basic::06000000), QContactCollectionId(qtcontacts:basic::07000000))))"; + + filter.setCollectionId(id2); + // Testing method setCollectionId (and the related clearing of the collection) + QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::06000000))))"; + filter.setCollectionId(id4); + // Testing again method setCollectionId (and the related clearing of the collection) + QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))"; + ids.clear(); + ids << id4; + // Testing again method setCollectionIds + QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))"; + + QContactCollectionFilter filter2; + filter2 = filter; + // Testing again method setCollectionIds on the copied filter + QTest::newRow("collection") << (QContactFilter)filter2 << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))"; + + QContactFilter fil; + fil = filter; + // Testing that the assignment/conversion went fine + QTest::newRow("collection") << (QContactFilter)fil << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))"; + + QContactCollectionFilter filter3(fil); + QTest::newRow("collection") << (QContactFilter)filter3 << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))"; + } +} + void tst_QContactFilter::traits() { QCOMPARE(sizeof(QContactFilter), sizeof(void *)); diff --git a/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp b/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp index 7e7f8d0a0..94395c859 100644 --- a/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp +++ b/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp @@ -150,6 +150,10 @@ private slots: void contactType(); void lateDeletion(); void compareVariant(); + void createCollection(); + void modifyCollection(); + void removeCollection(); + void saveContactIntoCollections(); #if defined(USE_VERSIT_PLZ) void partialSave(); @@ -190,6 +194,10 @@ private slots: void lateDeletion_data() {addManagers();} void testInterSectionOfIdFilters_data() {addManagers();} void testInterSectionOfIdAndDetailFilters_data() {addManagers();} + void createCollection_data() {addManagers();} + void modifyCollection_data() {addManagers();} + void removeCollection_data() {addManagers();} + void saveContactIntoCollections_data() {addManagers();} }; // Helper class that connects to a signal on ctor, and disconnects on dtor @@ -1474,15 +1482,23 @@ void tst_QContactManager::memoryManager() nc.setLastName("Civilian"); c.saveDetail(&nc); m1.saveContact(&c); + + // reset ids c.setId(QContactId()); + c.setCollectionId(QContactCollectionId()); + QContact c2; QContactName nc2 = c2.detail(QContactName::Type); c2 = c; nc2.setMiddleName("Public"); c2.saveDetail(&nc2); + m2.saveContact(&c2); // save c2 first; c will be given a higher id m2.saveContact(&c); // save c to m2 + + // reset ids c.setId(QContactId()); + c.setCollectionId(QContactCollectionId()); nc.setSuffix("MD"); c.saveDetail(&nc); m3.saveContact(&c); @@ -1871,6 +1887,7 @@ void tst_QContactManager::signalEmission() qRegisterMetaType("QContactId"); qRegisterMetaType >("QList"); qRegisterMetaType >("QList"); + QSignalSpy spyCA(m1.data(), SIGNAL(contactsAdded(QList))); QSignalSpy spyCM(m1.data(), SIGNAL(contactsChanged(QList, QList))); QSignalSpy spyCR(m1.data(), SIGNAL(contactsRemoved(QList))); @@ -1879,8 +1896,10 @@ void tst_QContactManager::signalEmission() QTestSignalSink cmsink(m1.data(), SIGNAL(contactsChanged(QList, QList))); QTestSignalSink crsink(m1.data(), SIGNAL(contactsRemoved(QList))); + QList args; QList arg; + QList collectionIdList; QContact c; QList batchAdd; QList batchRemove; @@ -3209,6 +3228,153 @@ void tst_QContactManager::compareVariant() QVERIFY((comparison + expected) == 0); } +void tst_QContactManager::createCollection() +{ + QFETCH(QString, uri); + QScopedPointer cm(QContactManager::fromUri(uri)); + + qRegisterMetaType >("QList"); + QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList))); + QByteArray collectionName = QUuid::createUuid().toByteArray(); + + // create collection + { + QContactCollection col; + col.setMetaData(QContactCollection::KeyName, collectionName); + QVERIFY(cm->saveCollection(&col)); + } + + // check "collectionsAdded" signal + QCOMPARE(collectionsAddedSpy.count(), 1); + QList ids = collectionsAddedSpy.takeFirst().at(0).value >(); + QCOMPARE(ids.count(), 1); + + // query for new collection + { + QContactCollection col = cm->collection(ids.at(0)); + QVERIFY(!col.id().isNull()); + QCOMPARE(col.id().toString(), ids.at(0).toString()); + QCOMPARE(col.metaData(QContactCollection::KeyName).toByteArray(), collectionName); + } +} + +void tst_QContactManager::modifyCollection() +{ + QFETCH(QString, uri); + QScopedPointer cm(QContactManager::fromUri(uri)); + + qRegisterMetaType >("QList"); + QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList))); + QSignalSpy collectionsChangedSpy(cm.data(), SIGNAL(collectionsChanged(QList))); + + QContactCollectionId colId; + QByteArray collectionName = QUuid::createUuid().toByteArray(); + + // save a new collection + { + QContactCollection col; + col.setMetaData(QContactCollection::KeyName, collectionName); + QVERIFY(cm->saveCollection(&col)); + QTRY_COMPARE(collectionsAddedSpy.count(), 1); + colId = col.id(); + QVERIFY(!colId.isNull()); + } + + // edit collection + { + QCOMPARE(collectionsChangedSpy.count(), 0); + QContactCollection col = cm->collection(colId); + QByteArray newCollectionName = QUuid::createUuid().toByteArray(); + col.setMetaData(QContactCollection::KeyName, newCollectionName); + QVERIFY(cm->saveCollection(&col)); + + // check signal "collectionsChanged" fired contains the collection id + QTRY_COMPARE(collectionsChangedSpy.count(), 1); + QList ids = collectionsChangedSpy.takeFirst().at(0).value >(); + QCOMPARE(ids.at(0).toString(), colId.toString()); + + // check if the collection name was updated + QContactCollection col2 = cm->collection(colId); + QCOMPARE(col2.metaData(QContactCollection::KeyName).toByteArray(), newCollectionName); + } +} + +void tst_QContactManager::removeCollection() +{ + QFETCH(QString, uri); + QScopedPointer cm(QContactManager::fromUri(uri)); + + qRegisterMetaType >("QList"); + QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList))); + QSignalSpy collectionsRemovedSpy(cm.data(), SIGNAL(collectionsRemoved(QList))); + + QContactCollectionId colId; + + // save a new collection + { + QContactCollection col; + QByteArray collectionName = QUuid::createUuid().toByteArray(); + col.setMetaData(QContactCollection::KeyName, collectionName); + QVERIFY(cm->saveCollection(&col)); + QTRY_COMPARE(collectionsAddedSpy.count(), 1); + colId = col.id(); + } + QList collections = cm->collections(); + + // remove collection + cm->removeCollection(colId); + + // check "collectionsRemoved" signal + QTRY_COMPARE(collectionsRemovedSpy.count(), 1); + QList ids = collectionsRemovedSpy.takeFirst().at(0).value >(); + QCOMPARE(ids.at(0).toString(), colId.toString()); + + + // check if the correct collection was removed + QList collectionsAfterRemoval = cm->collections(); + QCOMPARE(collections.count() - 1, collectionsAfterRemoval.count()); + Q_FOREACH (const QContactCollection &col, collectionsAfterRemoval) { + collections.removeAll(col); + } + QCOMPARE(collections.count(), 1); + QCOMPARE(collections.at(0).id().toString(), colId.toString()); +} + +void tst_QContactManager::saveContactIntoCollections() +{ + QFETCH(QString, uri); + QScopedPointer cm(QContactManager::fromUri(uri)); + + qRegisterMetaType >("QList"); + QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList))); + QByteArray collectionName = QUuid::createUuid().toByteArray(); + QContactCollectionId colId; + QContactId cId; + + // create collection + { + QContactCollection col; + col.setMetaData(QContactCollection::KeyName, collectionName); + QVERIFY(cm->saveCollection(&col)); + QTRY_COMPARE(collectionsAddedSpy.count(), 1); + colId = col.id(); + } + + // create contact + { + QContact c = createContact("Alice", "Last", "12345"); + c.setCollectionId(colId); + cm->saveContact(&c); + cId = c.id(); + } + + // query new contact and check for collection + { + QContact c = cm->contact(cId); + QCOMPARE(c.collectionId().toString(), colId.toString()); + } +} + void tst_QContactManager::compareVariant_data() { QTest::addColumn("a"); diff --git a/tests/auto/contacts/qmlcontacts/qmlcontacts.pro b/tests/auto/contacts/qmlcontacts/qmlcontacts.pro index 540543d76..0a9187726 100644 --- a/tests/auto/contacts/qmlcontacts/qmlcontacts.pro +++ b/tests/auto/contacts/qmlcontacts/qmlcontacts.pro @@ -12,8 +12,10 @@ OTHER_FILES += \ testcases/ContactsSavingTestCase.qml \ testcases/ContactsSignalingTestCase.qml \ testcases/ContactsTestHelper.qml \ + testcases/tst_collection.qml \ testcases/tst_contact_add_detail.qml \ testcases/tst_contact_addresses.qml \ + testcases/tst_contact_collection_filter.qml \ testcases/tst_contact_detail_access.qml \ testcases/tst_contactdetail.qml \ testcases/tst_contact_emails.qml \ diff --git a/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml b/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml index bc2911178..b5e2ded90 100644 --- a/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml +++ b/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml @@ -48,6 +48,7 @@ TestCase { id: contactsSavingTestCase property SignalSpy spy + property SignalSpy collectionSpy property bool debug: false ContactsTestConfiguration { @@ -69,6 +70,15 @@ TestCase { contactsSavingTestCase); spy.target = model; spy.signalName = "contactsChanged"; + + collectionSpy = Qt.createQmlObject( + "import QtTest 1.0;" + + "SignalSpy {" + + "}", + contactsSavingTestCase); + collectionSpy.target = model + collectionSpy.signalName = "collectionsChanged" + return spy; } @@ -83,6 +93,13 @@ TestCase { spy.wait(); } + // Verify that the collectionsChanged signal is emitted + function waitForCollectionsChanged() { + logDebug("waitForCollectionsChanged"); + collectionSpy.wait(); + } + + // Wait until duration has elapsed, or the contactsChanged signal is emitted function waitUntilContactsChanged(duration) { logDebug("waitUntilContactsChanged"); diff --git a/tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml b/tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml new file mode 100644 index 000000000..074adb52a --- /dev/null +++ b/tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Canonical Ltd +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtContacts 5.0 + +ContactsSavingTestCase { + id: testcase + name: "Contacts collection filter test" + + property string defaultCollectionId: "" + + ContactModel { + id: model + manager: getManagerUnderTest() + autoUpdate: true + } + + Collection { + id: testCollection + name: 'My collection filter test' + description: 'collection filter test' + } + + Contact { + id: contact1; + Name { + firstName: "A" + } + PhoneNumber { + number: "1111111111" + } + } + + Contact { + id: contact2; + Name { + firstName: "B" + } + PhoneNumber { + number: "2222222222" + } + } + + Contact { + id: contact3; + Name { + firstName: "John Joe" + } + PhoneNumber { + number: "3333333333" + } + } + + function createCollectionFilter(ids) + { + var filter = Qt.createQmlObject( + "import QtContacts 5.0;" + + "CollectionFilter {}", + testcase); + + filter.ids = ids + return filter; + } + + function initTestCase() { + initTestForModel(model); + waitUntilContactsChanged(); + compare(model.collections.length, 1); + defaultCollectionId = model.collections[0].collectionId + // The wait is needed so the model is populated + // (e.g. with garbage left from previous test runs) + // before cleanup() is called. + emptyContacts(model); + model.saveCollection(testCollection) + waitForCollectionsChanged(); + compare(model.collections.length, 2); + model.saveContact(contact1); + waitForContactsChanged(); + compare(contact1.collectionId, defaultCollectionId); + contact2.collectionId = testCollection.collectionId + model.saveContact(contact2); + waitForContactsChanged(); + contact3.collectionId = testCollection.collectionId + model.saveContact(contact3); + waitForContactsChanged(); + compare(model.contacts.length, 3); + } + + function test_collectionFilter(data) { + var filterDefaultCollection = createCollectionFilter([defaultCollectionId]); + model.filter = filterDefaultCollection; + waitForContactsChanged(); + compare(model.contacts.length, 1); + + var filterOnlyNewCollection = createCollectionFilter([testCollection.collectionId]); + model.filter = filterOnlyNewCollection; + waitForContactsChanged(); + compare(model.contacts.length, 2); + + var filterNewCollectionAndDefaultCollection = createCollectionFilter([defaultCollectionId, testCollection.collectionId]) + model.filter = filterNewCollectionAndDefaultCollection; + waitForContactsChanged(); + compare(model.contacts.length, 3); + + var filterEmpty = createCollectionFilter([]) + model.filter = filterEmpty; + waitForContactsChanged(); + compare(model.contacts.length, 0); + + var filterValidAndInvalidIds = createCollectionFilter([defaultCollectionId, "12345678", testCollection.collectionId]) + model.filter = filterValidAndInvalidIds; + waitForContactsChanged(); + compare(model.contacts.length, 3); + + var filterWithInvalidId = createCollectionFilter(["12345678"]) + model.filter = filterWithInvalidId; + waitForContactsChanged(); + compare(model.contacts.length, 0); + } +} -- cgit v1.2.3