1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#define QT_STATICPLUGIN
35#include <QtTest/QtTest>
36
37#ifdef INCLUDE_TESTACTIONS
38#include <QServiceManager>
39#endif
40#include <QtContacts>
41#include "qcontactmanagerdataholder.h" //QContactManagerDataHolder
42
43#include <QLocale>
44#ifdef Q_OS_UNIX
45#include <locale.h>
46#endif
47
48//TESTED_COMPONENT=src/contacts
49
50// Q_ASSERT replacement, since we often run in release builds
51#define Q_FATAL_VERIFY(statement) \
52do { \
53 if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \
54 qFatal("severe failure encountered, test cannot continue"); \
55} while (0)
56
57QTCONTACTS_USE_NAMESPACE
58/*
59 * This test is mostly just for testing sorting and filtering -
60 * having it in tst_QContactManager makes maintenance more
61 * difficult!
62 */
63
64Q_DECLARE_METATYPE(QVariant)
65Q_DECLARE_METATYPE(QContactManager*)
66Q_DECLARE_METATYPE(QContactDetail::DetailType)
67
68/*
69 * Global variables:
70 * These are the definition and field names used by the actions for their matching.
71 */
72QMap<QString, QPair<QContactDetail::DetailType, int> > defAndFieldNamesForTypeForActions;
73
74namespace {
75
76bool validDetailType(const QPair<QContactDetail::DetailType, int> &pair)
77{
78 return pair.first != QContactDetail::TypeUndefined;
79}
80
81bool validDetailField(const QPair<QContactDetail::DetailType, int> &pair)
82{
83 return pair.first != QContactDetail::TypeUndefined && pair.second != -1;
84}
85
86}
87
88/*
89 * We use this code to compare the output and expected lists of filtering
90 * where no sort order is implied.
91 * TODO: use this instead of QCOMPARE in the various filtering tests!
92 */
93#define QCOMPARE_UNSORTED(output, expected) if (output.size() != expected.size()) { \
94 QCOMPARE(output, expected); \
95 } else { \
96 for (int i = 0; i < output.size(); i++) { \
97 if (!expected.contains(output.at(i))) { \
98 QCOMPARE(output, expected); \
99 } \
100 } \
101 }
102
103class tst_QContactManagerFiltering : public QObject
104{
105Q_OBJECT
106
107public:
108 tst_QContactManagerFiltering();
109 virtual ~tst_QContactManagerFiltering();
110
111private:
112 void dumpContactDifferences(const QContact& a, const QContact& b);
113 void dumpContact(const QContact &c);
114 void dumpContacts();
115 bool isSuperset(const QContact& ca, const QContact& cb);
116
117 QList<QContactId> prepareModel(QContactManager* cm); // add the standard contacts
118
119 QString convertIds(QList<QContactId> allIds, QList<QContactId> ids, QChar minimumContact = 'a', QChar maximumContact = 'z'); // convert back to "abcd"
120 QContact createContact(QContactManager* cm, QContactType::TypeValues type, const QString &name);
121
122 QMap<QContactManager*, QMap<QString, QPair<QContactDetail::DetailType, int> > > defAndFieldNamesForTypePerManager;
123 QMultiMap<QContactManager*, QContactId> contactsAddedToManagers;
124 QList<QContactManager*> managers;
125 QScopedPointer<QContactManagerDataHolder> managerDataHolder;
126
127 QTestData& newMRow(const char *tag, QContactManager *cm);
128
129private slots:
130
131 void initTestCase();
132 void cleanupTestCase();
133
134 void rangeFiltering(); // XXX should take all managers
135 void rangeFiltering_data();
136
137 void detailStringFiltering(); // XXX should take all managers
138 void detailStringFiltering_data();
139
140 void detailPhoneNumberFiltering();
141 void detailPhoneNumberFiltering_data();
142
143#ifdef INCLUDE_TESTACTIONS
144 void actionPlugins();
145 void actionFiltering();
146 void actionFiltering_data();
147#endif
148
149 void detailVariantFiltering();
150 void detailVariantFiltering_data();
151
152 void intersectionFiltering();
153 void intersectionFiltering_data();
154
155 void unionFiltering();
156 void unionFiltering_data();
157
158 void relationshipFiltering();
159 void relationshipFiltering_data();
160
161 void changelogFiltering();
162 void changelogFiltering_data();
163
164 void idListFiltering();
165 void idListFiltering_data();
166
167 void convenienceFiltering();
168 void convenienceFiltering_data();
169
170 void sorting(); // XXX should take all managers
171 void sorting_data();
172
173 void multiSorting();
174 void multiSorting_data();
175
176 void invalidFiltering_data();
177 void invalidFiltering();
178
179 void allFiltering_data();
180 void allFiltering();
181
182 void fetchHint_data();
183 void fetchHint();
184
185private:
186 enum CollationSemantics {
187 UpperFirst = 0, // XYxy
188 LowerFirst = 1, // xyXY
189 InterleavedUpperFirst = 2, // XxYy
190 InterleavedLowerFirst = 3, // xXyY
191 FirstPassInterleavedUpperFirst = 4, // xxy < Xxz even though xxy > Xxy
192 FirstPassInterleavedLowerFirst = 5, // XXY < Xxz even though XXY > Xxy
193 UnknownCollation = 6
194 };
195 QHash<QContactManager *, int> m_collation;
196 QString expectedSorting(QContactManager *m, const QString &ufs, const QString &lfs, const QString &iufs, const QString &ilfs, const QString &fpiufs, const QString &fpilfs) {
197 switch (m_collation[m]) {
198 case UpperFirst: return ufs;
199 case LowerFirst: return lfs;
200 case InterleavedUpperFirst: return iufs;
201 case InterleavedLowerFirst: return ilfs;
202 case FirstPassInterleavedUpperFirst: return fpiufs;
203 case FirstPassInterleavedLowerFirst: return fpilfs;
204 default: return QLatin1String("unknowncollation");
205 }
206 }
207};
208
209tst_QContactManagerFiltering::tst_QContactManagerFiltering()
210{
211 // In order to make our tests reliable, set the C locale
212 QLocale::setDefault(QLocale::c());
213
214#if defined(Q_OS_UNIX) && !defined(QT_USE_ICU)
215 // Without ICU, we also need to set the locale on unix
216 ::setlocale(LC_ALL, locale: "C");
217#endif
218}
219
220tst_QContactManagerFiltering::~tst_QContactManagerFiltering()
221{
222}
223
224void tst_QContactManagerFiltering::initTestCase()
225{
226 managerDataHolder.reset(other: new QContactManagerDataHolder());
227
228 // firstly, build a list of the managers we wish to test.
229 QStringList managerNames = QContactManager::availableManagers();
230
231 /* Known one that will not pass */
232 managerNames.removeAll(t: "invalid");
233 managerNames.removeAll(t: "testdummy");
234 managerNames.removeAll(t: "teststaticdummy");
235 managerNames.removeAll(t: "maliciousplugin");
236
237 // Some internal engines on Maemo6
238 managerNames.removeAll(t: "social");
239 managerNames.removeAll(t: "simcard");
240 managerNames.removeAll(t: "com.nokia.messaging.contacts.engines.mail.contactslookup");
241
242 foreach(QString mgr, managerNames) {
243 QMap<QString, QString> params;
244 QString mgrUri = QContactManager::buildUri(managerName: mgr, params);
245 QContactManager* cm = QContactManager::fromUri(uri: mgrUri);
246 cm->setObjectName(mgr);
247 managers.append(t: cm);
248
249 if (mgr == "memory") {
250 params.insert(akey: "id", avalue: "tst_QContactManager");
251 mgrUri = QContactManager::buildUri(managerName: mgr, params);
252 cm = QContactManager::fromUri(uri: mgrUri);
253 cm->setObjectName("memory[params]");
254 managers.append(t: cm);
255 }
256 }
257
258 // for each manager that we wish to test, prepare the model.
259 foreach (QContactManager* cm, managers) {
260 QList<QContactId> addedContacts = prepareModel(cm);
261 if (addedContacts != contactsAddedToManagers.values(akey: cm)) {
262 qDebug() << "prepareModel returned:" << addedContacts;
263 qDebug() << "contactsAdded are: " << contactsAddedToManagers.values(akey: cm);
264 qFatal(msg: "returned list different from saved contacts list!");
265 }
266
267 // Also determine the string collation / sorting semantics.
268 // Case sensitivity is handled differently with/without ICU
269 // (in one case, the char sequence is 'A-Za-z', in the other it
270 // is 'AaBb..Zz') - the results are therefore highly divergent.
271 // To do so, we need to add some extra contacts.
272 QContact contactxxy, contactXxy, contactXXY, contactXxz;
273 QContactName xxn;
274 xxn.setFirstName("xxy");
275 contactxxy.saveDetail(detail: &xxn);
276 xxn.setFirstName("Xxy");
277 contactXxy.saveDetail(detail: &xxn);
278 xxn.setFirstName("XXY");
279 contactXXY.saveDetail(detail: &xxn);
280 xxn.setFirstName("Xxz");
281 contactXxz.saveDetail(detail: &xxn);
282 Q_FATAL_VERIFY(cm->saveContact(&contactxxy));
283 Q_FATAL_VERIFY(cm->saveContact(&contactXxy));
284 Q_FATAL_VERIFY(cm->saveContact(&contactXXY));
285 Q_FATAL_VERIFY(cm->saveContact(&contactXxz));
286
287 // Now fetch sorted contacts to determine sorting semantics.
288 QContactSortOrder s;
289 s.setDetailType(type: QContactName::Type, field: QContactName::FieldFirstName);
290 s.setDirection(Qt::AscendingOrder);
291 QList<QContact> sortedContacts = cm->contacts(sortOrders: s);
292 int xanderIndex = -1, XanderIndex = -1, yarrowIndex = -1, YarrowIndex = -1;
293 int xxyIndex = -1, XxyIndex = -1, XXYIndex = -1, XxzIndex = -1;
294 for (int i = 0; i < sortedContacts.size(); ++i) {
295 if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("xander")) {
296 xanderIndex = i;
297 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("Xander")) {
298 XanderIndex = i;
299 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("yarrow")) {
300 yarrowIndex = i;
301 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("Yarrow")) {
302 YarrowIndex = i;
303 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("xxy")) {
304 xxyIndex = i;
305 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("Xxy")) {
306 XxyIndex = i;
307 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("XXY")) {
308 XXYIndex = i;
309 } else if (sortedContacts[i].detail<QContactName>().firstName() == QStringLiteral("Xxz")) {
310 XxzIndex = i;
311 }
312 }
313
314 if (XanderIndex < YarrowIndex && YarrowIndex < xanderIndex && xanderIndex < yarrowIndex &&
315 XXYIndex < XxyIndex && XxyIndex < XxzIndex && XxzIndex < xxyIndex) {
316 //qDebug() << "XYxy, and XXY<Xxy<Xxz<xxy :. upper first sorting:"
317 // << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
318 // << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
319 m_collation[cm] = UpperFirst;
320 } else if (xanderIndex < yarrowIndex && yarrowIndex < XanderIndex && XanderIndex < YarrowIndex &&
321 xxyIndex < XxyIndex && XxyIndex < XxzIndex && XxzIndex < XXYIndex) {
322 //qDebug() << "xyXY, and xxy<Xxy<Xxz<XXY :. lower first sorting:"
323 // << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
324 // << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
325 m_collation[cm] = LowerFirst;
326 } else if (XanderIndex < xanderIndex && xanderIndex < YarrowIndex && YarrowIndex < yarrowIndex &&
327 XXYIndex < XxyIndex && XxyIndex < XxzIndex && XxzIndex < xxyIndex) {
328 //qDebug() << "XxYy, and XXY<Xxy<Xxz<xxy :. interleaved upper first sorting without first-pass case-insensitive characterwise comparison:"
329 // << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
330 // << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
331 m_collation[cm] = InterleavedUpperFirst;
332 } else if (xanderIndex < XanderIndex && XanderIndex < yarrowIndex && yarrowIndex < YarrowIndex &&
333 xxyIndex < XxyIndex && XxyIndex < XxzIndex && XxzIndex < XXYIndex) {
334 //qDebug() << "xXyY, and xxy<Xxy<Xxz<XXY :. interleaved lower first sorting without first-pass case-insensitive characterwise comparison:"
335 // << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
336 // << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
337 m_collation[cm] = InterleavedLowerFirst;
338 } else if (XanderIndex < xanderIndex && xanderIndex < YarrowIndex && YarrowIndex < yarrowIndex &&
339 XXYIndex < XxyIndex && XxyIndex < xxyIndex && xxyIndex < XxzIndex) {
340 //qDebug() << "XxYy, and XXY<Xxy<xxy<Xxz :. interleaved upper first sorting without first-pass case-insensitive characterwise comparison:"
341 // << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
342 // << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
343 m_collation[cm] = FirstPassInterleavedUpperFirst;
344 } else if (xanderIndex < XanderIndex && XanderIndex < yarrowIndex && yarrowIndex < YarrowIndex &&
345 xxyIndex < XxyIndex && XxyIndex < XXYIndex && XXYIndex < XxzIndex) {
346 //qDebug() << "xXyY, and xxy<Xxy<XXY<Xxz :. interleaved lower first sorting with first-pass case-insensitive characterwise comparison:"
347 // << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
348 // << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
349 m_collation[cm] = FirstPassInterleavedLowerFirst;
350 } else {
351 qDebug() << "unknown sorting:"
352 << "x:" << xanderIndex << "X:" << XanderIndex << "y:" << yarrowIndex << "Y:" << YarrowIndex
353 << "xxy:" << xxyIndex << "Xxy:" << XxyIndex << "XXY:" << XXYIndex << "Xxz:" << XxzIndex;
354 m_collation[cm] = UnknownCollation;
355 }
356
357 QList<QContactId> cleanup;
358 cleanup << contactxxy.id() << contactXxy.id() << contactXXY.id() << contactXxz.id();
359 Q_FATAL_VERIFY(cm->removeContacts(cleanup));
360 }
361
362#ifdef INCLUDE_TESTACTIONS
363 qDebug() << "Finished preparing each manager for test! About to load test actions:";
364 QServiceManager sm;
365 QStringList allServices = sm.findServices();
366 foreach(const QString& serv, allServices) {
367 if (serv.startsWith("tst_qcontactmanagerfiltering:")) {
368 if (!sm.removeService(serv)) {
369 qDebug() << " tst_qca: ctor: cleaning up test service" << serv << "failed:" << sm.error();
370 }
371 }
372 }
373 QStringList myServices;
374 myServices << "BooleanAction" << "DateAction" << "IntegerAction" << "NumberAction" << "PhoneNumberAction";
375 foreach (const QString& serv, myServices) {
376 QString builtPath = QCoreApplication::applicationDirPath() + "/plugins/contacts/xmldata/" + serv.toLower() + "service.xml";
377 if (!sm.addService(builtPath)) {
378 qDebug() << " tst_qca: ctor: unable to add" << serv << "service:" << sm.error();
379 }
380 }
381#endif
382 qDebug() << "Done!";
383}
384
385void tst_QContactManagerFiltering::cleanupTestCase()
386{
387 // first, remove any contacts that we've added to any managers.
388 foreach (QContactManager* manager, managers) {
389 QList<QContactId> contactIds = contactsAddedToManagers.values(akey: manager);
390 manager->removeContacts(contactIds, errorMap: 0);
391 }
392 contactsAddedToManagers.clear();
393
394 // finally, we can delete all of our manager instances
395 qDeleteAll(c: managers);
396 managers.clear();
397 defAndFieldNamesForTypePerManager.clear();
398
399 // And restore old contacts
400 managerDataHolder.reset(other: 0);
401
402#ifdef INCLUDE_TESTACTIONS
403 // clean up any actions/services.
404 QServiceManager sm;
405 QStringList allServices = sm.findServices();
406 foreach(const QString& serv, allServices) {
407 if (serv.startsWith("tst_qcontactmanagerfiltering:")) {
408 if (!sm.removeService(serv)) {
409 qDebug() << " tst_qca: ctor: cleaning up test service" << serv << "failed:" << sm.error();
410 }
411 }
412 }
413#endif
414}
415
416QString tst_QContactManagerFiltering::convertIds(QList<QContactId> allIds, QList<QContactId> ids, QChar minimumContact, QChar maximumContact)
417{
418 QString ret;
419 /* Expected is of the form "abcd".. it's possible that there are some extra contacts */
420 for (int i = 0; i < ids.size(); i++) {
421 if (allIds.indexOf(t: ids.at(i)) >= 0) {
422 QChar curr = ('a' + allIds.indexOf(t: ids.at(i)));
423 if (curr >= minimumContact && curr <= maximumContact) {
424 ret += curr;
425 }
426 }
427 }
428
429 return ret;
430}
431
432QTestData& tst_QContactManagerFiltering::newMRow(const char *tag, QContactManager *cm)
433{
434 // allocate a tag
435 QString foo = QString("%1[%2]").arg(a: tag).arg(a: cm->objectName());
436 return QTest::newRow(dataTag: foo.toLatin1().constData());
437}
438
439
440void tst_QContactManagerFiltering::detailStringFiltering_data()
441{
442 QTest::addColumn<QContactManager *>(name: "cm");
443 QTest::addColumn<QContactDetail::DetailType>(name: "detailType");
444 QTest::addColumn<int>(name: "detailField");
445 QTest::addColumn<QVariant>(name: "value");
446 QTest::addColumn<int>(name: "matchflags");
447 QTest::addColumn<QString>(name: "expected");
448
449 QVariant ev; // empty variant
450 QString es; // empty string
451
452 QContactDetail::DetailType name = QContactName::Type;
453 int firstname = QContactName::FieldFirstName;
454 int lastname = QContactName::FieldLastName;
455 int middlename = QContactName::FieldMiddleName;
456 int prefixname = QContactName::FieldPrefix;
457 int suffixname = QContactName::FieldSuffix;
458 QContactDetail::DetailType nickname = QContactNickname::Type;
459 int nicknameField = QContactNickname::FieldNickname;
460 QContactDetail::DetailType emailaddr = QContactEmailAddress::Type;
461 int emailfield = QContactEmailAddress::FieldEmailAddress;
462 QContactDetail::DetailType phonenumber = QContactPhoneNumber::Type;
463 int number = QContactPhoneNumber::FieldNumber;
464
465 for (int i = 0; i < managers.size(); i++) {
466 QContactManager *manager = managers.at(i);
467 newMRow(tag: "Name == Aaro", cm: manager) << manager << name << firstname << QVariant("Aaro") << 0 << es;
468 newMRow(tag: "Name == Aaron", cm: manager) << manager << name << firstname << QVariant("Aaron") << 0 << "a";
469 newMRow(tag: "Name == aaron", cm: manager) << manager << name << firstname << QVariant("aaron") << 0 << "a";
470 newMRow(tag: "Name == Aaron, case sensitive", cm: manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchCaseSensitive) << "a";
471 newMRow(tag: "Name == aaron, case sensitive", cm: manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchCaseSensitive) << es;
472
473 newMRow(tag: "Name == A, begins", cm: manager) << manager << name << firstname << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << "a";
474 newMRow(tag: "Name == Aaron, begins", cm: manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchStartsWith) << "a";
475 newMRow(tag: "Name == aaron, begins", cm: manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchStartsWith) << "a";
476 newMRow(tag: "Name == Aaron, begins, case sensitive", cm: manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << "a";
477 newMRow(tag: "Name == aaron, begins, case sensitive", cm: manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << es;
478 newMRow(tag: "Name == Aaron1, begins", cm: manager) << manager << name << firstname << QVariant("Aaron1") << (int)(QContactFilter::MatchStartsWith) << es;
479 newMRow(tag: "Last name == A, begins", cm: manager) << manager << name << lastname << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << "abc";
480 newMRow(tag: "Last name == Aaronson, begins", cm: manager) << manager << name << lastname << QVariant("Aaronson") << (int)(QContactFilter::MatchStartsWith) << "a";
481 newMRow(tag: "Last Name == Aaronson1, begins", cm: manager) << manager << name << lastname << QVariant("Aaronson1") << (int)(QContactFilter::MatchStartsWith) << es;
482
483 newMRow(tag: "Name == Aar, begins", cm: manager) << manager << name << firstname << QVariant("Aar") << (int)(QContactFilter::MatchStartsWith) << "a";
484 newMRow(tag: "Name == aar, begins", cm: manager) << manager << name << firstname << QVariant("aar") << (int)(QContactFilter::MatchStartsWith) << "a";
485 newMRow(tag: "Name == Aar, begins, case sensitive", cm: manager) << manager << name << firstname << QVariant("Aar") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << "a";
486 newMRow(tag: "Name == aar, begins, case sensitive", cm: manager) << manager << name << firstname << QVariant("aar") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << es;
487
488 newMRow(tag: "Name == aro, contains", cm: manager) << manager << name << firstname << QVariant("aro") << (int)(QContactFilter::MatchContains) << "a";
489 newMRow(tag: "Name == ARO, contains", cm: manager) << manager << name << firstname << QVariant("ARO") << (int)(QContactFilter::MatchContains) << "a";
490 newMRow(tag: "Name == aro, contains, case sensitive", cm: manager) << manager << name << firstname << QVariant("aro") << (int)(QContactFilter::MatchContains | QContactFilter::MatchCaseSensitive) << "a";
491 newMRow(tag: "Name == ARO, contains, case sensitive", cm: manager) << manager << name << firstname << QVariant("ARO") << (int)(QContactFilter::MatchContains | QContactFilter::MatchCaseSensitive) << es;
492
493 newMRow(tag: "Name == ron, ends", cm: manager) << manager << name << firstname << QVariant("ron") << (int)(QContactFilter::MatchEndsWith) << "a";
494 newMRow(tag: "Name == ARON, ends", cm: manager) << manager << name << firstname << QVariant("ARON") << (int)(QContactFilter::MatchEndsWith) << "a";
495 newMRow(tag: "Name == aron, ends, case sensitive", cm: manager) << manager << name << firstname << QVariant("aron") << (int)(QContactFilter::MatchEndsWith | QContactFilter::MatchCaseSensitive) << "a";
496 newMRow(tag: "Name == ARON, ends, case sensitive", cm: manager) << manager << name << firstname << QVariant("ARON") << (int)(QContactFilter::MatchEndsWith | QContactFilter::MatchCaseSensitive) << es;
497 newMRow(tag: "Last name == n, ends", cm: manager) << manager << name << lastname << QVariant("n") << (int)(QContactFilter::MatchEndsWith) << "abc";
498
499 newMRow(tag: "Name == Aaron, fixed", cm: manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchFixedString) << "a";
500 newMRow(tag: "Name == aaron, fixed", cm: manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchFixedString) << "a";
501 newMRow(tag: "Name == Aaron, fixed, case sensitive", cm: manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchCaseSensitive) << "a";
502 newMRow(tag: "Name == aaron, fixed, case sensitive", cm: manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchCaseSensitive) << es;
503
504 // middle name
505 newMRow(tag: "MName == Arne", cm: manager) << manager << name << middlename << QVariant("Arne") << (int)(QContactFilter::MatchContains) << "a";
506
507 // prefix
508 newMRow(tag: "Prefix == Sir", cm: manager) << manager << name << prefixname << QVariant("Sir") << (int)(QContactFilter::MatchContains) << "a";
509
510 // suffix
511 newMRow(tag: "Suffix == Dr.", cm: manager) << manager << name << suffixname << QVariant("Dr.") << (int)(QContactFilter::MatchContains) << "a";
512
513 // nickname
514 newMRow(tag: "Nickname detail exists", cm: manager) << manager << nickname << -1 << QVariant() << 0 << "ab";
515 newMRow(tag: "Nickname == Aaron, contains", cm: manager) << manager << nickname << nicknameField << QVariant("Aaron") << (int)(QContactFilter::MatchContains) << "a";
516
517 // email
518 newMRow(tag: "Email == Aaron@Aaronson.com", cm: manager) << manager << emailaddr << emailfield << QVariant("Aaron@Aaronson.com") << 0 << "a";
519 newMRow(tag: "Email == Aaron@Aaronsen.com", cm: manager) << manager << emailaddr << emailfield << QVariant("Aaron@Aaronsen.com") << 0 << es;
520
521 // phone number
522 newMRow(tag: "Phone number detail exists", cm: manager) << manager << phonenumber << -1 << QVariant("") << 0 << "ab";
523 newMRow(tag: "Phone number = 5551212", cm: manager) << manager << phonenumber << number << QVariant("5551212") << (int) QContactFilter::MatchExactly << "a";
524 newMRow(tag: "Phone number = 34, contains", cm: manager) << manager << phonenumber << number << QVariant("34") << (int) QContactFilter::MatchContains << "b";
525 newMRow(tag: "Phone number = 555, starts with", cm: manager) << manager << phonenumber << number << QVariant("555") << (int) QContactFilter::MatchStartsWith << "ab";
526 newMRow(tag: "Phone number = 1212, ends with", cm: manager) << manager << phonenumber << number << QVariant("1212") << (int) QContactFilter::MatchEndsWith << "a";
527 newMRow(tag: "Phone number = 555-1212, match phone number", cm: manager) << manager << phonenumber << number << QVariant("555-1212") << (int) QContactFilter::MatchPhoneNumber << "a"; // hyphens will be ignored by the match algorithm
528 newMRow(tag: "Phone number = 555, keypad collation", cm: manager) << manager << phonenumber << number << QVariant("555") << (int) (QContactFilter::MatchKeypadCollation | QContactFilter::MatchStartsWith) << "ab";
529
530 /* Converting other types to strings */
531 QPair<QContactDetail::DetailType, int> defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Integer");
532 if (validDetailField(pair: defAndFieldNames)) {
533 QTest::newRow(dataTag: "integer == 20") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << 0 << es;
534 QTest::newRow(dataTag: "integer == 20, as string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString) << "b";
535 QTest::newRow(dataTag: "integer == 20, begins with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchStartsWith) << "b";
536 QTest::newRow(dataTag: "integer == 2, begins with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("2") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchStartsWith) << "b";
537 QTest::newRow(dataTag: "integer == 20, ends with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchEndsWith) << "bc";
538 QTest::newRow(dataTag: "integer == 0, ends with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("0") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchEndsWith) << "abc";
539 QTest::newRow(dataTag: "integer == 20, contains, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchContains) << "bc";
540 QTest::newRow(dataTag: "integer == 0, contains, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("0") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchContains) << "abc";
541 }
542
543 /* Detail filter semantics: empty definition or field */
544 newMRow(tag: "Invalid type", cm: manager) << manager << static_cast<QContactDetail::DetailType>(-1) << -1 << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << es; // empty definition name means filter matches nothing
545 newMRow(tag: "Invalid field", cm: manager) << manager << name << -1 << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk"; // invalid field matches any with a name detail
546 }
547}
548
549void tst_QContactManagerFiltering::detailStringFiltering()
550{
551 QFETCH(QContactManager*, cm);
552 QFETCH(QContactDetail::DetailType, detailType);
553 QFETCH(int, detailField);
554 QFETCH(QVariant, value);
555 QFETCH(int, matchflags);
556 QFETCH(QString, expected);
557
558 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
559 QList<QContactId> ids;
560
561 QContactDetailFilter df;
562 df.setDetailType(type: detailType, field: detailField);
563 df.setValue(value);
564 df.setMatchFlags(QContactFilter::MatchFlags(matchflags));
565
566 if (cm->managerName() == "memory") {
567 /* At this point, since we're using memory, assume the filter isn't really supported */
568 QVERIFY(cm->isFilterSupported(df) == false);
569 }
570
571 ids = cm->contactIds(filter: df);
572
573 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
574 QEXPECT_FAIL("integer == 20", "Not sure if this should pass or fail", Continue);
575 QCOMPARE_UNSORTED(output, expected);
576}
577
578void tst_QContactManagerFiltering::detailPhoneNumberFiltering_data()
579{
580 QTest::addColumn<QContactManager *>(name: "cm");
581 QTest::addColumn<QContactDetail::DetailType>(name: "detailType");
582 QTest::addColumn<int>(name: "detailField");
583 QTest::addColumn<QVariant>(name: "value");
584 QTest::addColumn<int>(name: "matchflags");
585 QTest::addColumn<QString>(name: "expected");
586
587 // ITU-T standard keypad collation:
588 // 2 = abc, 3 = def, 4 = ghi, 5 = jkl, 6 = mno, 7 = pqrs, 8 = tuv, 9 = wxyz, 0 = space
589
590 QContactDetail::DetailType phoneType = QContactPhoneNumber::Type;
591 int phoneField = QContactPhoneNumber::FieldNumber;
592 QContactDetail::DetailType nameType = QContactName::Type;
593 int nameField = QContactName::FieldFirstName; // just test the first name.
594
595 // purely to test phone number filtering.
596 for (int i = 0; i < managers.size(); i++) {
597 QContactManager *manager = managers.at(i);
598
599 // first, keypad collation testing (ITU-T / T9 testing)
600 QTest::newRow(dataTag: "t9 aaron") << manager << nameType << nameField << QVariant(QString("22766")) << (int)(QContactFilter::MatchKeypadCollation) << "a";
601 QTest::newRow(dataTag: "t9 bob") << manager << nameType << nameField << QVariant(QString("262")) << (int)(QContactFilter::MatchKeypadCollation) << "b";
602 QTest::newRow(dataTag: "t9 john") << manager << nameType << nameField << QVariant(QString("5646")) << (int)(QContactFilter::MatchKeypadCollation) << "efg";
603 QTest::newRow(dataTag: "t9 bo") << manager << nameType << nameField << QVariant(QString("26")) << (int)(QContactFilter::MatchKeypadCollation | QContactFilter::MatchStartsWith) << "bc"; // bob, boris
604 QTest::newRow(dataTag: "t9 zzzz") << manager << nameType << nameField << QVariant(QString("9999")) << (int)(QContactFilter::MatchKeypadCollation) << ""; // nobody.
605
606 // now do phone number matching - first, aaron's phone number
607 QTest::newRow(dataTag: "a phone hyphen") << manager << phoneType << phoneField << QVariant(QString("555-1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
608 QTest::newRow(dataTag: "a phone plus") << manager << phoneType << phoneField << QVariant(QString("+5551212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
609 QTest::newRow(dataTag: "a phone brackets") << manager << phoneType << phoneField << QVariant(QString("(555)1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
610 QTest::newRow(dataTag: "a phone nospaces") << manager << phoneType << phoneField << QVariant(QString("5551212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
611 QTest::newRow(dataTag: "a phone single space") << manager << phoneType << phoneField << QVariant(QString("555 1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
612 QTest::newRow(dataTag: "a phone random spaces") << manager << phoneType << phoneField << QVariant(QString("55 512 12")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
613 QTest::newRow(dataTag: "a phone every space") << manager << phoneType << phoneField << QVariant(QString("5 5 5 1 2 1 2")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
614 QTest::newRow(dataTag: "a phone plus hyphen") << manager << phoneType << phoneField << QVariant(QString("+555-1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
615 QTest::newRow(dataTag: "a phone plus brackets") << manager << phoneType << phoneField << QVariant(QString("+5(55)1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
616 QTest::newRow(dataTag: "a phone plus brackets hyphen") << manager << phoneType << phoneField << QVariant(QString("+5(55)1-212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
617 QTest::newRow(dataTag: "a phone plus brackets hyphen spaces") << manager << phoneType << phoneField << QVariant(QString("+5 (55) 1-212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
618
619 // XXX TODO: should we test for character to number conversions (eg, dial 1800-PESTCONTROL) etc ?
620 //QTest::newRow("a phone characters") << manager << phoneType << phoneField << QVariant(QString("jjj1a1a")) << (int)(QContactFilter::MatchPhoneNumber) << "a"; // 5551212
621 //QTest::newRow("a phone characters") << manager << phoneType << phoneField << QVariant(QString("jkl1b1a")) << (int)(QContactFilter::MatchPhoneNumber) << "a"; // 5551212
622
623 // then matches bob's phone number
624 QTest::newRow(dataTag: "b phone hyphen") << manager << phoneType << phoneField << QVariant(QString("555-3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
625 QTest::newRow(dataTag: "b phone plus") << manager << phoneType << phoneField << QVariant(QString("+5553456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
626 QTest::newRow(dataTag: "b phone brackets") << manager << phoneType << phoneField << QVariant(QString("(555)3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
627 QTest::newRow(dataTag: "b phone nospaces") << manager << phoneType << phoneField << QVariant(QString("5553456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
628 QTest::newRow(dataTag: "b phone single space") << manager << phoneType << phoneField << QVariant(QString("555 3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
629 QTest::newRow(dataTag: "b phone random spaces") << manager << phoneType << phoneField << QVariant(QString("55 534 56")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
630 QTest::newRow(dataTag: "b phone every space") << manager << phoneType << phoneField << QVariant(QString("5 5 5 3 4 5 6")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
631 QTest::newRow(dataTag: "b phone plus hyphen") << manager << phoneType << phoneField << QVariant(QString("+555-3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
632 QTest::newRow(dataTag: "b phone plus brackets") << manager << phoneType << phoneField << QVariant(QString("+5(55)3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
633 QTest::newRow(dataTag: "b phone plus brackets hyphen") << manager << phoneType << phoneField << QVariant(QString("+5(55)3-456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
634 QTest::newRow(dataTag: "b phone plus brackets hyphen spaces") << manager << phoneType << phoneField << QVariant(QString("+5 (55) 3-456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
635
636 // then match no phone numbers (negative testing) -- 555-9999 matches nobody in our test set.
637 QTest::newRow(dataTag: "no phone hyphen") << manager << phoneType << phoneField << QVariant(QString("555-9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
638 QTest::newRow(dataTag: "no phone plus") << manager << phoneType << phoneField << QVariant(QString("+5559999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
639 QTest::newRow(dataTag: "no phone brackets") << manager << phoneType << phoneField << QVariant(QString("(555)9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
640 QTest::newRow(dataTag: "no phone nospaces") << manager << phoneType << phoneField << QVariant(QString("5559999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
641 QTest::newRow(dataTag: "no phone single space") << manager << phoneType << phoneField << QVariant(QString("555 9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
642 QTest::newRow(dataTag: "no phone random spaces") << manager << phoneType << phoneField << QVariant(QString("55 599 99")) << (int)(QContactFilter::MatchPhoneNumber) << "";
643 QTest::newRow(dataTag: "no phone every space") << manager << phoneType << phoneField << QVariant(QString("5 5 5 9 9 9 9")) << (int)(QContactFilter::MatchPhoneNumber) << "";
644 QTest::newRow(dataTag: "no phone plus hyphen") << manager << phoneType << phoneField << QVariant(QString("+555-9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
645 QTest::newRow(dataTag: "no phone plus brackets") << manager << phoneType << phoneField << QVariant(QString("+5(55)9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
646 QTest::newRow(dataTag: "no phone plus brackets hyphen") << manager << phoneType << phoneField << QVariant(QString("+5(55)9-999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
647 QTest::newRow(dataTag: "no phone plus brackets hyphen spaces") << manager << phoneType << phoneField << QVariant(QString("+5 (55) 9-999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
648
649 // then match both aaron and bob via starts with
650 QTest::newRow(dataTag: "ab phone starts nospace") << manager << phoneType << phoneField << QVariant(QString("555")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
651 QTest::newRow(dataTag: "ab phone starts hyphen") << manager << phoneType << phoneField << QVariant(QString("555-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
652 QTest::newRow(dataTag: "ab phone starts space") << manager << phoneType << phoneField << QVariant(QString("55 5")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
653 QTest::newRow(dataTag: "ab phone starts brackets") << manager << phoneType << phoneField << QVariant(QString("(555)")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
654 QTest::newRow(dataTag: "ab phone starts plus") << manager << phoneType << phoneField << QVariant(QString("+555")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
655 QTest::newRow(dataTag: "ab phone starts hyphen space") << manager << phoneType << phoneField << QVariant(QString("5 55-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
656 QTest::newRow(dataTag: "ab phone starts hyphen space brackets") << manager << phoneType << phoneField << QVariant(QString("5 (55)-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
657 QTest::newRow(dataTag: "ab phone starts hyphen space brackets plus") << manager << phoneType << phoneField << QVariant(QString("+5 (55)-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
658 }
659}
660
661void tst_QContactManagerFiltering::detailPhoneNumberFiltering()
662{
663 QFETCH(QContactManager*, cm);
664 QFETCH(QContactDetail::DetailType, detailType);
665 QFETCH(int, detailField);
666 QFETCH(QVariant, value);
667 QFETCH(int, matchflags);
668 QFETCH(QString, expected);
669
670 // note: this test is exactly the same as string filtering, but uses different fields and specific matchflags.
671
672 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
673 QList<QContactId> ids;
674
675 QContactDetailFilter df;
676 df.setDetailType(type: detailType, field: detailField);
677 df.setValue(value);
678 df.setMatchFlags(QContactFilter::MatchFlags(matchflags));
679
680 if (cm->managerName() == "memory") {
681 /* At this point, since we're using memory, assume the filter isn't really supported */
682 QVERIFY(cm->isFilterSupported(df) == false);
683 }
684
685 ids = cm->contactIds(filter: df);
686
687 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
688 //QSKIP("TODO: fix default implementation of phone number matching!");
689 QCOMPARE_UNSORTED(output, expected);
690}
691
692void tst_QContactManagerFiltering::detailVariantFiltering_data()
693{
694 QTest::addColumn<QContactManager *>(name: "cm");
695 QTest::addColumn<QContactDetail::DetailType>(name: "detailType");
696 QTest::addColumn<int>(name: "detailField");
697 QTest::addColumn<bool>(name: "setValue");
698 QTest::addColumn<QVariant>(name: "value");
699 QTest::addColumn<QString>(name: "expected");
700
701 QVariant ev; // empty variant
702 QString es; // empty string
703 const int invalidField(666);
704
705 for (int i = 0; i < managers.size(); i++) {
706 QContactManager *manager = managers.at(i);
707
708 /* Nothings */
709 newMRow(tag: "no field", cm: manager) << manager << static_cast<QContactDetail::DetailType>(-1) << -1 << false << ev << es;
710 newMRow(tag: "no type", cm: manager) << manager << static_cast<QContactDetail::DetailType>(-1) << static_cast<int>(QContactName::FieldFirstName) << false << ev << es;
711
712 /* Strings (name) */
713 newMRow(tag: "first name presence", cm: manager) << manager << QContactName::Type << static_cast<int>(QContactName::FieldFirstName) << false << ev << "abcdefghijk";
714 newMRow(tag: "first name == Aaron", cm: manager) << manager << QContactName::Type << static_cast<int>(QContactName::FieldFirstName) << true << QVariant("Aaron") << "a";
715
716 /*
717 * Doubles
718 * B has double(4.0)
719 * C has double(4.0)
720 * D has double(-128.0)
721 */
722 QPair<QContactDetail::DetailType, int> defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Double");
723 if (validDetailField(pair: defAndFieldNames)) {
724 newMRow(tag: "double presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "bcd";
725 QTest::newRow(dataTag: "double presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "bcd";
726 QTest::newRow(dataTag: "double presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
727 QTest::newRow(dataTag: "double value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
728 QTest::newRow(dataTag: "double value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QDateTime()) << es;
729 QTest::newRow(dataTag: "double value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(3.5) << es;
730 newMRow(tag: "double value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(4.0) << "bc";
731 QTest::newRow(dataTag: "double value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(4.0) << es;
732 QTest::newRow(dataTag: "double value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(-128.0) << "d";
733 QTest::newRow(dataTag: "double value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(-128.0) << es;
734 }
735
736 /*
737 * Integers
738 * A has 10
739 * B has 20
740 * C has -20
741 */
742 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Integer");
743 if (validDetailField(pair: defAndFieldNames)) {
744 newMRow(tag: "integer presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "abc";
745 QTest::newRow(dataTag: "integer presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abc";
746 QTest::newRow(dataTag: "integer presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
747 QTest::newRow(dataTag: "integer value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(50) << es;
748 QTest::newRow(dataTag: "integer value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
749 QTest::newRow(dataTag: "integer value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(50) << es;
750 newMRow(tag: "integer value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(10) << "a";
751 QTest::newRow(dataTag: "integer value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(10) << es;
752 QTest::newRow(dataTag: "integer value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(-20) << "c";
753 QTest::newRow(dataTag: "integer value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(-20) << es;
754 }
755
756 /*
757 * Date times
758 * A has QDateTime(QDate(2009, 06, 29), QTime(16, 52, 23, 0))
759 * C has QDateTime(QDate(2009, 06, 29), QTime(16, 54, 17, 0))
760 */
761 const QDateTime adt(QDate(2009, 06, 29), QTime(16, 52, 23, 0));
762 const QDateTime cdt(QDate(2009, 06, 29), QTime(16, 54, 17, 0));
763
764 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "DateTime");
765 if (validDetailField(pair: defAndFieldNames)) {
766 newMRow(tag: "datetime presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "ac";
767 QTest::newRow(dataTag: "datetime presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "ac";
768 QTest::newRow(dataTag: "datetime presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
769 QTest::newRow(dataTag: "datetime value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QDateTime(QDate(2100,5,13), QTime(5,5,5))) << es;
770 QTest::newRow(dataTag: "datetime value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
771 QTest::newRow(dataTag: "datetime value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QDateTime(QDate(2100,5,13), QTime(5,5,5))) << es;
772 newMRow(tag: "datetime value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(adt) << "a";
773 QTest::newRow(dataTag: "datetime value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(adt) << es;
774 QTest::newRow(dataTag: "datetime value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(cdt)<< "c";
775 QTest::newRow(dataTag: "datetime value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(cdt) << es;
776 }
777
778 /*
779 * Dates
780 * A has QDate(1988, 1, 26)
781 * B has QDate(2492, 5, 5)
782 * D has QDate(2770, 10, 1)
783 */
784 const QDate ad(1988, 1, 26);
785 const QDate bd(2492, 5, 5);
786 const QDate dd(2770, 10, 1);
787
788 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Date");
789 if (validDetailField(pair: defAndFieldNames)) {
790 newMRow(tag: "date presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "abd";
791 QTest::newRow(dataTag: "date presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abd";
792 QTest::newRow(dataTag: "date presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
793 QTest::newRow(dataTag: "date value (no match)") << manager << defAndFieldNames.first <<defAndFieldNames.second << true << QVariant(QDate(2100,5,13)) << es;
794 QTest::newRow(dataTag: "date value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
795 QTest::newRow(dataTag: "date value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QDate(2100,5,13)) << es;
796 newMRow(tag: "date value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(ad) << "a";
797 QTest::newRow(dataTag: "date value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(ad) << es;
798 QTest::newRow(dataTag: "date value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(bd) << es;
799 QTest::newRow(dataTag: "date value 3 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(dd) << es;
800 QTest::newRow(dataTag: "date value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(bd)<< "b";
801 QTest::newRow(dataTag: "date value 3") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(dd)<< "d";
802 }
803
804 /*
805 * Times
806 * A has QTime(16,52,23,0)
807 * B has QTime(15,52,23,0)
808 */
809 const QTime at = QTime(16,52,23,0);
810 const QTime bt = QTime(15,52,23,0);
811
812 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Time");
813 if (validDetailField(pair: defAndFieldNames)) {
814 newMRow(tag: "time presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "ab";
815 QTest::newRow(dataTag: "time presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "ab";
816 QTest::newRow(dataTag: "time presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
817 QTest::newRow(dataTag: "time value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QTime(5,5,5)) << es;
818 QTest::newRow(dataTag: "time value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
819 QTest::newRow(dataTag: "time value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QTime(5,5,5)) << es;
820 newMRow(tag: "time value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(at) << "a";
821 QTest::newRow(dataTag: "time value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(at) << es;
822 QTest::newRow(dataTag: "time value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(bt)<< "b";
823 QTest::newRow(dataTag: "time value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(bt) << es;
824 }
825
826
827 /*
828 * Bool
829 * A has bool(true)
830 * B has bool(false)
831 * C has bool(false)
832 */
833 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Bool");
834 if (validDetailField(pair: defAndFieldNames)) {
835 newMRow(tag: "bool presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "abc";
836 QTest::newRow(dataTag: "bool presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abc";
837 QTest::newRow(dataTag: "bool presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
838 QTest::newRow(dataTag: "bool value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(4.0) << es;
839 newMRow(tag: "bool value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(true) << "a";
840 QTest::newRow(dataTag: "bool value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(true) << es;
841 QTest::newRow(dataTag: "bool value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(false) << "bc";
842 QTest::newRow(dataTag: "bool value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(false) << es;
843 }
844
845 /*
846 * LongLong
847 * C has LongLong(8000000000LL)
848 * D has LongLong(-14000000000LL)
849 */
850 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "LongLong");
851 if (validDetailField(pair: defAndFieldNames)) {
852 newMRow(tag: "longlong presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "cd";
853 QTest::newRow(dataTag: "longlong presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "cd";
854 QTest::newRow(dataTag: "longlong presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
855 QTest::newRow(dataTag: "longlong value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(50000000000LL) << es;
856 QTest::newRow(dataTag: "longlong value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
857 QTest::newRow(dataTag: "longlong value (wrong field, no match)") << manager << defAndFieldNames.first<< invalidField << true << QVariant(50000000000LL) << es;
858 newMRow(tag: "longlong value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(8000000000LL) << "c";
859 QTest::newRow(dataTag: "longlong value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(8000000000LL) << es;
860 QTest::newRow(dataTag: "longlong value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(-14000000000LL) << "d";
861 QTest::newRow(dataTag: "longlong value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(-14000000000LL) << es;
862 }
863
864 /*
865 * ULongLong
866 * A has ULongLong(120000000000ULL)
867 * B has ULongLong(80000000000ULL)
868 * C has ULongLong(80000000000ULL)
869 */
870 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "ULongLong");
871 if (validDetailField(pair: defAndFieldNames)) {
872 newMRow(tag: "ulonglong presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "abc";
873 QTest::newRow(dataTag: "ulonglong presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abc";
874 QTest::newRow(dataTag: "ulonglong presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
875 QTest::newRow(dataTag: "ulonglong value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(50000000000ULL) << es;
876 QTest::newRow(dataTag: "ulonglong value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
877 QTest::newRow(dataTag: "ulonglong value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(50000000000ULL) << es;
878 newMRow(tag: "ulonglong value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(120000000000ULL) << "a";
879 QTest::newRow(dataTag: "ulonglong value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(120000000000ULL) << es;
880 QTest::newRow(dataTag: "ulonglong value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(80000000000ULL) << "bc";
881 QTest::newRow(dataTag: "ulonglong value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(80000000000ULL) << es;
882 }
883
884 /*
885 * UInt
886 * B has UInt(4000000000u)
887 * D has UInt(3000000000u)
888 */
889 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "UInt");
890 if (validDetailField(pair: defAndFieldNames)) {
891 newMRow(tag: "unsigned integer presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "bd";
892 QTest::newRow(dataTag: "unsigned integer presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "bd";
893 QTest::newRow(dataTag: "unsigned integer presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
894 QTest::newRow(dataTag: "unsigned integer value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3500000000u) << es;
895 QTest::newRow(dataTag: "unsigned integer value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
896 QTest::newRow(dataTag: "unsigned integer value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(3500000000u) << es;
897 newMRow(tag: "unsigned integer value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(4000000000u) << "b";
898 QTest::newRow(dataTag: "unsigned integer value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(4000000000u) << es;
899 QTest::newRow(dataTag: "unsigned integer value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3000000000u) << "d";
900 QTest::newRow(dataTag: "unsigned integer value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(3000000000u) << es;
901 }
902
903 /*
904 * Char
905 * B has QChar('b')
906 * C has QChar('c')
907 */
908 const QChar bchar('b');
909 const QChar cchar('c');
910 defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Char");
911 if (validDetailField(pair: defAndFieldNames)) {
912 newMRow(tag: "char presence", cm: manager) << manager << defAndFieldNames.first << -1 << false << ev << "bc";
913 QTest::newRow(dataTag: "char presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "bc";
914 QTest::newRow(dataTag: "char presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
915 QTest::newRow(dataTag: "char value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QChar('a')) << es;
916 QTest::newRow(dataTag: "char value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
917 QTest::newRow(dataTag: "char value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QChar('a')) << es;
918 newMRow(tag: "char value", cm: manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(bchar) << "b";
919 QTest::newRow(dataTag: "char value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(bchar) << es;
920 QTest::newRow(dataTag: "char value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(cchar)<< "c";
921 QTest::newRow(dataTag: "char value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(cchar) << es;
922 }
923 }
924}
925
926void tst_QContactManagerFiltering::detailVariantFiltering()
927{
928 QFETCH(QContactManager*, cm);
929 QFETCH(QContactDetail::DetailType, detailType);
930 QFETCH(int, detailField);
931 QFETCH(bool, setValue);
932 QFETCH(QVariant, value);
933 QFETCH(QString, expected);
934
935 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
936 QList<QContactId> ids;
937
938 QContactDetailFilter df;
939 df.setDetailType(type: detailType, field: detailField);
940 if (setValue)
941 df.setValue(value);
942
943 if (cm->managerName() == "memory") {
944 /* At this point, since we're using memory, assume the filter isn't really supported */
945 QVERIFY(cm->isFilterSupported(df) == false);
946 }
947
948 ids = cm->contactIds(filter: df);
949
950 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
951 QCOMPARE_UNSORTED(output, expected);
952}
953
954void tst_QContactManagerFiltering::rangeFiltering_data()
955{
956 QTest::addColumn<QContactManager *>(name: "cm");
957 QTest::addColumn<QContactDetail::DetailType>(name: "detailType");
958 QTest::addColumn<int>(name: "detailField");
959 QTest::addColumn<QVariant>(name: "minrange");
960 QTest::addColumn<QVariant>(name: "maxrange");
961 QTest::addColumn<bool>(name: "setrfs");
962 QTest::addColumn<int>(name: "rangeflagsi");
963 QTest::addColumn<bool>(name: "setmfs");
964 QTest::addColumn<int>(name: "matchflagsi");
965 QTest::addColumn<QString>(name: "expected");
966
967 QVariant ev; // empty variant
968 QString es; // empty string
969 const int invalidField(666);
970
971 QContactDetail::DetailType nameType = QContactName::Type;
972 int firstname = QContactName::FieldFirstName;
973
974 QContactDetail::DetailType phoneType = QContactPhoneNumber::Type;
975 int phonenum = QContactPhoneNumber::FieldNumber;
976
977 int csflag = (int)QContactFilter::MatchCaseSensitive;
978
979 for (int i = 0; i < managers.size(); i++) {
980 QContactManager *manager = managers.at(i);
981
982 /* First, cover the "empty detailType / detailField / ranges" cases */
983 newMRow(tag: "invalid detailType", cm: manager) << manager << QContactDetail::TypeUndefined << firstname << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << es;
984 newMRow(tag: "defn presence test", cm: manager) << manager << nameType << -1 << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << "abcdefghijk";
985 newMRow(tag: "field presence test", cm: manager) << manager << phoneType << phonenum << QVariant() << QVariant() << false << 0 << true << 0 << "ab";
986 newMRow(tag: "good type, bad field", cm: manager) << manager << nameType << invalidField << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << es;
987 newMRow(tag: "bad def", cm: manager) << manager << static_cast<QContactDetail::DetailType>(-1) << -1 << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << es;
988
989 /* Presence for fields that aren't there */
990 newMRow(tag: "defn presence test negative", cm: manager) << manager << QContactFamily::Type << -1 << ev << ev << false << 0 << false << 0 << es;
991 newMRow(tag: "field presence test negative", cm: manager) << manager << QContactFamily::Type << invalidField << ev << ev << false << 0 << false << 0 << es;
992 newMRow(tag: "defn yes, field no presence test negative", cm: manager) << manager << nameType << invalidField << ev << ev << false << 0 << false << 0 << es;
993
994 newMRow(tag: "no max, all results", cm: manager) << manager << nameType << firstname << QVariant("a") << QVariant() << false << 0 << true << 0 << "abcdefghijk";
995 newMRow(tag: "no max, some results", cm: manager) << manager << nameType << firstname << QVariant("bob") << QVariant() << false << 0 << true << 0 << "bcdefghijk";
996 newMRow(tag: "no max, no results", cm: manager) << manager << nameType << firstname << QVariant("ZamBeZI") << QVariant() << false << 0 << true << 0 << es;
997 newMRow(tag: "no min, all results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("zambezi") << false << 0 << true << 0 << "abcdefghijk";
998 newMRow(tag: "no min, some results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("bOb") << false << 0 << true << 0 << "a";
999 newMRow(tag: "no min, no results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("aardvark") << false << 0 << true << 0 << es;
1000
1001 /* now case sensitive */
1002 newMRow(tag: "no max, cs, all results", cm: manager) << manager << nameType << firstname << QVariant("A") << QVariant() << false << 0 << true << csflag << "abcdefghijk";
1003 newMRow(tag: "no max, cs, some results", cm: manager) << manager << nameType << firstname << QVariant("Bob") << QVariant() << false << 0 << true << csflag << "bcdefghijk";
1004 newMRow(tag: "no max, cs, no results", cm: manager) << manager << nameType << firstname << QVariant("Xambezi") << QVariant() << false << 0 << true << csflag << "hijk";
1005 newMRow(tag: "no min, cs, most results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("Xambezi") << false << 0 << true << csflag << "abcdefg";
1006 newMRow(tag: "no min, cs, some results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("Bob") << false << 0 << true << csflag << "a";
1007 newMRow(tag: "no min, cs, no results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("Aardvark") << false << 0 << true << csflag << es;
1008 newMRow(tag: "no max, cs, badcase, all results", cm: manager) << manager << nameType << firstname << QVariant("A") << QVariant() << false << 0 << true << csflag << "abcdefghijk";
1009 newMRow(tag: "no max, cs, badcase, some results", cm: manager) << manager << nameType << firstname << QVariant("bob") << QVariant() << false << 0 << true << csflag << expectedSorting(m: manager, ufs: "hj", lfs: "abcdefghijk", iufs: "defghijk", ilfs: "bcdefghijk", fpiufs: "cdefghijk", fpilfs: "bcdefghijk");
1010 newMRow(tag: "no max, cs, badcase, no results", cm: manager) << manager << nameType << firstname << QVariant("XAMBEZI") << QVariant() << false << 0 << true << csflag << "hijk";
1011 newMRow(tag: "no min, cs, badcase, all results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("XAMBEZI") << false << 0 << true << csflag << "abcdefg";
1012 newMRow(tag: "no min, cs, badcase, some results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("BOB") << false << 0 << true << csflag << expectedSorting(m: manager, ufs: "a", lfs: "abchj", iufs: "a", ilfs: "abc", fpiufs: "a", fpilfs: "ab");
1013 newMRow(tag: "no min, cs, badcase, no results", cm: manager) << manager << nameType << firstname << QVariant() << QVariant("AARDVARK") << false << 0 << true << csflag << es;
1014
1015 /* 'a' has phone number ("5551212") */
1016 QTest::newRow(dataTag: "range1") << manager << phoneType << phonenum << QVariant("5551200") << QVariant("5551220") << false << 0 << false << 0 << "a";
1017
1018 /* A(Aaron Aaronson), B(Bob Aaronsen), C(Boris Aaronsun), D(Dennis FitzMacyntire) */
1019 // string range matching - no matchflags set.
1020 QTest::newRow(dataTag: "string range - no matchflags - 1") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << "a";
1021 QTest::newRow(dataTag: "string range - no matchflags - 2") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "a";
1022 QTest::newRow(dataTag: "string range - no matchflags - 3") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "a";
1023 QTest::newRow(dataTag: "string range - no matchflags - 4") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "ab";
1024 QTest::newRow(dataTag: "string range - no matchflags - 5") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "ab";
1025 QTest::newRow(dataTag: "string range - no matchflags - 6") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "c";
1026 QTest::newRow(dataTag: "string range - no matchflags - 7") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "b";
1027 QTest::newRow(dataTag: "string range - no matchflags - 8") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "bc";
1028 QTest::newRow(dataTag: "string range - no matchflags - 9") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "";
1029 QTest::newRow(dataTag: "string range - no matchflags - 10") << manager << nameType << firstname << QVariant("Barry") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "bc";
1030
1031 // string range matching - QContactFilter::MatchStartsWith should produce the same results as without matchflags set.
1032 QTest::newRow(dataTag: "string range - startswith - 1") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "a";
1033 QTest::newRow(dataTag: "string range - startswith - 2") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "a";
1034 QTest::newRow(dataTag: "string range - startswith - 3") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "ab";
1035 QTest::newRow(dataTag: "string range - startswith - 4") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "ab";
1036 QTest::newRow(dataTag: "string range - startswith - 5") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "c";
1037 QTest::newRow(dataTag: "string range - startswith - 6") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "bc";
1038 QTest::newRow(dataTag: "string range - startswith - 7") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "bc";
1039 QTest::newRow(dataTag: "string range - startswith - 8") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "c";
1040 QTest::newRow(dataTag: "string range - startswith - 9") << manager << nameType << firstname << QVariant("Barry") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "bc";
1041
1042 // Open ended starts with
1043 QTest::newRow(dataTag: "string range - startswith open top - 1") << manager << nameType << firstname << QVariant("A") << ev << true << (int)(QContactDetailRangeFilter::IncludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk";
1044 QTest::newRow(dataTag: "string range - startswith open top - 2") << manager << nameType << firstname << QVariant("A") << ev << true << (int)(QContactDetailRangeFilter::ExcludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk";
1045 QTest::newRow(dataTag: "string range - startswith open top - 3") << manager << nameType << firstname << QVariant("Aaron") << ev << true << (int)(QContactDetailRangeFilter::IncludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk";
1046 QTest::newRow(dataTag: "string range - startswith open top - 4") << manager << nameType << firstname << QVariant("Aaron") << ev << true << (int)(QContactDetailRangeFilter::ExcludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "bcdefghijk";
1047 QTest::newRow(dataTag: "string range - startswith open bottom - 1") << manager << nameType << firstname << ev << QVariant("Borit") << true << (int)(QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "abc";
1048 QTest::newRow(dataTag: "string range - startswith open bottom - 2") << manager << nameType << firstname << ev << QVariant("Borit") << true << (int)(QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "abc";
1049 QTest::newRow(dataTag: "string range - startswith open bottom - 3") << manager << nameType << firstname << ev << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "abc";
1050 QTest::newRow(dataTag: "string range - startswith open bottom - 4") << manager << nameType << firstname << ev << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "ab";
1051
1052 /* A(10), B(20), C(-20) */
1053 // Now integer range testing
1054 QPair<QContactDetail::DetailType, int> defAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Integer");
1055 if (validDetailField(pair: defAndFieldNames)) {
1056 QTest::newRow(dataTag: "int range - no rangeflags - 1") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant(9) << false << 0 << false << 0 << es;
1057 QTest::newRow(dataTag: "int range - no rangeflags - 2") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant(10) << false << 0 << false << 0 << es;
1058 QTest::newRow(dataTag: "int range - no rangeflags - 3") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant(11) << false << 0 << false << 0 << "a";
1059 QTest::newRow(dataTag: "int range - no rangeflags - 4") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << false << 0 << false << 0 << es;
1060 QTest::newRow(dataTag: "int range - rangeflags - 1") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << false << 0 << es;
1061 QTest::newRow(dataTag: "int range - rangeflags - 2") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << false << 0 << es;
1062 QTest::newRow(dataTag: "int range - rangeflags - 3") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << es;
1063 QTest::newRow(dataTag: "int range - rangeflags - 4") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "a";
1064 QTest::newRow(dataTag: "int range - rangeflags - 5") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(11) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "a";
1065 QTest::newRow(dataTag: "int range - rangeflags - 6") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(11) << QVariant(11) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << es;
1066 QTest::newRow(dataTag: "int range - rangeflags - 7") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(-30) << QVariant(-19) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "c";
1067 QTest::newRow(dataTag: "int range - rangeflags - 8") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(-20) << QVariant(-30) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << es;
1068 QTest::newRow(dataTag: "int range - rangeflags - variant - 1") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant() << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "ab";
1069 QTest::newRow(dataTag: "int range - rangeflags - variant - 2") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant() << QVariant(11) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "ac";
1070 }
1071 }
1072}
1073
1074void tst_QContactManagerFiltering::rangeFiltering()
1075{
1076 QFETCH(QContactManager*, cm);
1077 QFETCH(QContactDetail::DetailType, detailType);
1078 QFETCH(int, detailField);
1079 QFETCH(QVariant, minrange);
1080 QFETCH(QVariant, maxrange);
1081 QFETCH(bool, setrfs);
1082 QFETCH(int, rangeflagsi);
1083 QFETCH(bool, setmfs);
1084 QFETCH(int, matchflagsi);
1085 QFETCH(QString, expected);
1086
1087 QContactDetailRangeFilter::RangeFlags rangeflags = (QContactDetailRangeFilter::RangeFlags)rangeflagsi;
1088 QContactFilter::MatchFlags matchflags = (QContactFilter::MatchFlags) matchflagsi;
1089
1090 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
1091 QList<QContactId> ids;
1092
1093 /* Build the range filter */
1094 QContactDetailRangeFilter drf;
1095 drf.setDetailType(type: detailType, field: detailField);
1096 if (setrfs)
1097 drf.setRange(min: minrange, max: maxrange, flags: rangeflags);
1098 else
1099 drf.setRange(min: minrange, max: maxrange);
1100 if (setmfs)
1101 drf.setMatchFlags(matchflags);
1102
1103 if (cm->managerName() == "memory") {
1104 /* At this point, since we're using memory, assume the filter isn't really supported */
1105 QVERIFY(cm->isFilterSupported(drf) == false);
1106 }
1107 ids = cm->contactIds(filter: drf);
1108
1109 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
1110 QEXPECT_FAIL("string range - startswith - 3", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1111 QEXPECT_FAIL("string range - startswith - 4", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1112 QEXPECT_FAIL("string range - startswith - 5", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1113 QEXPECT_FAIL("string range - startswith - 8", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1114 QCOMPARE_UNSORTED(output, expected);
1115}
1116
1117void tst_QContactManagerFiltering::intersectionFiltering_data()
1118{
1119 QTest::addColumn<QContactManager *>(name: "cm");
1120 QTest::addColumn<bool>(name: "firstfilter");
1121 QTest::addColumn<int>(name: "fftype"); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1122 QTest::addColumn<QContactDetail::DetailType>(name: "ffdetailtype");
1123 QTest::addColumn<int>(name: "ffdetailfield");
1124 QTest::addColumn<bool>(name: "ffsetvalue");
1125 QTest::addColumn<QVariant>(name: "ffvalue");
1126 QTest::addColumn<QVariant>(name: "ffminrange");
1127 QTest::addColumn<QVariant>(name: "ffmaxrange");
1128 QTest::addColumn<bool>(name: "secondfilter");
1129 QTest::addColumn<int>(name: "sftype");
1130 QTest::addColumn<QContactDetail::DetailType>(name: "sfdetailtype");
1131 QTest::addColumn<int>(name: "sfdetailfield");
1132 QTest::addColumn<bool>(name: "sfsetvalue");
1133 QTest::addColumn<QVariant>(name: "sfvalue");
1134 QTest::addColumn<QVariant>(name: "sfminrange");
1135 QTest::addColumn<QVariant>(name: "sfmaxrange");
1136 QTest::addColumn<QString>(name: "order");
1137 QTest::addColumn<QString>(name: "expected");
1138
1139 QString es; // empty string.
1140
1141 for (int i = 0; i < managers.size(); i++) {
1142 QContactManager *manager = managers.at(i);
1143
1144 // for the following tests, terminology:
1145 // X will be an (empty) intersection filter created in the test
1146 // Y will be the first filter defined here
1147 // Z will be the second filter defined here
1148
1149 // WITH Y AND Z AS DETAIL FILTERS (with no overlap between Y and Z results)
1150 // For these tests, Y matches "bc" and Z matches "a"
1151 // X && Y - X empty so es
1152 QPair<QContactDetail::DetailType, int> integerDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Integer");
1153 QPair<QContactDetail::DetailType, int> booleanDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Bool");
1154 if (validDetailField(pair: integerDefAndFieldNames) && validDetailField(pair: booleanDefAndFieldNames)) {
1155 QTest::newRow(dataTag: "A1") << manager
1156 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1157 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1158 << "XY" << es;
1159 // Y && X - X empty so es
1160 QTest::newRow(dataTag: "A2") << manager
1161 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1162 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1163 << "YX" << es;
1164 // Y && Z - matches "a" and "bc" - so intersected = es
1165 QTest::newRow(dataTag: "A3") << manager
1166 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1167 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1168 << "YZ" << es;
1169 // Z && Y - matches "bc" and "a" - so intersected = es
1170 QTest::newRow(dataTag: "A4") << manager
1171 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1172 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1173 << "ZY" << es;
1174 // X && Z - X empty so es
1175 QTest::newRow(dataTag: "A5") << manager
1176 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1177 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1178 << "XZ" << es;
1179 // Z && X - X empty so es
1180 QTest::newRow(dataTag: "A6") << manager
1181 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1182 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1183 << "ZX" << es;
1184 // X && Y && Z - X empty so es
1185 QTest::newRow(dataTag: "A7") << manager
1186 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1187 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1188 << "XYZ" << es;
1189 // X && Z && Y - X empty so es
1190 QTest::newRow(dataTag: "A8") << manager
1191 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1192 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1193 << "XZY" << es;
1194 // Y && X && Z - X empty so es
1195 QTest::newRow(dataTag: "A9") << manager
1196 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1197 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1198 << "YXZ" << es;
1199 // Z && X && Y - X empty so es
1200 QTest::newRow(dataTag: "A10") << manager
1201 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1202 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1203 << "ZXY" << es;
1204 // Y && Z && X - X empty so es
1205 QTest::newRow(dataTag: "A11") << manager
1206 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1207 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1208 << "YZX" << es;
1209 // Z && Y && X - X empty so es
1210 QTest::newRow(dataTag: "A12") << manager
1211 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1212 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1213 << "ZYX" << es;
1214
1215 // WITH Y AND Z AS DETAIL FILTERS (with some overlap between Y and Z results)
1216 // For these tests, Y matches "bc", Z matches "b"
1217 // X && Y - X empty so es
1218 QTest::newRow(dataTag: "B1") << manager
1219 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1220 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1221 << "XY" << es;
1222 // Y && X - X empty so es
1223 QTest::newRow(dataTag: "B2") << manager
1224 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1225 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1226 << "YX" << es;
1227 // Y && Z - matches "b" and "bc" - so intersected = "b"
1228 QTest::newRow(dataTag: "B3") << manager
1229 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1230 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1231 << "YZ" << "b";
1232 // Z && Y - matches "bc" and "b" - so intersected = "b"
1233 QTest::newRow(dataTag: "B4") << manager
1234 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1235 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1236 << "ZY" << "b";
1237 // X && Z - X empty so es
1238 QTest::newRow(dataTag: "B5") << manager
1239 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1240 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1241 << "XZ" << es;
1242 // Z && X - X empty so es
1243 QTest::newRow(dataTag: "B6") << manager
1244 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1245 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1246 << "ZX" << es;
1247 // X && Y && Z - X empty so es
1248 QTest::newRow(dataTag: "B7") << manager
1249 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1250 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1251 << "XYZ" << es;
1252 // X && Z && Y - X empty so es
1253 QTest::newRow(dataTag: "B8") << manager
1254 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1255 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1256 << "XZY" << es;
1257 // Y && X && Z - X empty so es
1258 QTest::newRow(dataTag: "B9") << manager
1259 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1260 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1261 << "YXZ" << es;
1262 // Z && X && Y - X empty so es
1263 QTest::newRow(dataTag: "B10") << manager
1264 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1265 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1266 << "ZXY" << es;
1267 // Y && Z && X - X empty so es
1268 QTest::newRow(dataTag: "B11") << manager
1269 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1270 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1271 << "YZX" << es;
1272 // Z && Y && X - X empty so es
1273 QTest::newRow(dataTag: "B12") << manager
1274 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1275 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1276 << "ZYX" << es;
1277 }
1278
1279 //---------------------------
1280
1281 // WITH Y AND Z AS RANGE FILTERS (with no overlap between Y and Z results)
1282 // For these tests, Y matches "a", Z matches "b"
1283 // X && Y - X empty so es
1284 if (validDetailField(pair: integerDefAndFieldNames)) {
1285 QTest::newRow(dataTag: "C1") << manager
1286 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1287 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1288 << "XY" << es;
1289 // Y && X - X empty so es
1290 QTest::newRow(dataTag: "C2") << manager
1291 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1292 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1293 << "YX" << es;
1294 // Y && Z - no overlap so es
1295 QTest::newRow(dataTag: "C3") << manager
1296 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1297 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1298 << "YZ" << es;
1299 // Z && Y - no overlap so es
1300 QTest::newRow(dataTag: "C4") << manager
1301 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1302 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1303 << "ZY" << es;
1304 // X && Z - X empty so es
1305 QTest::newRow(dataTag: "C5") << manager
1306 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1307 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1308 << "XZ" << es;
1309 // Z && X - X empty so es
1310 QTest::newRow(dataTag: "C6") << manager
1311 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1312 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1313 << "ZX" << es;
1314 // X && Y && Z - X empty so es
1315 QTest::newRow(dataTag: "C7") << manager
1316 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1317 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1318 << "XYZ" << es;
1319 // X && Z && Y - X empty so es
1320 QTest::newRow(dataTag: "C8") << manager
1321 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1322 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1323 << "XZY" << es;
1324 // Y && X && Z - X empty so es
1325 QTest::newRow(dataTag: "C9") << manager
1326 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1327 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1328 << "YXZ" << es;
1329 // Z && X && Y - X empty so es
1330 QTest::newRow(dataTag: "C10") << manager
1331 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1332 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1333 << "ZXY" << es;
1334 // Y && Z && X - X empty so es
1335 QTest::newRow(dataTag: "C11") << manager
1336 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1337 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1338 << "YZX" << es;
1339 // Z && Y && X - X empty so es
1340 QTest::newRow(dataTag: "C12") << manager
1341 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1342 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1343 << "ZYX" << es;
1344
1345 // WITH Y AND Z AS RANGE FILTERS (with some overlap between Y and Z results)
1346 // For these tests, Y matches "ab", Z matches "b"
1347 // X && Y - X empty so es
1348 QTest::newRow(dataTag: "D1") << manager
1349 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1350 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1351 << "XY" << es;
1352 // Y && X - X empty so es
1353 QTest::newRow(dataTag: "D2") << manager
1354 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1355 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1356 << "YX" << es;
1357 // Y && Z - Y matches "ab", Z matches "b", intersection = "b"
1358 QTest::newRow(dataTag: "D3") << manager
1359 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1360 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1361 << "YZ" << "b";
1362 // Z && Y - Y matches "ab", Z matches "b", intersection = "b"
1363 QTest::newRow(dataTag: "D4") << manager
1364 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1365 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1366 << "ZY" << "b";
1367 // X && Z - X empty so es
1368 QTest::newRow(dataTag: "D5") << manager
1369 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1370 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1371 << "XZ" << es;
1372 // Z && X - X empty so es
1373 QTest::newRow(dataTag: "D6") << manager
1374 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1375 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1376 << "ZX" << es;
1377 // X && Y && Z - X empty so es
1378 QTest::newRow(dataTag: "D7") << manager
1379 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1380 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1381 << "XYZ" << es;
1382 // X && Z && Y - X empty so es
1383 QTest::newRow(dataTag: "D8") << manager
1384 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1385 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1386 << "XZY" << es;
1387 // Y && X && Z - X empty so es
1388 QTest::newRow(dataTag: "D9") << manager
1389 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1390 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1391 << "YXZ" << es;
1392 // Z && X && Y - X empty so es
1393 QTest::newRow(dataTag: "D10") << manager
1394 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1395 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1396 << "ZXY" << es;
1397 // Y && Z && X - X empty so es
1398 QTest::newRow(dataTag: "D11") << manager
1399 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1400 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1401 << "YZX" << es;
1402 // Z && Y && X - X empty so es
1403 QTest::newRow(dataTag: "D12") << manager
1404 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1405 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1406 << "ZYX" << es;
1407 }
1408 }
1409}
1410
1411void tst_QContactManagerFiltering::intersectionFiltering()
1412{
1413 QFETCH(QContactManager*, cm);
1414 QFETCH(bool, firstfilter);
1415 QFETCH(int, fftype); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1416 QFETCH(QContactDetail::DetailType, ffdetailtype);
1417 QFETCH(int, ffdetailfield);
1418 QFETCH(bool, ffsetvalue);
1419 QFETCH(QVariant, ffvalue);
1420 QFETCH(QVariant, ffminrange);
1421 QFETCH(QVariant, ffmaxrange);
1422 QFETCH(bool, secondfilter);
1423 QFETCH(int, sftype);
1424 QFETCH(QContactDetail::DetailType, sfdetailtype);
1425 QFETCH(int, sfdetailfield);
1426 QFETCH(bool, sfsetvalue);
1427 QFETCH(QVariant, sfvalue);
1428 QFETCH(QVariant, sfminrange);
1429 QFETCH(QVariant, sfmaxrange);
1430 QFETCH(QString, order);
1431 QFETCH(QString, expected);
1432
1433 QContactFilter *x = new QContactIntersectionFilter();
1434 QContactFilter *y = 0, *z = 0;
1435
1436 if (firstfilter) {
1437 switch (fftype) {
1438 case 1: // detail filter
1439 y = new QContactDetailFilter();
1440 static_cast<QContactDetailFilter*>(y)->setDetailType(type: ffdetailtype, field: ffdetailfield);
1441 if (ffsetvalue)
1442 static_cast<QContactDetailFilter*>(y)->setValue(ffvalue);
1443 break;
1444 case 2: // range filter
1445 y = new QContactDetailRangeFilter();
1446 static_cast<QContactDetailRangeFilter*>(y)->setDetailType(type: ffdetailtype, field: ffdetailfield);
1447 static_cast<QContactDetailRangeFilter*>(y)->setRange(min: ffminrange, max: ffmaxrange);
1448 break;
1449 case 3: // group membership filter
1450 case 4: // union filter
1451 case 5: // intersection filter
1452 break;
1453
1454 default:
1455 QVERIFY(false); // force fail.
1456 break;
1457 }
1458 }
1459
1460 if (secondfilter) {
1461 switch (sftype) {
1462 case 1: // detail filter
1463 z = new QContactDetailFilter();
1464 static_cast<QContactDetailFilter*>(z)->setDetailType(type: sfdetailtype, field: sfdetailfield);
1465 if (sfsetvalue)
1466 static_cast<QContactDetailFilter*>(z)->setValue(sfvalue);
1467 break;
1468 case 2: // range filter
1469 z = new QContactDetailRangeFilter();
1470 static_cast<QContactDetailRangeFilter*>(z)->setDetailType(type: sfdetailtype, field: sfdetailfield);
1471 static_cast<QContactDetailRangeFilter*>(z)->setRange(min: sfminrange, max: sfmaxrange);
1472 break;
1473 case 3: // group membership filter
1474 case 4: // union filter
1475 case 5: // intersection filter
1476 break;
1477
1478 default:
1479 QVERIFY(false); // force fail.
1480 break;
1481 }
1482 }
1483
1484 // control variables - order: starts, ends, mids
1485 bool sX = false;
1486 bool sY = false;
1487 bool sZ = false;
1488 bool eX = false;
1489 bool eY = false;
1490 bool eZ = false;
1491 bool mX = false;
1492 bool mY = false;
1493 bool mZ = false;
1494
1495 if (order.startsWith(s: "X"))
1496 sX = true;
1497 if (order.startsWith(s: "Y"))
1498 sY = true;
1499 if (order.startsWith(s: "Z"))
1500 sZ = true;
1501 if (order.endsWith(s: "X"))
1502 eX = true;
1503 if (order.endsWith(s: "Y"))
1504 eY = true;
1505 if (order.endsWith(s: "Z"))
1506 eZ = true;
1507 if (order.size() > 2) {
1508 if (order.at(i: 1) == 'X')
1509 mX = true;
1510 if (order.at(i: 1) == 'Y')
1511 mY = true;
1512 if (order.at(i: 1) == 'Z')
1513 mZ = true;
1514 }
1515
1516 // now perform the filtering.
1517 QContactIntersectionFilter resultFilter;
1518 if (sX) {
1519 if (mY && eZ)
1520 resultFilter = *x & *y & *z;
1521 else if (mZ && eY)
1522 resultFilter = *x & *z & *y;
1523 else if (eY)
1524 resultFilter = *x & *y;
1525 else if (eZ)
1526 resultFilter = *x & *z;
1527 } else if (sY) {
1528 if (mX && eZ)
1529 resultFilter = *y & *x & *z;
1530 else if (mZ && eX)
1531 resultFilter = *y & *z & *x;
1532 else if (eX)
1533 resultFilter = *y & *x;
1534 else if (eZ)
1535 resultFilter = *y & *z;
1536 } else if (sZ) {
1537 if (mX && eY)
1538 resultFilter = *z & *x & *y;
1539 else if (mY && eX)
1540 resultFilter = *z & *y & *x;
1541 else if (eX)
1542 resultFilter = *z & *x;
1543 else if (eY)
1544 resultFilter = *z & *y;
1545 }
1546
1547 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
1548 QList<QContactId> ids;
1549
1550 ids = cm->contactIds(filter: resultFilter);
1551
1552 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
1553 QCOMPARE_UNSORTED(output, expected);
1554
1555 delete x;
1556 if (y) delete y;
1557 if (z) delete z;
1558}
1559
1560void tst_QContactManagerFiltering::unionFiltering_data()
1561{
1562 QTest::addColumn<QContactManager *>(name: "cm");
1563 QTest::addColumn<bool>(name: "firstfilter");
1564 QTest::addColumn<int>(name: "fftype"); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1565 QTest::addColumn<QContactDetail::DetailType>(name: "ffdetailtype");
1566 QTest::addColumn<int>(name: "ffdetailfield");
1567 QTest::addColumn<bool>(name: "ffsetvalue");
1568 QTest::addColumn<QVariant>(name: "ffvalue");
1569 QTest::addColumn<QVariant>(name: "ffminrange");
1570 QTest::addColumn<QVariant>(name: "ffmaxrange");
1571 QTest::addColumn<bool>(name: "secondfilter");
1572 QTest::addColumn<int>(name: "sftype");
1573 QTest::addColumn<QContactDetail::DetailType>(name: "sfdetailtype");
1574 QTest::addColumn<int>(name: "sfdetailfield");
1575 QTest::addColumn<bool>(name: "sfsetvalue");
1576 QTest::addColumn<QVariant>(name: "sfvalue");
1577 QTest::addColumn<QVariant>(name: "sfminrange");
1578 QTest::addColumn<QVariant>(name: "sfmaxrange");
1579 QTest::addColumn<QString>(name: "order");
1580 QTest::addColumn<QString>(name: "expected");
1581
1582 QString es; // empty string.
1583
1584 for (int i = 0; i < managers.size(); i++) {
1585 QContactManager *manager = managers.at(i);
1586
1587 // for the following tests, terminology:
1588 // X will be an (empty) union filter created in the test
1589 // Y will be the first filter defined here
1590 // Z will be the second filter defined here
1591
1592 // WITH Y AND Z AS DETAIL FILTERS (with no overlap between Y and Z results)
1593 // For these tests, Y matches "bc" and Z matches "a"
1594 // X || Y - X empty, Y matches "bc" so union = "bc"
1595 QPair<QContactDetail::DetailType, int> integerDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Integer");
1596 QPair<QContactDetail::DetailType, int> booleanDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Bool");
1597 if (validDetailField(pair: integerDefAndFieldNames) && validDetailField(pair: booleanDefAndFieldNames)) {
1598 QTest::newRow(dataTag: "A1") << manager
1599 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1600 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1601 << "XY" << "bc";
1602 // Y || X - Y matches "bc", X empty so union = "bc"
1603 QTest::newRow(dataTag: "A2") << manager
1604 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1605 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1606 << "YX" << "bc";
1607 // Y || Z - Y matches "bc" and Z matches "a" - so union = "abc"
1608 QTest::newRow(dataTag: "A3") << manager
1609 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1610 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1611 << "YZ" << "abc";
1612 // Z || Y - Y matches "bc" and Z matches "a" - so union = "abc"
1613 QTest::newRow(dataTag: "A4") << manager
1614 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1615 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1616 << "ZY" << "abc";
1617 // X || Z - X empty, Z matches "a" so "a"
1618 QTest::newRow(dataTag: "A5") << manager
1619 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << false << QVariant(false) << QVariant() << QVariant()
1620 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1621 << "XZ" << "a";
1622 // Z || X - X empty, Z matches "a" so "a"
1623 QTest::newRow(dataTag: "A6") << manager
1624 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << false << QVariant(false) << QVariant() << QVariant()
1625 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1626 << "ZX" << "a";
1627 // X || Y || Z - X empty, Y matches "bc", Z matches "a" so "abc"
1628 QTest::newRow(dataTag: "A7") << manager
1629 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1630 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1631 << "XYZ" << "abc";
1632 // X || Z || Y - X empty, Y matches "bc", Z matches "a" so "abc"
1633 QTest::newRow(dataTag: "A8") << manager
1634 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1635 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1636 << "XZY" << "abc";
1637 // Y || X || Z - X empty, Y matches "bc", Z matches "a" so "abc"
1638 QTest::newRow(dataTag: "A9") << manager
1639 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1640 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1641 << "YXZ" << "abc";
1642 // Z || X || Y - X empty, Y matches "bc", Z matches "a" so "abc"
1643 QTest::newRow(dataTag: "A10") << manager
1644 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1645 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1646 << "ZXY" << "abc";
1647 // Y || Z || X - X empty, Y matches "bc", Z matches "a" so "abc"
1648 QTest::newRow(dataTag: "A11") << manager
1649 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1650 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1651 << "YZX" << "abc";
1652 // Z || Y || X - X empty, Y matches "bc", Z matches "a" so "abc"
1653 QTest::newRow(dataTag: "A12") << manager
1654 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1655 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1656 << "ZYX" << "abc";
1657
1658 // WITH Y AND Z AS DETAIL FILTERS (with some overlap between Y and Z results)
1659 // For these tests, Y matches "bc", Z matches "b"
1660 // X || Y - X empty, Y matches "b", so "bc"
1661 QTest::newRow(dataTag: "B1") << manager
1662 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1663 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1664 << "XY" << "bc";
1665 // Y || X - X empty, Y matches "bc", so "bc"
1666 QTest::newRow(dataTag: "B2") << manager
1667 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1668 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1669 << "YX" << "bc";
1670 // Y || Z - X empty, Y matches "bc", Z matches "b" so "bc"
1671 QTest::newRow(dataTag: "B3") << manager
1672 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1673 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1674 << "YZ" << "bc";
1675 // Z || Y - X empty, Y matches "bc", Z matches "b" so "bc"
1676 QTest::newRow(dataTag: "B4") << manager
1677 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1678 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1679 << "ZY" << "bc";
1680 // X || Z - X empty, Z matches "b" so "b"
1681 QTest::newRow(dataTag: "B5") << manager
1682 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1683 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1684 << "XZ" << "b";
1685 // Z || X - X empty, Z matches "b" so "b"
1686 QTest::newRow(dataTag: "B6") << manager
1687 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1688 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1689 << "ZX" << "b";
1690 // X || Y || Z - X empty, Y matches "bc", Z matches "b" so "bc"
1691 QTest::newRow(dataTag: "B7") << manager
1692 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1693 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1694 << "XYZ" << "bc";
1695 // X || Z || Y - X empty, Y matches "bc", Z matches "b" so "bc"
1696 QTest::newRow(dataTag: "B8") << manager
1697 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1698 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1699 << "XZY" << "bc";
1700 // Y || X || Z - X empty, Y matches "bc", Z matches "b" so "bc"
1701 QTest::newRow(dataTag: "B9") << manager
1702 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1703 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1704 << "YXZ" << "bc";
1705 // Z || X || Y - X empty, Y matches "bc", Z matches "b" so "bc"
1706 QTest::newRow(dataTag: "B10") << manager
1707 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1708 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1709 << "ZXY" << "bc";
1710 // Y || Z || X - X empty, Y matches "bc", Z matches "b" so "bc"
1711 QTest::newRow(dataTag: "B11") << manager
1712 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1713 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1714 << "YZX" << "bc";
1715 // Z || Y || X - X empty, Y matches "bc", Z matches "b" so "bc"
1716 QTest::newRow(dataTag: "B12") << manager
1717 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1718 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1719 << "ZYX" << "bc";
1720 }
1721
1722 //---------------------------
1723
1724 // WITH Y AND Z AS RANGE FILTERS (with no overlap between Y and Z results)
1725 // For these tests, Y matches "a", Z matches "b"
1726 // X || Y - X empty, Y matches "a" so "a"
1727 if (validDetailField(pair: integerDefAndFieldNames)) {
1728 QTest::newRow(dataTag: "C1") << manager
1729 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1730 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1731 << "XY" << "a";
1732 // Y || X - X empty, Y matches "a" so "a"
1733 QTest::newRow(dataTag: "C2") << manager
1734 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1735 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1736 << "YX" << "a";
1737 // Y || Z - Y matches "a", Z matches "b" so "ab"
1738 QTest::newRow(dataTag: "C3") << manager
1739 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1740 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1741 << "YZ" << "ab";
1742 // Z || Y - Y matches "a", Z matches "b" so "ab"
1743 QTest::newRow(dataTag: "C4") << manager
1744 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1745 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1746 << "ZY" << "ab";
1747 // X || Z - X empty, Z matches "b" so "b"
1748 QTest::newRow(dataTag: "C5") << manager
1749 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1750 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1751 << "XZ" << "b";
1752 // Z || X - X empty, Z matches "b" so "b"
1753 QTest::newRow(dataTag: "C6") << manager
1754 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1755 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1756 << "ZX" << "b";
1757 // X || Y || Z - X empty, Y matches "a", Z matches "b" so "ab"
1758 QTest::newRow(dataTag: "C7") << manager
1759 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1760 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1761 << "XYZ" << "ab";
1762 // X || Z || Y - X empty, Y matches "a", Z matches "b" so "ab"
1763 QTest::newRow(dataTag: "C8") << manager
1764 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1765 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1766 << "XZY" << "ab";
1767 // Y || X || Z - X empty, Y matches "a", Z matches "b" so "ab"
1768 QTest::newRow(dataTag: "C9") << manager
1769 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1770 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1771 << "YXZ" << "ab";
1772 // Z || X || Y - X empty, Y matches "a", Z matches "b" so "ab"
1773 QTest::newRow(dataTag: "C10") << manager
1774 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1775 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1776 << "ZXY" << "ab";
1777 // Y || Z || X - X empty, Y matches "a", Z matches "b" so "ab"
1778 QTest::newRow(dataTag: "C11") << manager
1779 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1780 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1781 << "YZX" << "ab";
1782 // Z || Y || X - X empty, Y matches "a", Z matches "b" so "ab"
1783 QTest::newRow(dataTag: "C12") << manager
1784 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1785 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1786 << "ZYX" << "ab";
1787
1788 // WITH Y AND Z AS RANGE FILTERS (with some overlap between Y and Z results)
1789 // For these tests, Y matches "ab", Z matches "b"
1790 // X || Y - X empty, Y matches "ab" so "ab"
1791 QTest::newRow(dataTag: "D1") << manager
1792 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1793 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1794 << "XY" << "ab";
1795 // Y || X - X empty, Y matches "ab" so "ab"
1796 QTest::newRow(dataTag: "D2") << manager
1797 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1798 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1799 << "YX" << "ab";
1800 // Y || Z - Y matches "ab", Z matches "b", union = "ab"
1801 QTest::newRow(dataTag: "D3") << manager
1802 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1803 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1804 << "YZ" << "ab";
1805 // Z || Y - Y matches "ab", Z matches "b", union = "ab"
1806 QTest::newRow(dataTag: "D4") << manager
1807 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1808 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1809 << "ZY" << "ab";
1810 // X || Z - X empty, Z matches "b" so "b"
1811 QTest::newRow(dataTag: "D5") << manager
1812 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1813 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1814 << "XZ" << "b";
1815 // Z || X - X empty, Z matches "b" so "b"
1816 QTest::newRow(dataTag: "D6") << manager
1817 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1818 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1819 << "ZX" << "b";
1820 // X || Y || Z - X empty, Y matches "ab", Z matches "b" so "ab"
1821 QTest::newRow(dataTag: "D7") << manager
1822 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1823 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1824 << "XYZ" << "ab";
1825 // X || Z || Y - X empty, Y matches "ab", Z matches "b" so "ab"
1826 QTest::newRow(dataTag: "D8") << manager
1827 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1828 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1829 << "XZY" << "ab";
1830 // Y || X || Z - X empty, Y matches "ab", Z matches "b" so "ab"
1831 QTest::newRow(dataTag: "D9") << manager
1832 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1833 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1834 << "YXZ" << "ab";
1835 // Z || X || Y - X empty, Y matches "ab", Z matches "b" so "ab"
1836 QTest::newRow(dataTag: "D10") << manager
1837 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1838 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1839 << "ZXY" << "ab";
1840 // Y || Z || X - X empty, Y matches "ab", Z matches "b" so "ab"
1841 QTest::newRow(dataTag: "D11") << manager
1842 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1843 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1844 << "YZX" << "ab";
1845 // Z || Y || X - X empty, Y matches "ab", Z matches "b" so "ab"
1846 QTest::newRow(dataTag: "D12") << manager
1847 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1848 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1849 << "ZYX" << "ab";
1850 }
1851 }
1852}
1853
1854void tst_QContactManagerFiltering::unionFiltering()
1855{
1856 QFETCH(QContactManager*, cm);
1857 QFETCH(bool, firstfilter);
1858 QFETCH(int, fftype); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1859 QFETCH(QContactDetail::DetailType, ffdetailtype);
1860 QFETCH(int, ffdetailfield);
1861 QFETCH(bool, ffsetvalue);
1862 QFETCH(QVariant, ffvalue);
1863 QFETCH(QVariant, ffminrange);
1864 QFETCH(QVariant, ffmaxrange);
1865 QFETCH(bool, secondfilter);
1866 QFETCH(int, sftype);
1867 QFETCH(QContactDetail::DetailType, sfdetailtype);
1868 QFETCH(int, sfdetailfield);
1869 QFETCH(bool, sfsetvalue);
1870 QFETCH(QVariant, sfvalue);
1871 QFETCH(QVariant, sfminrange);
1872 QFETCH(QVariant, sfmaxrange);
1873 QFETCH(QString, order);
1874 QFETCH(QString, expected);
1875
1876 QContactFilter *x = new QContactUnionFilter();
1877 QContactFilter *y = 0, *z = 0;
1878
1879 if (firstfilter) {
1880 switch (fftype) {
1881 case 1: // detail filter
1882 y = new QContactDetailFilter();
1883 static_cast<QContactDetailFilter*>(y)->setDetailType(type: ffdetailtype, field: ffdetailfield);
1884 if (ffsetvalue)
1885 static_cast<QContactDetailFilter*>(y)->setValue(ffvalue);
1886 break;
1887 case 2: // range filter
1888 y = new QContactDetailRangeFilter();
1889 static_cast<QContactDetailRangeFilter*>(y)->setDetailType(type: ffdetailtype, field: ffdetailfield);
1890 static_cast<QContactDetailRangeFilter*>(y)->setRange(min: ffminrange, max: ffmaxrange);
1891 break;
1892 case 3: // group membership filter
1893 case 4: // union filter
1894 case 5: // intersection filter
1895 break;
1896
1897 default:
1898 QVERIFY(false); // force fail.
1899 break;
1900 }
1901 }
1902
1903 if (secondfilter) {
1904 switch (sftype) {
1905 case 1: // detail filter
1906 z = new QContactDetailFilter();
1907 static_cast<QContactDetailFilter*>(z)->setDetailType(type: sfdetailtype, field: sfdetailfield);
1908 if (sfsetvalue)
1909 static_cast<QContactDetailFilter*>(z)->setValue(sfvalue);
1910 break;
1911 case 2: // range filter
1912 z = new QContactDetailRangeFilter();
1913 static_cast<QContactDetailRangeFilter*>(z)->setDetailType(type: sfdetailtype, field: sfdetailfield);
1914 static_cast<QContactDetailRangeFilter*>(z)->setRange(min: sfminrange, max: sfmaxrange);
1915 break;
1916 case 3: // group membership filter
1917 case 4: // union filter
1918 case 5: // intersection filter
1919 break;
1920
1921 default:
1922 QVERIFY(false); // force fail.
1923 break;
1924 }
1925 }
1926
1927 // control variables - order: starts, ends, mids
1928 bool sX = false;
1929 bool sY = false;
1930 bool sZ = false;
1931 bool eX = false;
1932 bool eY = false;
1933 bool eZ = false;
1934 bool mX = false;
1935 bool mY = false;
1936 bool mZ = false;
1937
1938 if (order.startsWith(s: "X"))
1939 sX = true;
1940 if (order.startsWith(s: "Y"))
1941 sY = true;
1942 if (order.startsWith(s: "Z"))
1943 sZ = true;
1944 if (order.endsWith(s: "X"))
1945 eX = true;
1946 if (order.endsWith(s: "Y"))
1947 eY = true;
1948 if (order.endsWith(s: "Z"))
1949 eZ = true;
1950 if (order.size() > 2) {
1951 if (order.at(i: 1) == 'X')
1952 mX = true;
1953 if (order.at(i: 1) == 'Y')
1954 mY = true;
1955 if (order.at(i: 1) == 'Z')
1956 mZ = true;
1957 }
1958
1959 // now perform the filtering.
1960 QContactUnionFilter resultFilter;
1961 if (sX) {
1962 if (mY && eZ)
1963 resultFilter = *x | *y | *z;
1964 else if (mZ && eY)
1965 resultFilter = *x | *z | *y;
1966 else if (eY)
1967 resultFilter = *x | *y;
1968 else if (eZ)
1969 resultFilter = *x | *z;
1970 } else if (sY) {
1971 if (mX && eZ)
1972 resultFilter = *y | *x | *z;
1973 else if (mZ && eX)
1974 resultFilter = *y | *z | *x;
1975 else if (eX)
1976 resultFilter = *y | *x;
1977 else if (eZ)
1978 resultFilter = *y | *z;
1979 } else if (sZ) {
1980 if (mX && eY)
1981 resultFilter = *z | *x | *y;
1982 else if (mY && eX)
1983 resultFilter = *z | *y | *x;
1984 else if (eX)
1985 resultFilter = *z | *x;
1986 else if (eY)
1987 resultFilter = *z | *y;
1988 }
1989
1990 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
1991 QList<QContactId> ids;
1992
1993 ids = cm->contactIds(filter: resultFilter);
1994
1995 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
1996 QCOMPARE_UNSORTED(output, expected);
1997
1998 delete x;
1999 if (y) delete y;
2000 if (z) delete z;
2001}
2002
2003void tst_QContactManagerFiltering::relationshipFiltering_data()
2004{
2005 QTest::addColumn<QContactManager *>(name: "cm");
2006 QTest::addColumn<int>(name: "relatedContactRole");
2007 QTest::addColumn<QString>(name: "relationshipType");
2008 QTest::addColumn<char>(name: "relatedContact");
2009 QTest::addColumn<QString>(name: "expected");
2010
2011 const int firstRole(static_cast<int>(QContactRelationship::First));
2012 const int secondRole(static_cast<int>(QContactRelationship::Second));
2013 const int eitherRole(static_cast<int>(QContactRelationship::Either));
2014
2015 for (int i = 0; i < managers.size(); i++) {
2016 QContactManager *manager = managers.at(i);
2017
2018 // HasMember
2019 QTest::newRow(dataTag: "RF-1") << manager << secondRole << QContactRelationship::HasMember() << '\0' << "a";
2020 QTest::newRow(dataTag: "RF-2") << manager << firstRole << QContactRelationship::HasMember() << '\0' << "b";
2021 QTest::newRow(dataTag: "RF-3") << manager << eitherRole << QContactRelationship::HasMember() << '\0' << "ab";
2022
2023 // match any contact that has an assistant
2024 QTest::newRow(dataTag: "RF-4") << manager << secondRole << QContactRelationship::HasAssistant() << '\0' << "a";
2025 // match any contact that is an assistant
2026 QTest::newRow(dataTag: "RF-5") << manager << firstRole << QContactRelationship::HasAssistant() << '\0' << "b";
2027 // match any contact that has an assistant or is an assistant
2028 QTest::newRow(dataTag: "RF-6") << manager << eitherRole << QContactRelationship::HasAssistant() << '\0' << "ab";
2029
2030 // IsSameAs
2031 QTest::newRow(dataTag: "RF-7") << manager << secondRole << QContactRelationship::IsSameAs() << '\0' << "a";
2032 QTest::newRow(dataTag: "RF-8") << manager << firstRole << QContactRelationship::IsSameAs() << '\0' << "b";
2033 QTest::newRow(dataTag: "RF-9") << manager << eitherRole << QContactRelationship::IsSameAs() << '\0' << "ab";
2034
2035 // Aggregates
2036 QTest::newRow(dataTag: "RF-10") << manager << secondRole << QContactRelationship::Aggregates() << '\0' << "a";
2037 QTest::newRow(dataTag: "RF-11") << manager << firstRole << QContactRelationship::Aggregates() << '\0' << "b";
2038 QTest::newRow(dataTag: "RF-12") << manager << eitherRole << QContactRelationship::Aggregates() << '\0' << "ab";
2039
2040 // HasManager
2041 QTest::newRow(dataTag: "RF-13") << manager << secondRole << QContactRelationship::HasManager() << '\0' << "a";
2042 QTest::newRow(dataTag: "RF-14") << manager << firstRole << QContactRelationship::HasManager() << '\0' << "b";
2043 QTest::newRow(dataTag: "RF-15") << manager << eitherRole << QContactRelationship::HasManager() << '\0' << "ab";
2044
2045 // HasSpouse
2046 QTest::newRow(dataTag: "RF-16") << manager << secondRole << QContactRelationship::HasSpouse() << '\0' << "a";
2047 QTest::newRow(dataTag: "RF-17") << manager << firstRole << QContactRelationship::HasSpouse() << '\0' << "b";
2048 QTest::newRow(dataTag: "RF-18") << manager << eitherRole << QContactRelationship::HasSpouse() << '\0' << "ab";
2049
2050 // Unknown relationship
2051 QTest::newRow(dataTag: "RF-19") << manager << secondRole << QStringLiteral("UnknownRelationship") << '\0' << "a";
2052 QTest::newRow(dataTag: "RF-20") << manager << firstRole << QStringLiteral("UnknownRelationship") << '\0' << "b";
2053 QTest::newRow(dataTag: "RF-21") << manager << eitherRole << QStringLiteral("UnknownRelationship") << '\0' << "ab";
2054
2055 // match any contact that is the related contact in a relationship with contact-A
2056 QTest::newRow(dataTag: "RF-22") << manager << secondRole << QString() << 'a' << "";
2057 // match any contact has contact-A as the related contact
2058 QTest::newRow(dataTag: "RF-23") << manager << firstRole << QString() << 'a' << "b";
2059 // match any contact that has any relationship with contact-A
2060 QTest::newRow(dataTag: "RF-24") << manager << eitherRole << QString() << 'a' << "b";
2061
2062 // match any contact that is the related contact in a relationship with contact-B
2063 QTest::newRow(dataTag: "RF-25") << manager << secondRole << QString() << 'b' << "a";
2064 // match any contact has contact-B as the related contact
2065 QTest::newRow(dataTag: "RF-26") << manager << firstRole << QString() << 'b' << "";
2066 // match any contact that has any relationship with contact-B
2067 QTest::newRow(dataTag: "RF-27") << manager << eitherRole << QString() << 'b' << "a";
2068 }
2069}
2070
2071QContact tst_QContactManagerFiltering::createContact(QContactManager* cm, QContactType::TypeValues type, const QString &name)
2072{
2073 QContact contact;
2074 contact.setType(type);
2075 QContactName contactName;
2076 for (int i = QContactName::FieldPrefix; i <= QContactName::FieldSuffix; ++i) {
2077 contactName.setValue(field: i, value: name);
2078 }
2079 contact.saveDetail(detail: &contactName);
2080 cm->saveContact(contact: &contact);
2081 return contact;
2082}
2083
2084void tst_QContactManagerFiltering::relationshipFiltering()
2085{
2086 QFETCH(QContactManager*, cm);
2087 QFETCH(int, relatedContactRole);
2088 QFETCH(QString, relationshipType);
2089 QFETCH(char, relatedContact);
2090 QFETCH(QString, expected);
2091
2092 // TODO: A little re-factoring could be used to make the test case more readable
2093
2094 // 1. Create contacts to be used in relationship testing
2095 QContact contactA;
2096 if(relationshipType == QContactRelationship::HasMember()) {
2097 // Change contact type to group as this is required at least by symbian backend
2098 // TODO: should it be possible to query this constraint from the backend?
2099 contactA = createContact(cm, type: QContactType::TypeGroup, name: "ContactA");
2100 } else {
2101 contactA = createContact(cm, type: QContactType::TypeContact, name: "ContactA");
2102 }
2103 QContact contactB = createContact(cm, type: QContactType::TypeContact, name: "ContactB");
2104
2105 // 2. Create the relationship between the contacts
2106 QContact first;
2107 first.setId(contactA.id());
2108 QContact second;
2109 second.setId(contactB.id());
2110
2111 QContactRelationship h2i;
2112 h2i.setFirst(first.id());
2113 h2i.setSecond(second.id());
2114 h2i.setRelationshipType(relationshipType);
2115 // save and check error code
2116 bool succeeded = false;
2117 if(cm->isRelationshipTypeSupported(relationshipType, contactType: contactA.type())
2118 && cm->isRelationshipTypeSupported(relationshipType, contactType: contactB.type())) {
2119 succeeded = true;
2120 QVERIFY(cm->saveRelationship(&h2i));
2121 QCOMPARE(cm->error(), QContactManager::NoError);
2122 } else {
2123 QVERIFY(!cm->saveRelationship(&h2i));
2124 QCOMPARE(cm->error(), QContactManager::NotSupportedError);
2125 }
2126
2127 // 3. Construct the filter
2128 QContactRelationshipFilter crf;
2129 crf.setRelatedContactRole(static_cast<QContactRelationship::Role>(relatedContactRole));
2130 crf.setRelationshipType(relationshipType);
2131 if (relatedContact == 'a') {
2132 crf.setRelatedContactId(first.id());
2133 } else if (relatedContact == 'b') {
2134 crf.setRelatedContactId(second.id());
2135 }
2136
2137 // 4. Grab the filtering results
2138 QList<QContactId> contacts;
2139 contacts.append(t: contactA.id());
2140 contacts.append(t: contactB.id());
2141 QList<QContactId> ids = cm->contactIds(filter: crf);
2142 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2143
2144 // Check that a different relationship type does not match
2145 crf.setRelationshipType(QStringLiteral("Some other type"));
2146 QList<QContactId> ids2 = cm->contactIds(filter: crf);
2147
2148 // 5. Remove the created relationship and contacts
2149 if(succeeded) {
2150 // Check that an existing relationship can be removed
2151 QVERIFY(cm->removeRelationship(h2i));
2152 QCOMPARE(cm->error(), QContactManager::NoError);
2153 } else {
2154 // Check that non-existing relationship cannot be removed
2155 QVERIFY(!cm->removeRelationship(h2i));
2156 //TODO: what is the expected error code?
2157 //QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
2158 }
2159 foreach (const QContactId& cid, contacts) {
2160 cm->removeContact(contactId: cid);
2161 }
2162
2163 // 6. Verify the filtering result
2164 if(succeeded) {
2165 QCOMPARE_UNSORTED(output, expected);
2166 QCOMPARE(ids2, QList<QContactId>());
2167 } else {
2168 QString msg = "Manager does not support relationship type " + relationshipType + " between " + contactA.type() + " and " + contactB.type() + " type contacts.";
2169 QSKIP(msg.toLatin1());
2170 }
2171}
2172
2173void tst_QContactManagerFiltering::sorting_data()
2174{
2175 QTest::addColumn<QContactManager *>(name: "cm");
2176 QTest::addColumn<QContactDetail::DetailType>(name: "detailType");
2177 QTest::addColumn<int>(name: "detailField");
2178 QTest::addColumn<int>(name: "directioni");
2179 QTest::addColumn<bool>(name: "setbp");
2180 QTest::addColumn<int>(name: "blankpolicyi");
2181 QTest::addColumn<int>(name: "casesensitivityi");
2182 QTest::addColumn<QString>(name: "expected");
2183 QTest::addColumn<QString>(name: "unstable");
2184
2185 int firstname = QContactName::FieldFirstName;
2186 int lastname = QContactName::FieldLastName;
2187 QContactDetail::DetailType nameType = QContactName::Type;
2188 QContactDetail::DetailType dlType = QContactDisplayLabel::Type;
2189 int dlfld = QContactDisplayLabel::FieldLabel;
2190
2191 int asc = Qt::AscendingOrder;
2192 int desc = Qt::DescendingOrder;
2193 int bll = QContactSortOrder::BlanksLast;
2194 int blf = QContactSortOrder::BlanksFirst;
2195 int cs = Qt::CaseSensitive;
2196 int ci = Qt::CaseInsensitive;
2197
2198 for (int i = 0; i < managers.size(); i++) {
2199 QContactManager *manager = managers.at(i);
2200
2201 QPair<QContactDetail::DetailType, int> integerDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "Integer");
2202 QPair<QContactDetail::DetailType, int> stringDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "String");
2203
2204 newMRow(tag: "first ascending", cm: manager) << manager << nameType << firstname << asc << false << 0 << cs << expectedSorting(m: manager, ufs: "abcdefgikhj", lfs: "hjabcdefgik", iufs: "abcdefgihkj", ilfs: "abcdefghijk", fpiufs: "abcdefgihkj", fpilfs: "abcdefghijk") << "efg"; // efg have the same first name
2205 newMRow(tag: "first descending", cm: manager) << manager << nameType << firstname << desc << false << 0 << cs << expectedSorting(m: manager, ufs: "jhkigfedcba", lfs: "kigfedcbajh", iufs: "jkhigfedcba", ilfs: "kjihgfedcba", fpiufs: "jkhigfedcba", fpilfs: "kjihgfedcba") << "efg";// efg have the same first name
2206 newMRow(tag: "last ascending", cm: manager) << manager << nameType << lastname << asc << false << 0 << cs << "bacdefghijk" << "hijk"; // all have a well defined, sortable last name except hijk
2207 newMRow(tag: "last descending", cm: manager) << manager << nameType << lastname << desc << false << 0 << cs << "gfedcabhijk" << "hijk"; // all have a well defined, sortable last name except hijk
2208 if (validDetailField(pair: integerDefAndFieldNames)) {
2209 newMRow(tag: "integer ascending, blanks last", cm: manager) << manager << integerDefAndFieldNames.first << integerDefAndFieldNames.second << asc << true << bll << cs << "cabgfedhijk" << "gfedhijk"; // gfedhijk have no integer
2210 newMRow(tag: "integer descending, blanks last", cm: manager) << manager << integerDefAndFieldNames.first << integerDefAndFieldNames.second << desc << true << bll << cs << "bacgfedhijk" << "gfedhijk"; // gfedhijk have no integer
2211 newMRow(tag: "integer ascending, blanks first", cm: manager) << manager << integerDefAndFieldNames.first << integerDefAndFieldNames.second << asc << true << blf << cs << "hijkdefgcab" << "gfedhijk"; // gfedhijk have no integer
2212 newMRow(tag: "integer descending, blanks first", cm: manager) << manager << integerDefAndFieldNames.first << integerDefAndFieldNames.second << desc << true << blf << cs << "hijkdefgbac" << "gfedhijk"; // gfedhijk have no integer
2213 }
2214 if (validDetailField(pair: stringDefAndFieldNames)) {
2215 QTest::newRow(dataTag: "string ascending (null value), blanks first") << manager << stringDefAndFieldNames.first << stringDefAndFieldNames.second << asc << true << blf << cs << "feabcdg" << "fehijk"; // f and e have blank string
2216 QTest::newRow(dataTag: "string ascending (null value), blanks last") << manager << stringDefAndFieldNames.first << stringDefAndFieldNames.second << asc << true << bll << cs << "abcdgef" << "efhijk"; // f and e have blank string
2217 }
2218
2219 newMRow(tag: "display label insensitive", cm: manager) << manager << dlType << dlfld << asc << false << 0 << ci << "abcdefghjik" << "efghji";
2220 newMRow(tag: "display label sensitive", cm: manager) << manager << dlType << dlfld << asc << false << 0 << cs << "abcdefghjik" << "efg";
2221 }
2222}
2223
2224void tst_QContactManagerFiltering::sorting()
2225{
2226 QFETCH(QContactManager*, cm);
2227 QFETCH(QContactDetail::DetailType, detailType);
2228 QFETCH(int, detailField);
2229 QFETCH(int, directioni);
2230 QFETCH(bool, setbp);
2231 QFETCH(int, blankpolicyi);
2232 QFETCH(int, casesensitivityi);
2233 QFETCH(QString, expected);
2234 QFETCH(QString, unstable);
2235
2236 Qt::SortOrder direction = (Qt::SortOrder)directioni;
2237 QContactSortOrder::BlankPolicy blankpolicy = (QContactSortOrder::BlankPolicy) blankpolicyi;
2238 Qt::CaseSensitivity casesensitivity = (Qt::CaseSensitivity) casesensitivityi;
2239
2240 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
2241 QList<QContactId> ids;
2242
2243 /* Build the sort order */
2244 QContactSortOrder s;
2245 s.setDetailType(type: detailType, field: detailField);
2246 s.setDirection(direction);
2247 if (setbp)
2248 s.setBlankPolicy(blankpolicy);
2249 s.setCaseSensitivity(casesensitivity);
2250
2251 ids = cm->contactIds(sortOrders: s);
2252 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2253
2254 // It's possible to get some contacts back in an arbitrary order (since we single sort)
2255 if (unstable.length() > 1) {
2256 // ensure that the maximum distance between unstable elements in the output is the size of the unstable string.
2257 int firstIndex = -1;
2258 int lastIndex = -1;
2259
2260 for (int i = 0; i < output.size(); i++) {
2261 if (unstable.contains(c: output.at(i))) {
2262 firstIndex = i;
2263 break;
2264 }
2265 }
2266
2267 for (int i = output.size() - 1; i >= 0; i--) {
2268 if (unstable.contains(c: output.at(i))) {
2269 lastIndex = i;
2270 break;
2271 }
2272 }
2273
2274 if (firstIndex == -1 || lastIndex == -1) {
2275 bool containsAllUnstableElements = false;
2276 QVERIFY(containsAllUnstableElements);
2277 }
2278
2279 bool unstableElementsAreGrouped = ((lastIndex - firstIndex) == (unstable.length() - 1));
2280 QVERIFY(unstableElementsAreGrouped);
2281
2282 // now remove all unstable elements from the output
2283 for (int i = 1; i < unstable.length(); i++) {
2284 output.remove(c: unstable.at(i));
2285 expected.remove(c: unstable.at(i));
2286 }
2287 }
2288
2289 // These tests pass only due to the un-sorted order matching the tested order:
2290 //QEXPECT_FAIL("display label insensitive[memory]", "memory backend does not add QContactDisplayLabel details", Continue);
2291 //QEXPECT_FAIL("display label insensitive[memory[params]]", "memory backend does not add QContactDisplayLabel details", Continue);
2292 QEXPECT_FAIL("display label sensitive[memory]", "memory backend does not add QContactDisplayLabel details", Continue);
2293 QEXPECT_FAIL("display label sensitive[memory[params]]", "memory backend does not add QContactDisplayLabel details", Continue);
2294 QCOMPARE(output, expected);
2295
2296 /* Now do a check with a filter involved; the filter should not affect the sort order */
2297 QContactDetailFilter presenceName;
2298 presenceName.setDetailType(type: QContactName::Type);
2299
2300 ids = cm->contactIds(filter: presenceName, sortOrders: s);
2301
2302 output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2303
2304 // It's possible to get some contacts back in an arbitrary order (since we single sort)
2305 if (unstable.length() > 1) {
2306 // ensure that the maximum distance between unstable elements in the output is the size of the unstable string.
2307 int firstIndex = -1;
2308 int lastIndex = -1;
2309
2310 for (int i = 0; i < output.size(); i++) {
2311 if (unstable.contains(c: output.at(i))) {
2312 firstIndex = i;
2313 break;
2314 }
2315 }
2316
2317 for (int i = output.size() - 1; i >= 0; i--) {
2318 if (unstable.contains(c: output.at(i))) {
2319 lastIndex = i;
2320 break;
2321 }
2322 }
2323
2324 if (firstIndex == -1 || lastIndex == -1) {
2325 bool containsAllUnstableElements = false;
2326 QVERIFY(containsAllUnstableElements);
2327 }
2328
2329 bool unstableElementsAreGrouped = ((lastIndex - firstIndex) == (unstable.length() - 1));
2330 QVERIFY(unstableElementsAreGrouped);
2331
2332 // now remove all unstable elements from the output
2333 for (int i = 1; i < unstable.length(); i++) {
2334 output.remove(c: unstable.at(i));
2335 expected.remove(c: unstable.at(i));
2336 }
2337 }
2338
2339 //QEXPECT_FAIL("display label insensitive[memory]", "memory backend does not add QContactDisplayLabel details", Continue);
2340 //QEXPECT_FAIL("display label insensitive[memory[params]]", "memory backend does not add QContactDisplayLabel details", Continue);
2341 QEXPECT_FAIL("display label sensitive[memory]", "memory backend does not add QContactDisplayLabel details", Continue);
2342 QEXPECT_FAIL("display label sensitive[memory[params]]", "memory backend does not add QContactDisplayLabel details", Continue);
2343 QCOMPARE(output, expected);
2344}
2345
2346void tst_QContactManagerFiltering::multiSorting_data()
2347{
2348 QTest::addColumn<QContactManager *>(name: "cm");
2349
2350 QTest::addColumn<bool>(name: "firstsort");
2351 QTest::addColumn<QContactDetail::DetailType>(name: "fsdetailtype");
2352 QTest::addColumn<int>(name: "fsdetailfield");
2353 QTest::addColumn<int>(name: "fsdirectioni");
2354
2355 QTest::addColumn<bool>(name: "secondsort");
2356 QTest::addColumn<QContactDetail::DetailType>(name: "ssdetailtype");
2357 QTest::addColumn<int>(name: "ssdetailfield");
2358 QTest::addColumn<int>(name: "ssdirectioni");
2359
2360 QTest::addColumn<QString>(name: "expected");
2361 QTest::addColumn<bool>(name: "efgunstable");
2362
2363
2364 QString es;
2365
2366 int firstname = QContactName::FieldFirstName;
2367 int lastname = QContactName::FieldLastName;
2368 QContactDetail::DetailType nameType = QContactName::Type;
2369 QContactDetail::DetailType phoneType = QContactPhoneNumber::Type;
2370 int numberfield = QContactPhoneNumber::FieldNumber;
2371
2372 int asc = Qt::AscendingOrder;
2373 int desc = Qt::DescendingOrder;
2374
2375 for (int i = 0; i < managers.size(); i++) {
2376 QContactManager *manager = managers.at(i);
2377 QPair<QContactDetail::DetailType, int> stringDefAndFieldNames = defAndFieldNamesForTypePerManager.value(akey: manager).value(akey: "String");
2378
2379 QTest::newRow(dataTag: "1") << manager
2380 << true << nameType << firstname << asc
2381 << true << nameType << lastname << asc
2382 << "abcdefg" << false;
2383 QTest::newRow(dataTag: "2") << manager
2384 << true << nameType << firstname << asc
2385 << true << nameType << lastname << desc
2386 << "abcdgfe" << false;
2387 QTest::newRow(dataTag: "3") << manager
2388 << true << nameType << firstname << desc
2389 << true << nameType << lastname << asc
2390 << "efgdcba" << false;
2391 QTest::newRow(dataTag: "4") << manager
2392 << true << nameType << firstname << desc
2393 << true << nameType << lastname << desc
2394 << "gfedcba" << false;
2395
2396 QTest::newRow(dataTag: "5") << manager
2397 << true << nameType << firstname << asc
2398 << false << nameType << lastname << asc
2399 << "abcdefg" << true;
2400
2401 QTest::newRow(dataTag: "5b") << manager
2402 << true << nameType << firstname << asc
2403 << true << static_cast<QContactDetail::DetailType>(-1) << -1 << asc
2404 << "abcdefg" << true;
2405
2406 QTest::newRow(dataTag: "6") << manager
2407 << false << nameType << firstname << asc
2408 << true << nameType << lastname << asc
2409 << "bacdefg" << false;
2410
2411 // This test is completely unstable; no sort criteria means dependent upon internal sort order of manager.
2412 //QTest::newRow("7") << manager
2413 // << false << nameType << firstname << asc
2414 // << false << nameType << lastname << asc
2415 // << "abcdefg" << false; // XXX Isn't this totally unstable?
2416
2417 if (validDetailField(pair: stringDefAndFieldNames)) {
2418 QTest::newRow(dataTag: "8") << manager
2419 << true << stringDefAndFieldNames.first << stringDefAndFieldNames.second << asc
2420 << false << stringDefAndFieldNames.first << stringDefAndFieldNames.second << desc
2421 << "abcdgef" << false; // default policy = blanks last, and ef have no value (e is empty, f is null)
2422
2423 QTest::newRow(dataTag: "8b") << manager
2424 << true << stringDefAndFieldNames.first << stringDefAndFieldNames.second << asc
2425 << false << static_cast<QContactDetail::DetailType>(-1) << -1 << desc
2426 << "abcdgef" << false; // default policy = blanks last, and ef have no value (e is empty, f is null)
2427 }
2428
2429 QTest::newRow(dataTag: "9") << manager
2430 << true << phoneType << numberfield << asc
2431 << true << nameType << lastname << desc
2432 << "abgfedc" << false;
2433
2434 QTest::newRow(dataTag: "10") << manager
2435 << true << nameType << firstname << asc
2436 << true << nameType << firstname << desc
2437 << "abcdefg" << true;
2438
2439 }
2440}
2441
2442void tst_QContactManagerFiltering::multiSorting()
2443{
2444 QFETCH(QContactManager*, cm);
2445 QFETCH(bool, firstsort);
2446 QFETCH(QContactDetail::DetailType, fsdetailtype);
2447 QFETCH(int, fsdetailfield);
2448 QFETCH(int, fsdirectioni);
2449 QFETCH(bool, secondsort);
2450 QFETCH(QContactDetail::DetailType, ssdetailtype);
2451 QFETCH(int, ssdetailfield);
2452 QFETCH(int, ssdirectioni);
2453 QFETCH(QString, expected);
2454 QFETCH(bool, efgunstable);
2455
2456 Qt::SortOrder fsdirection = (Qt::SortOrder)fsdirectioni;
2457 Qt::SortOrder ssdirection = (Qt::SortOrder)ssdirectioni;
2458
2459 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
2460
2461 /* Build the sort orders */
2462 QContactSortOrder fs;
2463 fs.setDetailType(type: fsdetailtype, field: fsdetailfield);
2464 fs.setDirection(fsdirection);
2465 QContactSortOrder ss;
2466 ss.setDetailType(type: ssdetailtype, field: ssdetailfield);
2467 ss.setDirection(ssdirection);
2468 QList<QContactSortOrder> sortOrders;
2469 if (firstsort)
2470 sortOrders.append(t: fs);
2471 if (secondsort)
2472 sortOrders.append(t: ss);
2473
2474 QList<QContactId> ids = cm->contactIds(sortOrders);
2475 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2476
2477 // Remove the display label tests
2478 output.remove(c: 'h');
2479 output.remove(c: 'i');
2480 output.remove(c: 'j');
2481 output.remove(c: 'k');
2482
2483 // Just like the single sort test, we might get some contacts back in indeterminate order
2484 // (but their relative position with other contacts should not change)
2485 if (efgunstable) {
2486 QVERIFY(output.count('e') == 1);
2487 QVERIFY(output.count('f') == 1);
2488 QVERIFY(output.count('g') == 1);
2489 output.remove(c: 'f');
2490 output.remove(c: 'g');
2491 expected.remove(c: 'f');
2492 expected.remove(c: 'g');
2493 }
2494
2495 QCOMPARE(output, expected);
2496}
2497
2498#ifdef INCLUDE_TESTACTIONS
2499void tst_QContactManagerFiltering::actionPlugins()
2500{
2501 QStringList actions = QContactAction::availableActions();
2502 QVERIFY(actions.contains("Boolean"));
2503 QVERIFY(actions.contains("Number"));
2504
2505 /* Ignore the version if the vendor is not set */
2506 actions = QContactAction::availableActions(QString());
2507 QVERIFY(actions.contains("Boolean"));
2508 QVERIFY(actions.contains("Number"));
2509
2510 actions = QContactAction::availableActions("NumberCo");
2511 QVERIFY(actions.contains("Number"));
2512 QVERIFY(!actions.contains("Boolean"));
2513
2514 actions = QContactAction::availableActions("IntegerCo");
2515 QVERIFY(actions.contains("Number"));
2516 QVERIFY(!actions.contains("Boolean"));
2517
2518 actions = QContactAction::availableActions("BooleanCo");
2519 QVERIFY(!actions.contains("Number"));
2520 QVERIFY(actions.contains("Boolean"));
2521
2522 actions = QContactAction::availableActions("IntegerCo");
2523 QVERIFY(actions.contains("Number"));
2524 QVERIFY(!actions.contains("Boolean"));
2525
2526 actions = QContactAction::availableActions("BooleanCo");
2527 QVERIFY(!actions.contains("Number"));
2528 QVERIFY(actions.contains("Boolean"));
2529}
2530
2531void tst_QContactManagerFiltering::actionFiltering_data()
2532{
2533 QTest::addColumn<QContactManager *>("cm");
2534 QTest::addColumn<QString>("actionName");
2535 QTest::addColumn<QString>("expected");
2536
2537 QString es;
2538
2539 for (int i = 0; i < managers.size(); i++) {
2540 QContactManager *manager = managers.at(i);
2541 QPair<QContactDetail::DetailType, int> booleanDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Bool");
2542 QPair<QContactDetail::DetailType, int> integerDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Integer");
2543 QPair<QContactDetail::DetailType, int> dateDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Date");
2544
2545 newMRow("bad actionname", manager) << manager << "No such action" << "";
2546
2547 QString expected;
2548 if (validDetailField(integerDefAndFieldNames) || validDetailField(booleanDefAndFieldNames)) {
2549 expected = "abcd";
2550 } else if (validDetailField(dateDefAndFieldNames)) {
2551 expected = "abd";
2552 } else {
2553 /* contact a,b have phone number, so at least phone number action can match them */
2554 expected = "ab";
2555 }
2556
2557 QTest::newRow("empty (any action matches)") << manager << es << expected;
2558
2559 if (validDetailField(integerDefAndFieldNames)) {
2560 newMRow("Number", manager) << manager << "NumberAction" << "abcd";
2561 QTest::newRow("Number (NumberCo)") << manager << "NumberAction" << "abcd";
2562 }
2563
2564 if (validDetailField(booleanDefAndFieldNames)) {
2565 /* Boolean testing */
2566 newMRow("Boolean action", manager) << manager << "BooleanAction" << "a";
2567 newMRow("BooleanCo", manager) << manager << es << "a";
2568 }
2569
2570 if (validDetailField(booleanDefAndFieldNames)) {
2571 newMRow("Boolean action matching true", manager) << manager << es << "a";
2572 newMRow("Boolean action matching false", manager) << manager << es << es;
2573 }
2574
2575 /* Recursive filtering */
2576 QTest::newRow("Recursive action 1") << manager << "IntersectionRecursive" << es;
2577 QTest::newRow("Recursive action 2") << manager << "UnionRecursive" << es;
2578 QTest::newRow("Recursive action 3") << manager << "PairRecursive" << es;
2579 QTest::newRow("Recursive action 4") << manager << "AnotherPairRecursive" << es;
2580 QTest::newRow("Recursive action 5") << manager << "Recursive" << es;
2581 }
2582}
2583
2584void tst_QContactManagerFiltering::actionFiltering()
2585{
2586 QFETCH(QContactManager*, cm);
2587 QFETCH(QString, actionName);
2588 QFETCH(QString, expected);
2589
2590 // only test the memory engine - action filtering + service framework plugin loading
2591 // codepaths are tested fully this way since the codepath for other engines is that of
2592 // the memory engine, and only the memory engine has the required definitions and fields.
2593 if (cm->managerName() != QString(QLatin1String("memory")))
2594 return;
2595
2596 /* Load the definition and field names for the various variant types for the current manager */
2597 defAndFieldNamesForTypeForActions = defAndFieldNamesForTypePerManager.value(cm);
2598 if (!defAndFieldNamesForTypeForActions.isEmpty()) {
2599 QContactActionFilter af;
2600 af.setActionName(actionName);
2601
2602 QList<QContactId> ids = cm->contactIds(af);
2603 QList<QContactId> contacts = contactsAddedToManagers.values(cm);
2604
2605qDebug() << " actionName =" << actionName;
2606
2607 QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
2608 QCOMPARE_UNSORTED(output, expected);
2609 }
2610}
2611#endif
2612
2613void tst_QContactManagerFiltering::idListFiltering_data()
2614{
2615 QTest::addColumn<QContactManager *>(name: "cm");
2616 QTest::addColumn<QString>(name: "input");
2617 QTest::addColumn<QString>(name: "expected");
2618
2619 QString es;
2620
2621 for (int i = 0; i < managers.size(); i++) {
2622 QContactManager *manager = managers.at(i);
2623 newMRow(tag: "empty", cm: manager) << manager << es << es;
2624 newMRow(tag: "a", cm: manager) << manager << "a" << "a";
2625 newMRow(tag: "ab", cm: manager) << manager << "ab" << "ab";
2626 newMRow(tag: "aa", cm: manager) << manager << "aa" << "a";
2627 newMRow(tag: "ba", cm: manager) << manager << "ba" << "ab";
2628 newMRow(tag: "abcd", cm: manager) << manager << "abcd" << "abcd";
2629 newMRow(tag: "abcde", cm: manager) << manager << "abcde" << "abcd";
2630 }
2631}
2632
2633void tst_QContactManagerFiltering::idListFiltering()
2634{
2635 QFETCH(QContactManager*, cm);
2636 QFETCH(QString, input);
2637 QFETCH(QString, expected);
2638
2639 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
2640 QList<QContactId> ids;
2641
2642 // extra id that won't exist
2643 QContactId e;
2644
2645 /* Convert the input to a list of ids */
2646 foreach(QChar c, input) {
2647 if (c == 'a')
2648 ids << contacts.at(i: 0);
2649 else if (c == 'b')
2650 ids << contacts.at(i: 1);
2651 else if (c == 'c')
2652 ids << contacts.at(i: 2);
2653 else if (c == 'd')
2654 ids << contacts.at(i: 3);
2655 else if (c == 'e')
2656 ids << e;
2657 }
2658
2659 /* And do the search */
2660 QContactIdFilter idf;
2661 idf.setIds(ids);
2662
2663 /* Retrieve contacts matching the filter, and compare (unsorted) output */
2664 ids = cm->contactIds(filter: idf);
2665 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2666 QCOMPARE_UNSORTED(output, expected);
2667}
2668
2669void tst_QContactManagerFiltering::convenienceFiltering_data()
2670{
2671 QTest::addColumn<QContactManager *>(name: "cm");
2672 QTest::addColumn<QString>(name: "addressSubString");
2673 QTest::addColumn<bool>(name: "addressEnabled");
2674 QTest::addColumn<QString>(name: "emailAddressSubString");
2675 QTest::addColumn<bool>(name: "emailEnabled");
2676 QTest::addColumn<QString>(name: "phoneSubString");
2677 QTest::addColumn<bool>(name: "phoneEnabled");
2678 QTest::addColumn<QString>(name: "displayLabelSubString");
2679 QTest::addColumn<bool>(name: "displayLabelEnabled");
2680 QTest::addColumn<QString>(name: "nameSubString");
2681 QTest::addColumn<bool>(name: "nameEnabled");
2682 QTest::addColumn<bool>(name: "favoriteEnabled");
2683 QTest::addColumn<QString>(name: "tagSubString");
2684 QTest::addColumn<bool>(name: "tagEnabled");
2685 QTest::addColumn<QString>(name: "expected");
2686
2687 QString es; // empty string
2688
2689 foreach (QContactManager *manager, managers) {
2690 const QList<QContactDetail::DetailType> supportedTypes(manager->supportedContactDetailTypes());
2691 if (supportedTypes.contains(t: QContactAddress::Type)) {
2692 newMRow(tag: "address matching only", cm: manager) << manager
2693 << "streetstring" << true
2694 << es << false
2695 << es << false
2696 << es << false
2697 << es << false
2698 << false // Favorite has no substring associated.
2699 << es << false
2700 << "l";
2701 }
2702 if (supportedTypes.contains(t: QContactEmailAddress::Type)) {
2703 newMRow(tag: "emailAddress matching only", cm: manager) << manager
2704 << es << false
2705 << "@test.com" << true
2706 << es << false
2707 << es << false
2708 << es << false
2709 << false
2710 << es << false
2711 << "m";
2712 }
2713 if (supportedTypes.contains(t: QContactPhoneNumber::Type)) {
2714 newMRow(tag: "phone matching only", cm: manager) << manager
2715 << es << false
2716 << es << false
2717 << "12345" << true
2718 << es << false
2719 << es << false
2720 << false
2721 << es << false
2722 << "n";
2723 }
2724 if (supportedTypes.contains(t: QContactDisplayLabel::Type)) {
2725 newMRow(tag: "displayLabel matching only", cm: manager) << manager
2726 << es << false
2727 << es << false
2728 << es << false
2729 << "Freddy" << true
2730 << es << false
2731 << false
2732 << es << false
2733 << "o";
2734 }
2735 if (supportedTypes.contains(t: QContactName::Type)) {
2736 newMRow(tag: "name matching only", cm: manager) << manager
2737 << es << false
2738 << es << false
2739 << es << false
2740 << es << false
2741 << "Frederic" << true
2742 << false
2743 << es << false
2744 << "p";
2745 }
2746 if (supportedTypes.contains(t: QContactFavorite::Type)) {
2747 newMRow(tag: "favorite matching only", cm: manager) << manager
2748 << es << false
2749 << es << false
2750 << es << false
2751 << es << false
2752 << es << false
2753 << true
2754 << es << false
2755 << "q";
2756 }
2757 if (supportedTypes.contains(t: QContactTag::Type)) {
2758 newMRow(tag: "tag matching only", cm: manager) << manager
2759 << es << false
2760 << es << false
2761 << es << false
2762 << es << false
2763 << es << false
2764 << false
2765 << "Football" << true
2766 << "r";
2767 }
2768 if (supportedTypes.contains(t: QContactAddress::Type) &&
2769 supportedTypes.contains(t: QContactPhoneNumber::Type)) {
2770 newMRow(tag: "address or phone matching", cm: manager) << manager
2771 << "streetstring" << true
2772 << es << false
2773 << "12345" << true
2774 << es << false
2775 << es << false
2776 << false
2777 << es << false
2778 << "ln";
2779 }
2780 if (supportedTypes.contains(t: QContactFavorite::Type) &&
2781 supportedTypes.contains(t: QContactTag::Type)) {
2782 newMRow(tag: "favorite or tag matching", cm: manager) << manager
2783 << es << false
2784 << es << false
2785 << es << false
2786 << es << false
2787 << es << false
2788 << true
2789 << "Football" << true
2790 << "qr";
2791 }
2792 }
2793}
2794
2795void tst_QContactManagerFiltering::convenienceFiltering()
2796{
2797 QFETCH(QContactManager*, cm);
2798 QFETCH(QString, addressSubString);
2799 QFETCH(bool, addressEnabled);
2800 QFETCH(QString, emailAddressSubString);
2801 QFETCH(bool, emailEnabled);
2802 QFETCH(QString, phoneSubString);
2803 QFETCH(bool, phoneEnabled);
2804 QFETCH(QString, displayLabelSubString);
2805 QFETCH(bool, displayLabelEnabled);
2806 QFETCH(QString, nameSubString);
2807 QFETCH(bool, nameEnabled);
2808 QFETCH(bool, favoriteEnabled);
2809 QFETCH(QString, tagSubString);
2810 QFETCH(bool, tagEnabled);
2811 QFETCH(QString, expected);
2812
2813 QContactFilter af = QContactAddress::match(subString: addressSubString);
2814 QContactFilter ef = QContactEmailAddress::match(emailAddress: emailAddressSubString);
2815 QContactFilter pf = QContactPhoneNumber::match(number: phoneSubString);
2816 QContactFilter df = QContactDisplayLabel::match(label: displayLabelSubString);
2817 QContactFilter nf = QContactName::match(name: nameSubString);
2818 QContactFilter ff = QContactFavorite::match();
2819 QContactFilter tf = QContactTag::match(subString: tagSubString);
2820
2821 QList<QContactFilter> convenienceFilters;
2822 if (addressEnabled) convenienceFilters << af;
2823 if (emailEnabled) convenienceFilters << ef;
2824 if (phoneEnabled) convenienceFilters << pf;
2825 if (displayLabelEnabled) convenienceFilters << df;
2826 if (nameEnabled) convenienceFilters << nf;
2827 if (favoriteEnabled) convenienceFilters << ff;
2828 if (tagEnabled) convenienceFilters << tf;
2829
2830 QContactFilter finalFilter;
2831 finalFilter = convenienceFilters.at(i: 0);
2832 if (convenienceFilters.size() > 1) {
2833 for (int i = 1; i < convenienceFilters.size(); ++i) {
2834 // if more than one filter, we union them.
2835 finalFilter = (finalFilter | convenienceFilters.at(i));
2836 }
2837 }
2838
2839 /* Retrieve contacts matching the filter, and ensure that the results are expected */
2840 QList<QContactId> ids = cm->contactIds(filter: finalFilter);
2841
2842 // build a string containing letters corresponding to the ids we retrieved.
2843 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
2844 QString resultString = convertIds(allIds: contacts, ids, minimumContact: 'l', maximumContact: 'r'); // just the convenience filtering contacts (L->R)
2845 QEXPECT_FAIL("displayLabel matching only[memory]", "memory backend does not add QContactDisplayLabel details", Continue);
2846 QEXPECT_FAIL("displayLabel matching only[memory[params]]", "memory backend does not add QContactDisplayLabel details", Continue);
2847 QCOMPARE(resultString, expected);
2848}
2849
2850void tst_QContactManagerFiltering::invalidFiltering_data()
2851{
2852 QTest::addColumn<QContactManager*>(name: "cm");
2853
2854 for (int i = 0; i < managers.size(); i++) {
2855 QContactManager *manager = managers.at(i);
2856 QTest::newRow(dataTag: manager->managerName().toLatin1().constData()) << manager;
2857 }
2858}
2859
2860void tst_QContactManagerFiltering::invalidFiltering()
2861{
2862 QFETCH(QContactManager*, cm);
2863
2864 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
2865 QContactInvalidFilter f; // invalid
2866 QList<QContactId> ids = cm->contactIds(filter: f);
2867 QVERIFY(ids.count() == 0);
2868
2869 // Try unions/intersections of invalids too
2870 ids = cm->contactIds(filter: f | f);
2871 QVERIFY(ids.count() == 0);
2872
2873 ids = cm->contactIds(filter: f & f);
2874 QVERIFY(ids.count() == 0);
2875}
2876
2877void tst_QContactManagerFiltering::allFiltering_data()
2878{
2879 QTest::addColumn<QContactManager*>(name: "cm");
2880
2881 for (int i = 0; i < managers.size(); i++) {
2882 QContactManager *manager = managers.at(i);
2883 QTest::newRow(dataTag: manager->managerName().toLatin1().constData()) << manager;
2884 }
2885}
2886
2887void tst_QContactManagerFiltering::allFiltering()
2888{
2889 QFETCH(QContactManager*, cm);
2890
2891 QList<QContactId> contacts = contactsAddedToManagers.values(akey: cm);
2892 QContactFilter f; // default = permissive
2893 QList<QContactId> ids = cm->contactIds(filter: f);
2894 QVERIFY(ids.count() == contacts.size());
2895 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2896 QString expected = convertIds(allIds: contacts, ids: contacts, minimumContact: 'a', maximumContact: 'k'); // :)
2897 QCOMPARE_UNSORTED(output, expected);
2898
2899 // Try unions/intersections of defaults
2900 ids = cm->contactIds(filter: f | f);
2901 output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2902 QCOMPARE_UNSORTED(output, expected);
2903
2904 ids = cm->contactIds(filter: f & f);
2905 output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'k'); // don't include the convenience filtering contacts
2906 QCOMPARE_UNSORTED(output, expected);
2907}
2908
2909void tst_QContactManagerFiltering::fetchHint_data()
2910{
2911 QTest::addColumn<QContactManager*>(name: "cm");
2912
2913 for (int i = 0; i < managers.size(); i++) {
2914 QContactManager *manager = managers.at(i);
2915 QTest::newRow(dataTag: manager->managerName().toLatin1().constData()) << manager;
2916 }
2917}
2918
2919void tst_QContactManagerFiltering::fetchHint()
2920{
2921 QFETCH(QContactManager*, cm);
2922
2923 // if no fetch hint is provided, the manager should return all data
2924 // if a fetch hint is provided, it should have a clearly defined effect,
2925 // unless it is ignored by the manager, in which case the result should
2926 // be equivalent to not providing a fetch hint.
2927
2928 // we use a defined sort order for the retrieval of contacts to make comparison simple.
2929 // We sort on name, because we include name details in the fetch hint.
2930 QList<QContactSortOrder> nameSort;
2931 QContactSortOrder firstNameSort, middleNameSort, lastNameSort;
2932 firstNameSort.setDetailType(type: QContactName::Type, field: QContactName::FieldFirstName);
2933 middleNameSort.setDetailType(type: QContactName::Type, field: QContactName::FieldMiddleName);
2934 lastNameSort.setDetailType(type: QContactName::Type, field: QContactName::FieldLastName);
2935 nameSort << lastNameSort << middleNameSort << firstNameSort;
2936
2937 // fetch all contacts from the manager.
2938 QList<QContact> allContacts = cm->contacts(sortOrders: nameSort);
2939
2940 // define some maximum count limit, and some list of detail definitions to retrieve.
2941 int countLimit = (allContacts.size() / 2) + 1;
2942 QList<QContactDetail::DetailType> defs;
2943 defs << QContactName::Type
2944 << QContactPhoneNumber::Type;
2945
2946 // test that the manager doesn't incorrectly implement fetch hints.
2947 // we test max count limit, and detail definition limits.
2948 // XXX TODO: other hints!
2949 QContactFetchHint mclh; // max count limited hint
2950 QContactFetchHint ddh; // detail definitions hint
2951 mclh.setMaxCountHint(countLimit);
2952 ddh.setDetailTypesHint(defs);
2953
2954 // the next part of the test requires some contacts to be saved in the manager.
2955 if (allContacts.size() == 0) {
2956 QSKIP("No contacts in manager; skipping fetch hint limit test.");
2957 }
2958
2959 // test with a hint which sets a maximum count limit for retrieved contacts.
2960 QList<QContact> mclhContacts = cm->contacts(sortOrders: nameSort, fetchHint: mclh);
2961 QVERIFY(allContacts.size() >= mclhContacts.size());
2962 if (allContacts.size() > mclh.maxCountHint()) {
2963 // shouldn't return an arbitrarily smaller amount of contacts.
2964 QVERIFY(mclhContacts.size() == mclh.maxCountHint()
2965 || mclhContacts.size() == allContacts.size());
2966 }
2967 for (int i = 0; i < mclhContacts.size(); ++i) {
2968 // the sort order should still be defined.
2969 QVERIFY(mclhContacts.at(i) == allContacts.at(i));
2970 }
2971
2972 // now test with a hint which describes which details the client is interested in.
2973 QList<QContact> ddhContacts = cm->contacts(sortOrders: nameSort, fetchHint: ddh);
2974 QCOMPARE(ddhContacts.size(), allContacts.size());
2975 for (int i = 0; i < allContacts.size(); ++i) {
2976 QContact a = allContacts.at(i);
2977 QContact b = ddhContacts.at(i);
2978
2979 // since we're sorting on a detail which should exist (since it was included in the hint)
2980 // the order of the contacts returned shouldn't have changed.
2981 QVERIFY(a.id() == b.id());
2982
2983 // check that the hint didn't remove names or phones.
2984 QCOMPARE(a.details(QContactName::Type).size(),
2985 b.details(QContactName::Type).size());
2986 QCOMPARE(a.details(QContactPhoneNumber::Type).size(),
2987 b.details(QContactPhoneNumber::Type).size());
2988
2989 // other details are not necessarily returned.
2990 QVERIFY(a.details().size() >= b.details().size());
2991 }
2992}
2993
2994
2995void tst_QContactManagerFiltering::changelogFiltering_data()
2996{
2997 QTest::addColumn<QContactManager *>(name: "cm");
2998 QTest::addColumn<QList<QContactId> >(name: "contacts");
2999 QTest::addColumn<int>(name: "eventType");
3000 QTest::addColumn<QDateTime>(name: "since");
3001 QTest::addColumn<QString>(name: "expected");
3002
3003 int added = (int)QContactChangeLogFilter::EventAdded;
3004 int changed = (int)QContactChangeLogFilter::EventChanged;
3005 int removed = (int)QContactChangeLogFilter::EventRemoved;
3006
3007 for (int i = 0; i < managers.size(); i++) {
3008 QContactManager *manager = managers.at(i);
3009
3010 QList<QContactId> contacts = contactsAddedToManagers.values(akey: manager);
3011 QContact a,b,c,d;
3012 a = manager->contact(contactId: contacts.at(i: 0));
3013 b = manager->contact(contactId: contacts.at(i: 1));
3014 c = manager->contact(contactId: contacts.at(i: 2));
3015 d = manager->contact(contactId: contacts.at(i: 3));
3016
3017 QDateTime ac = a.detail<QContactTimestamp>().created();
3018 QDateTime bc = b.detail<QContactTimestamp>().created();
3019 QDateTime cc = c.detail<QContactTimestamp>().created();
3020 QDateTime dc = d.detail<QContactTimestamp>().created();
3021
3022 QDateTime am = a.detail<QContactTimestamp>().lastModified();
3023 QDateTime bm = b.detail<QContactTimestamp>().lastModified();
3024 QDateTime cm = c.detail<QContactTimestamp>().lastModified();
3025 QDateTime dm = d.detail<QContactTimestamp>().lastModified();
3026
3027 newMRow(tag: "Added since before start", cm: manager) << manager << contacts << added << ac.addSecs(secs: -1) << "abcdefg";
3028 newMRow(tag: "Added since first", cm: manager) << manager << contacts << added << ac << "abcdefg";
3029 newMRow(tag: "Added since second", cm: manager) << manager << contacts << added << bc << "bcdefg";
3030 newMRow(tag: "Added since third", cm: manager) << manager << contacts << added << cc << "cdefg";
3031 newMRow(tag: "Added since fourth", cm: manager) << manager << contacts << added << dc << "defg";
3032 newMRow(tag: "Added since after fourth", cm: manager) << manager << contacts << added << dc.addSecs(secs: 1) << "efg";
3033 newMRow(tag: "Added since first changed", cm: manager) << manager << contacts << added << am << "";
3034 newMRow(tag: "Added since second changed", cm: manager) << manager << contacts << added << bm << "";
3035 newMRow(tag: "Added since third changed", cm: manager) << manager << contacts << added << cm << "";
3036 newMRow(tag: "Added since fourth changed", cm: manager) << manager << contacts << added << cm << "";
3037
3038 newMRow(tag: "Changed since before start", cm: manager) << manager << contacts << changed << ac.addSecs(secs: -1) << "abcdefg";
3039 newMRow(tag: "Changed since first", cm: manager) << manager << contacts << changed << ac << "abcdefg";
3040 newMRow(tag: "Changed since second", cm: manager) << manager << contacts << changed << bc << "abcdefg";
3041 newMRow(tag: "Changed since third", cm: manager) << manager << contacts << changed << cc << "abcdefg";
3042 newMRow(tag: "Changed since fourth", cm: manager) << manager << contacts << changed << dc << "abcdefg";
3043 newMRow(tag: "Changed since after fourth", cm: manager) << manager << contacts << changed << dc.addSecs(secs: 1) << "abcefg";
3044 newMRow(tag: "Changed since first changed", cm: manager) << manager << contacts << changed << am << "a";
3045 newMRow(tag: "Changed since second changed", cm: manager) << manager << contacts << changed << bm << "ab";
3046 newMRow(tag: "Changed since third changed", cm: manager) << manager << contacts << changed << cm << "abc";
3047 newMRow(tag: "Changed since fourth changed", cm: manager) << manager << contacts << changed << dm << "abcdefg";
3048
3049 // These are currently useless..
3050 newMRow(tag: "Removed since before start", cm: manager) << manager << contacts << removed << ac.addSecs(secs: -1) << "";
3051 newMRow(tag: "Removed since first", cm: manager) << manager << contacts << removed << ac << "";
3052 newMRow(tag: "Removed since second", cm: manager) << manager << contacts << removed << bc << "";
3053 newMRow(tag: "Removed since third", cm: manager) << manager << contacts << removed << cc << "";
3054 newMRow(tag: "Removed since fourth", cm: manager) << manager << contacts << removed << dc << "";
3055 newMRow(tag: "Removed since after fourth", cm: manager) << manager << contacts << removed << dc.addSecs(secs: 1) << "";
3056 }
3057}
3058
3059void tst_QContactManagerFiltering::changelogFiltering()
3060{
3061 QFETCH(int, eventType);
3062 QFETCH(QDateTime, since);
3063 QFETCH(QString, expected);
3064 QFETCH(QContactManager*, cm);
3065 QFETCH(QList<QContactId>, contacts);
3066
3067 QList<QContactId> ids;
3068
3069 QContactChangeLogFilter clf((QContactChangeLogFilter::EventType)eventType);
3070 clf.setSince(since);
3071
3072 ids = cm->contactIds(filter: clf);
3073
3074 QString output = convertIds(allIds: contacts, ids, minimumContact: 'a', maximumContact: 'g'); // don't include the convenience filtering contacts
3075 QCOMPARE(output, expected); // unsorted? or sorted?
3076}
3077
3078QList<QContactId> tst_QContactManagerFiltering::prepareModel(QContactManager *cm)
3079{
3080 // Sleep between contact additions to allow change log filtering to differentiate contacts by timestamp
3081 // Assume 1-second resolution or better
3082 const int napTime = 1000;
3083
3084 QMap<QString, QPair<QContactDetail::DetailType, int> > definitionDetails;
3085 definitionDetails.insert(akey: "String", avalue: qMakePair(x: QContactGuid::Type, y: static_cast<int>(QContactGuid::FieldGuid)));
3086 definitionDetails.insert(akey: "Integer", avalue: qMakePair(x: QContactPresence::Type, y: static_cast<int>(QContactPresence::FieldPresenceState)));
3087 definitionDetails.insert(akey: "DateTime", avalue: qMakePair(x: QContactAnniversary::Type, y: static_cast<int>(QContactAnniversary::FieldOriginalDate)));
3088 definitionDetails.insert(akey: "Date", avalue: qMakePair(x: QContactBirthday::Type, y: static_cast<int>(QContactBirthday::FieldBirthday)));
3089 definitionDetails.insert(akey: "Bool", avalue: qMakePair(x: QContactFavorite::Type, y: static_cast<int>(QContactFavorite::FieldFavorite)));
3090 definitionDetails.insert(akey: "Double", avalue: qMakePair(x: QContactDetail::TypeGeoLocation, y: static_cast<int>(QContactGeoLocation::FieldLatitude)));
3091 // Currently unused:
3092 definitionDetails.insert(akey: "LongLong", avalue: qMakePair(x: QContactDetail::TypeUndefined, y: -1));
3093 definitionDetails.insert(akey: "ULongLong", avalue: qMakePair(x: QContactDetail::TypeUndefined, y: -1));
3094 definitionDetails.insert(akey: "Time", avalue: qMakePair(x: QContactDetail::TypeUndefined, y: -1));
3095 definitionDetails.insert(akey: "UInt", avalue: qMakePair(x: QContactDetail::TypeUndefined, y: -1));
3096 definitionDetails.insert(akey: "Char", avalue: qMakePair(x: QContactDetail::TypeUndefined, y: -1));
3097
3098 defAndFieldNamesForTypePerManager.insert(akey: cm, avalue: definitionDetails);
3099
3100 /* Add some contacts */
3101 QContact contactA, contactB, contactC, contactD;
3102 QContactName name;
3103 QContactPhoneNumber number;
3104
3105 // Create details for each relevant value type
3106 QContactDetail stringDetail(definitionDetails.value(akey: "String").first);
3107 QContactDetail integerDetail(definitionDetails.value(akey: "Integer").first);
3108 QContactDetail datetimeDetail(definitionDetails.value(akey: "DateTime").first);
3109 QContactDetail doubleDetail(definitionDetails.value(akey: "Double").first);
3110 QContactDetail boolDetail(definitionDetails.value(akey: "Bool").first);
3111 QContactDetail longlongDetail(definitionDetails.value(akey: "LongLong").first);
3112 QContactDetail ulonglongDetail(definitionDetails.value(akey: "ULongLong").first);
3113 QContactDetail dateDetail(definitionDetails.value(akey: "Date").first);
3114 QContactDetail timeDetail(definitionDetails.value(akey: "Time").first);
3115 QContactDetail uintDetail(definitionDetails.value(akey: "UInt").first);
3116 QContactDetail charDetail(definitionDetails.value(akey: "Char").first);
3117
3118 name.setFirstName("Aaron");
3119 name.setLastName("Aaronson");
3120 name.setMiddleName("Arne");
3121 name.setPrefix("Sir");
3122 name.setSuffix("Dr.");
3123 QContactNickname nick;
3124 nick.setNickname("Sir Aaron");
3125 QContactEmailAddress emailAddr;
3126 emailAddr.setEmailAddress("Aaron@Aaronson.com");
3127 number.setNumber("5551212");
3128 stringDetail.setValue(field: definitionDetails.value(akey: "String").second, value: "Aaron Aaronson");
3129 integerDetail.setValue(field: definitionDetails.value(akey: "Integer").second, value: 10);
3130 datetimeDetail.setValue(field: definitionDetails.value(akey: "DateTime").second, value: QDateTime(QDate(2009, 06, 29), QTime(16, 52, 23, 0)));
3131 boolDetail.setValue(field: definitionDetails.value(akey: "Bool").second, value: true);
3132 ulonglongDetail.setValue(field: definitionDetails.value(akey: "ULongLong").second, value: (qulonglong)120000000000LL); // 120B
3133 dateDetail.setValue(field: definitionDetails.value(akey: "Date").second, value: QDate(1988, 1, 26));
3134 timeDetail.setValue(field: definitionDetails.value(akey: "Time").second, value: QTime(16,52,23,0));
3135
3136 contactA.saveDetail(detail: &name);
3137 contactA.saveDetail(detail: &nick);
3138 contactA.saveDetail(detail: &emailAddr);
3139 contactA.saveDetail(detail: &number);
3140 if (validDetailField(pair: definitionDetails.value(akey: "String")))
3141 contactA.saveDetail(detail: &stringDetail);
3142 if (validDetailField(pair: definitionDetails.value(akey: "Integer")))
3143 contactA.saveDetail(detail: &integerDetail);
3144 if (validDetailField(pair: definitionDetails.value(akey: "DateTime")))
3145 contactA.saveDetail(detail: &datetimeDetail);
3146 if (validDetailField(pair: definitionDetails.value(akey: "Bool")))
3147 contactA.saveDetail(detail: &boolDetail);
3148 if (validDetailField(pair: definitionDetails.value(akey: "ULongLong")))
3149 contactA.saveDetail(detail: &ulonglongDetail);
3150 if (validDetailField(pair: definitionDetails.value(akey: "Date")))
3151 contactA.saveDetail(detail: &dateDetail);
3152 if (validDetailField(pair: definitionDetails.value(akey: "Time")))
3153 contactA.saveDetail(detail: &timeDetail);
3154
3155 name = QContactName();
3156 name.setFirstName("Bob");
3157 name.setLastName("Aaronsen");
3158 nick.setNickname("Sir Bob");
3159 number.setNumber("5553456");
3160 stringDetail.setValue(field: definitionDetails.value(akey: "String").second, value: "Bob Aaronsen");
3161 integerDetail.setValue(field: definitionDetails.value(akey: "Integer").second, value: 20);
3162 doubleDetail.setValue(field: definitionDetails.value(akey: "Double").second, value: 4.0);
3163 boolDetail.setValue(field: definitionDetails.value(akey: "Bool").second, value: false);
3164 ulonglongDetail.setValue(field: definitionDetails.value(akey: "ULongLong").second, value: (qulonglong) 80000000000LL); // 80B
3165 uintDetail.setValue(field: definitionDetails.value(akey: "UInt").second, value: 4000000000u); // 4B
3166 dateDetail.setValue(field: definitionDetails.value(akey: "Date").second, value: QDate(2492, 5, 5));
3167 timeDetail.setValue(field: definitionDetails.value(akey: "Time").second, value: QTime(15,52,23,0));
3168 charDetail.setValue(field: definitionDetails.value(akey: "Char").second, value: QVariant(QChar('b')));
3169
3170 contactB.saveDetail(detail: &name);
3171 contactB.saveDetail(detail: &nick);
3172 contactB.saveDetail(detail: &number);
3173 if (validDetailField(pair: definitionDetails.value(akey: "String")))
3174 contactB.saveDetail(detail: &stringDetail);
3175 if (validDetailField(pair: definitionDetails.value(akey: "Integer")))
3176 contactB.saveDetail(detail: &integerDetail);
3177 if (validDetailField(pair: definitionDetails.value(akey: "Double")))
3178 contactB.saveDetail(detail: &doubleDetail);
3179 if (validDetailField(pair: definitionDetails.value(akey: "Bool")))
3180 contactB.saveDetail(detail: &boolDetail);
3181 if (validDetailField(pair: definitionDetails.value(akey: "ULongLong")))
3182 contactB.saveDetail(detail: &ulonglongDetail);
3183 if (validDetailField(pair: definitionDetails.value(akey: "UInt")))
3184 contactB.saveDetail(detail: &uintDetail);
3185 if (validDetailField(pair: definitionDetails.value(akey: "Date")))
3186 contactB.saveDetail(detail: &dateDetail);
3187 if (validDetailField(pair: definitionDetails.value(akey: "Time")))
3188 contactB.saveDetail(detail: &timeDetail);
3189 if (validDetailField(pair: definitionDetails.value(akey: "Char")))
3190 contactB.saveDetail(detail: &charDetail);
3191
3192 name.setFirstName("Boris");
3193 name.setLastName("Aaronsun");
3194 stringDetail.setValue(field: definitionDetails.value(akey: "String").second, value: "Boris Aaronsun");
3195 integerDetail.setValue(field: definitionDetails.value(akey: "Integer").second, value: -20);
3196 datetimeDetail.setValue(field: definitionDetails.value(akey: "DateTime").second, value: QDateTime(QDate(2009, 06, 29), QTime(16, 54, 17, 0)));
3197 longlongDetail.setValue(field: definitionDetails.value(akey: "LongLong").second, value: (qlonglong)8000000000LL); // 8B
3198 charDetail.setValue(field: definitionDetails.value(akey: "Char").second, value: QVariant(QChar('c')));
3199
3200 contactC.saveDetail(detail: &name);
3201 if (validDetailField(pair: definitionDetails.value(akey: "String")))
3202 contactC.saveDetail(detail: &stringDetail);
3203 if (validDetailField(pair: definitionDetails.value(akey: "Integer")))
3204 contactC.saveDetail(detail: &integerDetail);
3205 if (validDetailField(pair: definitionDetails.value(akey: "DateTime")))
3206 contactC.saveDetail(detail: &datetimeDetail);
3207 if (validDetailField(pair: definitionDetails.value(akey: "Double")))
3208 contactC.saveDetail(detail: &doubleDetail);
3209 if (validDetailField(pair: definitionDetails.value(akey: "Bool")))
3210 contactC.saveDetail(detail: &boolDetail);
3211 if (validDetailField(pair: definitionDetails.value(akey: "LongLong")))
3212 contactC.saveDetail(detail: &longlongDetail);
3213 if (validDetailField(pair: definitionDetails.value(akey: "ULongLong")))
3214 contactC.saveDetail(detail: &ulonglongDetail);
3215 if (validDetailField(pair: definitionDetails.value(akey: "Char")))
3216 contactC.saveDetail(detail: &charDetail);
3217
3218 name.setFirstName("Dennis");
3219 name.setLastName("FitzMacintyre");
3220 stringDetail.setValue(field: definitionDetails.value(akey: "String").second, value: "Dennis FitzMacintyre");
3221 doubleDetail.setValue(field: definitionDetails.value(akey: "Double").second, value: -128.0);
3222 longlongDetail.setValue(field: definitionDetails.value(akey: "LongLong").second, value: (qlonglong)-14000000000LL);
3223 uintDetail.setValue(field: definitionDetails.value(akey: "UInt").second, value: 3000000000u); // 3B
3224 dateDetail.setValue(field: definitionDetails.value(akey: "Date").second, value: QDate(2770, 10, 1));
3225
3226 contactD.saveDetail(detail: &name);
3227 if (validDetailField(pair: definitionDetails.value(akey: "String")))
3228 contactD.saveDetail(detail: &stringDetail);
3229 if (validDetailField(pair: definitionDetails.value(akey: "Double")))
3230 contactD.saveDetail(detail: &doubleDetail);
3231 if (validDetailField(pair: definitionDetails.value(akey: "LongLong")))
3232 contactD.saveDetail(detail: &longlongDetail);
3233 if (validDetailField(pair: definitionDetails.value(akey: "UInt")))
3234 contactD.saveDetail(detail: &uintDetail);
3235 if (validDetailField(pair: definitionDetails.value(akey: "Date")))
3236 contactD.saveDetail(detail: &dateDetail);
3237
3238 qDebug() << "Generating contacts with different timestamps, please wait..";
3239 int originalContactCount = cm->contactIds().count();
3240 bool successfulSave = cm->saveContact(contact: &contactA);
3241 Q_FATAL_VERIFY(successfulSave);
3242 QTest::qSleep(ms: napTime);
3243 successfulSave = cm->saveContact(contact: &contactB);
3244 Q_FATAL_VERIFY(successfulSave);
3245 QTest::qSleep(ms: napTime);
3246 successfulSave = cm->saveContact(contact: &contactC);
3247 Q_FATAL_VERIFY(successfulSave);
3248 QTest::qSleep(ms: napTime);
3249 successfulSave = cm->saveContact(contact: &contactD);
3250 Q_FATAL_VERIFY(successfulSave);
3251 QTest::qSleep(ms: napTime);
3252
3253 /* Now add some contacts specifically for multisorting */
3254 QContact contactE,contactF,contactG;
3255 QContactName n;
3256 n.setFirstName("John");
3257 n.setLastName("Smithee");
3258 stringDetail.setValue(field: definitionDetails.value(akey: "String").second, value: "");
3259 if (validDetailField(pair: definitionDetails.value(akey: "String")))
3260 contactE.saveDetail(detail: &stringDetail);
3261 contactE.saveDetail(detail: &n);
3262 n = QContactName();
3263 n.setFirstName("John");
3264 n.setLastName("Smithey");
3265 contactF.saveDetail(detail: &n);
3266 n = QContactName();
3267 n.setFirstName("John");
3268 n.setLastName("Smithy");
3269 stringDetail.setValue(field: definitionDetails.value(akey: "String").second, value: "zzz");
3270 if (validDetailField(pair: definitionDetails.value(akey: "String")))
3271 contactG.saveDetail(detail: &stringDetail);
3272 contactG.saveDetail(detail: &n);
3273 successfulSave = cm->saveContact(contact: &contactE);
3274 Q_FATAL_VERIFY(successfulSave);
3275 successfulSave = cm->saveContact(contact: &contactF);
3276 Q_FATAL_VERIFY(successfulSave);
3277 successfulSave = cm->saveContact(contact: &contactG);
3278 Q_FATAL_VERIFY(successfulSave);
3279 originalContactCount += 7;
3280 Q_FATAL_VERIFY(cm->contactIds().count() == originalContactCount);
3281
3282 /* Now some for the locale aware sorting */
3283 /* In the C locale, all lowercase chars sort after uppercase */
3284 QContact contactH, contactI, contactJ, contactK;
3285 QContactName n2;
3286 n2.setFirstName("xander");
3287 contactH.saveDetail(detail: &n2);
3288 n2.setFirstName("Xander");
3289 contactI.saveDetail(detail: &n2);
3290 n2.setFirstName("yarrow");
3291 contactJ.saveDetail(detail: &n2);
3292 n2.setFirstName("Yarrow");
3293 contactK.saveDetail(detail: &n2);
3294
3295 Q_FATAL_VERIFY(cm->saveContact(&contactH));
3296 Q_FATAL_VERIFY(cm->saveContact(&contactI));
3297 Q_FATAL_VERIFY(cm->saveContact(&contactJ));
3298 Q_FATAL_VERIFY(cm->saveContact(&contactK));
3299
3300 /* Ensure the last modified times are different */
3301 QTest::qSleep(ms: napTime);
3302 QContactName modifiedName = contactC.detail(type: QContactName::Type);
3303 contactC.saveDetail(detail: &modifiedName);
3304 cm->saveContact(contact: &contactC);
3305 QTest::qSleep(ms: napTime);
3306 modifiedName = contactB.detail(type: QContactName::Type);
3307 contactB.saveDetail(detail: &modifiedName);
3308 cm->saveContact(contact: &contactB);
3309 QTest::qSleep(ms: napTime);
3310 modifiedName = contactA.detail(type: QContactName::Type);
3311 contactA.saveDetail(detail: &modifiedName);
3312 cm->saveContact(contact: &contactA);
3313 QTest::qSleep(ms: napTime);
3314
3315 /* Now some for convenience filtering */
3316 QList<QContactDetail::DetailType> allTypes = cm->supportedContactDetailTypes();
3317 // Contact L ----------------------------------------
3318 QContact contactL;
3319 if (allTypes.contains(t: QContactAddress::Type)) {
3320 QContactAddress ladr;
3321 ladr.setStreet("streetstring road"); // Contact L matches streetstring.
3322 ladr.setLocality("testplace");
3323 ladr.setRegion("somewhere");
3324 contactL.saveDetail(detail: &ladr);
3325 }
3326 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3327 QContactEmailAddress led;
3328 led.setEmailAddress("frad@test.domain");
3329 contactL.saveDetail(detail: &led);
3330 }
3331 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3332 QContactPhoneNumber lp;
3333 lp.setNumber("11111");
3334 contactL.saveDetail(detail: &lp);
3335 }
3336 if (allTypes.contains(t: QContactName::Type)) {
3337 QContactName ln;
3338 ln.setFirstName("Fradarick");
3339 ln.setLastName("Gumboots");
3340 contactL.saveDetail(detail: &ln);
3341 }
3342 if (allTypes.contains(t: QContactTag::Type)) {
3343 QContactTag lt;
3344 lt.setTag("Soccer");
3345 contactL.saveDetail(detail: &lt);
3346 }
3347 // Contact M ----------------------------------------
3348 QContact contactM;
3349 if (allTypes.contains(t: QContactAddress::Type)) {
3350 QContactAddress madr;
3351 madr.setStreet("some road");
3352 madr.setLocality("testplace");
3353 madr.setRegion("somewhere");
3354 contactM.saveDetail(detail: &madr);
3355 }
3356 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3357 QContactEmailAddress med;
3358 med.setEmailAddress("frbd@test.com"); // Contact M matches @test.com
3359 contactM.saveDetail(detail: &med);
3360 }
3361 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3362 QContactPhoneNumber mp;
3363 mp.setNumber("22222");
3364 contactM.saveDetail(detail: &mp);
3365 }
3366 if (allTypes.contains(t: QContactName::Type)) {
3367 QContactName mn;
3368 mn.setFirstName("Frbdbrick");
3369 mn.setLastName("Gumboots");
3370 contactM.saveDetail(detail: &mn);
3371 }
3372 if (allTypes.contains(t: QContactTag::Type)) {
3373 QContactTag mt;
3374 mt.setTag("Soccer");
3375 contactM.saveDetail(detail: &mt);
3376 }
3377 // Contact N ----------------------------------------
3378 QContact contactN;
3379 if (allTypes.contains(t: QContactAddress::Type)) {
3380 QContactAddress nadr;
3381 nadr.setStreet("some road");
3382 nadr.setLocality("testplace");
3383 nadr.setRegion("somewhere");
3384 contactN.saveDetail(detail: &nadr);
3385 }
3386 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3387 QContactEmailAddress ned;
3388 ned.setEmailAddress("frcd@test.domain");
3389 contactN.saveDetail(detail: &ned);
3390 }
3391 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3392 QContactPhoneNumber np;
3393 np.setNumber("12345"); // Contact N matches 12345
3394 contactN.saveDetail(detail: &np);
3395 }
3396 if (allTypes.contains(t: QContactName::Type)) {
3397 QContactName nn;
3398 nn.setFirstName("Frcdcrick");
3399 nn.setLastName("Gumboots");
3400 contactN.saveDetail(detail: &nn);
3401 }
3402 if (allTypes.contains(t: QContactTag::Type)) {
3403 QContactTag nt;
3404 nt.setTag("Soccer");
3405 contactN.saveDetail(detail: &nt);
3406 }
3407 // Contact O ----------------------------------------
3408 QContact contactO;
3409 if (allTypes.contains(t: QContactAddress::Type)) {
3410 QContactAddress oadr;
3411 oadr.setStreet("some road");
3412 oadr.setLocality("testplace");
3413 oadr.setRegion("somewhere");
3414 contactO.saveDetail(detail: &oadr);
3415 }
3416 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3417 QContactEmailAddress oed;
3418 oed.setEmailAddress("frdd@test.domain");
3419 contactO.saveDetail(detail: &oed);
3420 }
3421 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3422 QContactPhoneNumber op;
3423 op.setNumber("44444");
3424 contactO.saveDetail(detail: &op);
3425 }
3426 if (allTypes.contains(t: QContactName::Type)) {
3427 QContactName on;
3428 on.setFirstName("Freddy"); // Contact O matches Freddy
3429 on.setLastName("Gumboots");
3430 contactO.saveDetail(detail: &on);
3431 }
3432 if (allTypes.contains(t: QContactTag::Type)) {
3433 QContactTag ot;
3434 ot.setTag("Soccer");
3435 contactO.saveDetail(detail: &ot);
3436 }
3437 // Contact P ----------------------------------------
3438 QContact contactP;
3439 if (allTypes.contains(t: QContactAddress::Type)) {
3440 QContactAddress padr;
3441 padr.setStreet("some road");
3442 padr.setLocality("testplace");
3443 padr.setRegion("somewhere");
3444 contactP.saveDetail(detail: &padr);
3445 }
3446 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3447 QContactEmailAddress ped;
3448 ped.setEmailAddress("fred@test.domain");
3449 contactP.saveDetail(detail: &ped);
3450 }
3451 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3452 QContactPhoneNumber pp;
3453 pp.setNumber("55555");
3454 contactP.saveDetail(detail: &pp);
3455 }
3456 if (allTypes.contains(t: QContactName::Type)) {
3457 QContactName pn;
3458 pn.setFirstName("Frederick"); // Contact P matches Frederic (contains).
3459 pn.setLastName("Gumboots");
3460 contactP.saveDetail(detail: &pn);
3461 }
3462 if (allTypes.contains(t: QContactTag::Type)) {
3463 QContactTag pt;
3464 pt.setTag("Soccer");
3465 contactP.saveDetail(detail: &pt);
3466 }
3467 // Contact Q ----------------------------------------
3468 QContact contactQ;
3469 if (allTypes.contains(t: QContactAddress::Type)) {
3470 QContactAddress qadr;
3471 qadr.setStreet("some road");
3472 qadr.setLocality("testplace");
3473 qadr.setRegion("somewhere");
3474 contactQ.saveDetail(detail: &qadr);
3475 }
3476 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3477 QContactEmailAddress qed;
3478 qed.setEmailAddress("frfd@test.domain");
3479 contactQ.saveDetail(detail: &qed);
3480 }
3481 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3482 QContactPhoneNumber qp;
3483 qp.setNumber("66666");
3484 contactQ.saveDetail(detail: &qp);
3485 }
3486 if (allTypes.contains(t: QContactName::Type)) {
3487 QContactName qn;
3488 qn.setFirstName("Frfdfrick");
3489 qn.setLastName("Gumboots");
3490 contactQ.saveDetail(detail: &qn);
3491 }
3492 if (allTypes.contains(t: QContactTag::Type)) {
3493 QContactTag qt;
3494 qt.setTag("Soccer");
3495 contactQ.saveDetail(detail: &qt);
3496 }
3497 if (allTypes.contains(t: QContactFavorite::Type)) {
3498 QContactFavorite qf;
3499 qf.setFavorite(true); // Contact Q matches favorite = true
3500 contactQ.saveDetail(detail: &qf);
3501 }
3502 // Contact R ----------------------------------------
3503 QContact contactR;
3504 if (allTypes.contains(t: QContactAddress::Type)) {
3505 QContactAddress radr;
3506 radr.setStreet("some road");
3507 radr.setLocality("testplace");
3508 radr.setRegion("somewhere");
3509 contactR.saveDetail(detail: &radr);
3510 }
3511 if (allTypes.contains(t: QContactEmailAddress::Type)) {
3512 QContactEmailAddress red;
3513 red.setEmailAddress("frgd@test.domain");
3514 contactR.saveDetail(detail: &red);
3515 }
3516 if (allTypes.contains(t: QContactPhoneNumber::Type)) {
3517 QContactPhoneNumber rp;
3518 rp.setNumber("77777");
3519 contactR.saveDetail(detail: &rp);
3520 }
3521 if (allTypes.contains(t: QContactName::Type)) {
3522 QContactName rn;
3523 rn.setFirstName("Frgdgrick");
3524 rn.setLastName("Gumboots");
3525 contactR.saveDetail(detail: &rn);
3526 }
3527 if (allTypes.contains(t: QContactTag::Type)) {
3528 QContactTag rt;
3529 rt.setTag("Football"); // Contact R matches Football
3530 contactR.saveDetail(detail: &rt);
3531 }
3532 // --------------------- save.
3533 Q_FATAL_VERIFY(cm->saveContact(&contactL));
3534 Q_FATAL_VERIFY(cm->saveContact(&contactM));
3535 Q_FATAL_VERIFY(cm->saveContact(&contactN));
3536 Q_FATAL_VERIFY(cm->saveContact(&contactO));
3537 Q_FATAL_VERIFY(cm->saveContact(&contactP));
3538 Q_FATAL_VERIFY(cm->saveContact(&contactQ));
3539 Q_FATAL_VERIFY(cm->saveContact(&contactR));
3540 // --------------------- end.
3541
3542 /* Reload the contacts to pick up any changes */
3543 contactA = cm->contact(contactId: contactA.id());
3544 contactB = cm->contact(contactId: contactB.id());
3545 contactC = cm->contact(contactId: contactC.id());
3546 contactD = cm->contact(contactId: contactD.id());
3547 contactE = cm->contact(contactId: contactE.id());
3548 contactF = cm->contact(contactId: contactF.id());
3549 contactG = cm->contact(contactId: contactG.id());
3550 contactH = cm->contact(contactId: contactH.id());
3551 contactI = cm->contact(contactId: contactI.id());
3552 contactJ = cm->contact(contactId: contactJ.id());
3553 contactK = cm->contact(contactId: contactK.id());
3554 contactL = cm->contact(contactId: contactL.id());
3555 contactM = cm->contact(contactId: contactM.id());
3556 contactN = cm->contact(contactId: contactN.id());
3557 contactO = cm->contact(contactId: contactO.id());
3558 contactP = cm->contact(contactId: contactP.id());
3559 contactQ = cm->contact(contactId: contactQ.id());
3560 contactR = cm->contact(contactId: contactR.id());
3561
3562 QList<QContactId> list;
3563
3564 /* Add our newly saved contacts to our internal list of added contacts */
3565 foreach (const QContactId &id, (QList<QContactId>() << contactR.id()
3566 << contactQ.id()
3567 << contactP.id()
3568 << contactO.id()
3569 << contactN.id()
3570 << contactM.id()
3571 << contactL.id()
3572 << contactK.id()
3573 << contactJ.id()
3574 << contactI.id()
3575 << contactH.id()
3576 << contactG.id()
3577 << contactF.id()
3578 << contactE.id()
3579 << contactD.id()
3580 << contactC.id()
3581 << contactB.id()
3582 << contactA.id())) {
3583 if (!id.isNull()) {
3584 contactsAddedToManagers.insert(akey: cm, avalue: id);
3585 list.prepend(t: id);
3586 }
3587 }
3588
3589 return list;
3590}
3591
3592/* ============ Utility functions ============= */
3593
3594void tst_QContactManagerFiltering::dumpContactDifferences(const QContact& ca, const QContact& cb)
3595{
3596 // Try to narrow down the differences
3597 QContact a(ca);
3598 QContact b(cb);
3599
3600 QContactName n1 = a.detail(type: QContactName::Type);
3601 QContactName n2 = b.detail(type: QContactName::Type);
3602
3603 // Check the name components in more detail
3604 QCOMPARE(n1.firstName(), n2.firstName());
3605 QCOMPARE(n1.middleName(), n2.middleName());
3606 QCOMPARE(n1.lastName(), n2.lastName());
3607 QCOMPARE(n1.prefix(), n2.prefix());
3608 QCOMPARE(n1.suffix(), n2.suffix());
3609
3610 // Check the display label
3611 QCOMPARE(a.detail<QContactDisplayLabel>().label(), b.detail<QContactDisplayLabel>().label());
3612
3613 // Now look at the rest
3614 QList<QContactDetail> aDetails = a.details();
3615 QList<QContactDetail> bDetails = b.details();
3616
3617 // They can be in any order, so loop
3618 // First remove any matches
3619 foreach(QContactDetail d, aDetails) {
3620 foreach(QContactDetail d2, bDetails) {
3621 if(d == d2) {
3622 a.removeDetail(detail: &d);
3623 b.removeDetail(detail: &d2);
3624 break;
3625 }
3626 }
3627 }
3628
3629 // Now dump the extra details that were unmatched in A
3630 aDetails = a.details();
3631 bDetails = b.details();
3632 foreach(QContactDetail d, aDetails) {
3633 if (d.type() != QContactDisplayLabel::Type)
3634 qDebug() << "A contact had extra detail:" << d.type() << d.values();
3635 }
3636 // and same for B
3637 foreach(QContactDetail d, bDetails) {
3638 if (d.type() != QContactDisplayLabel::Type)
3639 qDebug() << "B contact had extra detail:" << d.type() << d.values();
3640 }
3641
3642 QCOMPARE(b, a);
3643}
3644
3645bool tst_QContactManagerFiltering::isSuperset(const QContact& ca, const QContact& cb)
3646{
3647 // returns true if contact ca is a superset of contact cb
3648 // we use this test instead of equality because dynamic information
3649 // such as presence/location, and synthesised information such as
3650 // display label and (possibly) type, may differ between a contact
3651 // in memory and the contact in the managed store.
3652
3653 QContact a(ca);
3654 QContact b(cb);
3655 QList<QContactDetail> aDetails = a.details();
3656 QList<QContactDetail> bDetails = b.details();
3657
3658 // They can be in any order, so loop
3659 // First remove any matches
3660 foreach(QContactDetail d, aDetails) {
3661 foreach(QContactDetail d2, bDetails) {
3662 if(d == d2) {
3663 a.removeDetail(detail: &d);
3664 b.removeDetail(detail: &d2);
3665 break;
3666 }
3667 }
3668 }
3669
3670 // check for contact type updates
3671 if (a.type() != b.type())
3672 return false; // nonempty type is different.
3673
3674 // Now check to see if b has any details remaining; if so, a is not a superset.
3675 // Note that the DisplayLabel and Type can never be removed.
3676 if (b.details().size() > 2
3677 || (b.details().size() == 2 && (b.details().value(i: 0).type() != QContactDisplayLabel::Type
3678 || b.details().value(i: 1).type() != QContactType::Type)))
3679 return false;
3680 return true;
3681}
3682
3683void tst_QContactManagerFiltering::dumpContact(const QContact& contact)
3684{
3685 QContactManager m;
3686 qDebug() << "Contact: " << contact.id() << "(" << contact.detail<QContactDisplayLabel>().label() << ")";
3687 QList<QContactDetail> details = contact.details();
3688 foreach(QContactDetail d, details) {
3689 qDebug() << " " << d.type() << ":";
3690 qDebug() << " Vals:" << d.values();
3691 }
3692}
3693
3694void tst_QContactManagerFiltering::dumpContacts()
3695{
3696 QContactManager m;
3697 QList<QContactId> ids = m.contactIds();
3698
3699 foreach(QContactId id, ids) {
3700 QContact c = m.contact(contactId: id);
3701 dumpContact(contact: c);
3702 }
3703}
3704
3705QTEST_MAIN(tst_QContactManagerFiltering)
3706#include "tst_qcontactmanagerfiltering.moc"
3707#include "qcontactmanager.h"
3708

source code of qtpim/tests/auto/contacts/qcontactmanagerfiltering/unittest/tst_qcontactmanagerfiltering.cpp