Correct expected results when using ICU
[qt:qtpim.git] / tests / auto / contacts / qcontactmanagerfiltering / unittest / tst_qcontactmanagerfiltering.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #define QT_STATICPLUGIN
43 #include <QtTest/QtTest>
44
45 #ifdef INCLUDE_TESTACTIONS
46 #include <QServiceManager>
47 #endif
48 #include <QtContacts>
49 #include "qcontactmanagerdataholder.h" //QContactManagerDataHolder
50
51 #include <QLocale>
52 #ifdef Q_OS_UNIX
53 #include <locale.h>
54 #endif
55
56 //TESTED_COMPONENT=src/contacts
57
58 // Q_ASSERT replacement, since we often run in release builds
59 #define Q_FATAL_VERIFY(statement)                                         \
60 do {                                                                      \
61     if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \
62         qFatal("severe failure encountered, test cannot continue");       \
63 } while (0)
64
65 QTCONTACTS_USE_NAMESPACE
66 /*
67  * This test is mostly just for testing sorting and filtering -
68  * having it in tst_QContactManager makes maintenance more
69  * difficult!
70  */
71
72 Q_DECLARE_METATYPE(QVariant)
73 Q_DECLARE_METATYPE(QContactManager*)
74 Q_DECLARE_METATYPE(QContactDetail::DetailType)
75
76 /*
77  * Global variables:
78  * These are the definition and field names used by the actions for their matching.
79  */
80 QMap<QString, QPair<QContactDetail::DetailType, int> > defAndFieldNamesForTypeForActions;
81
82 namespace {
83
84 bool validDetailType(const QPair<QContactDetail::DetailType, int> &pair)
85 {
86     return pair.first != QContactDetail::TypeUndefined;
87 }
88
89 bool validDetailField(const QPair<QContactDetail::DetailType, int> &pair)
90 {
91     return pair.first != QContactDetail::TypeUndefined && pair.second != -1;
92 }
93
94 }
95
96 /*
97  * We use this code to compare the output and expected lists of filtering
98  * where no sort order is implied.
99  * TODO: use this instead of QCOMPARE in the various filtering tests!
100  */
101 #define QCOMPARE_UNSORTED(output, expected) if (output.size() != expected.size()) { \
102                                                 QCOMPARE(output, expected); \
103                                             } else { \
104                                                 for (int i = 0; i < output.size(); i++) { \
105                                                     if (!expected.contains(output.at(i))) { \
106                                                         QCOMPARE(output, expected); \
107                                                     } \
108                                                 } \
109                                             }
110
111 class tst_QContactManagerFiltering : public QObject
112 {
113 Q_OBJECT
114
115 public:
116     tst_QContactManagerFiltering();
117     virtual ~tst_QContactManagerFiltering();
118
119 private:
120     void dumpContactDifferences(const QContact& a, const QContact& b);
121     void dumpContact(const QContact &c);
122     void dumpContacts();
123     bool isSuperset(const QContact& ca, const QContact& cb);
124
125     QList<QContactId> prepareModel(QContactManager* cm); // add the standard contacts
126
127     QString convertIds(QList<QContactId> allIds, QList<QContactId> ids, QChar minimumContact = 'a', QChar maximumContact = 'z'); // convert back to "abcd"
128     QContact createContact(QContactManager* cm, QContactType::TypeValues type, const QString &name);
129
130     QMap<QContactManager*, QMap<QString, QPair<QContactDetail::DetailType, int> > > defAndFieldNamesForTypePerManager;
131     QMultiMap<QContactManager*, QContactId> contactsAddedToManagers;
132     QList<QContactManager*> managers;
133     QScopedPointer<QContactManagerDataHolder> managerDataHolder;
134
135     QTestData& newMRow(const char *tag, QContactManager *cm);
136
137 private slots:
138
139     void initTestCase();
140     void cleanupTestCase();
141
142     void rangeFiltering(); // XXX should take all managers
143     void rangeFiltering_data();
144
145     void detailStringFiltering(); // XXX should take all managers
146     void detailStringFiltering_data();
147
148     void detailPhoneNumberFiltering();
149     void detailPhoneNumberFiltering_data();
150
151 #ifdef INCLUDE_TESTACTIONS
152     void actionPlugins();
153     void actionFiltering();
154     void actionFiltering_data();
155 #endif
156
157     void detailVariantFiltering();
158     void detailVariantFiltering_data();
159
160     void intersectionFiltering();
161     void intersectionFiltering_data();
162
163     void unionFiltering();
164     void unionFiltering_data();
165
166     void relationshipFiltering();
167     void relationshipFiltering_data();
168
169     void changelogFiltering();
170     void changelogFiltering_data();
171
172     void idListFiltering();
173     void idListFiltering_data();
174
175     void convenienceFiltering();
176     void convenienceFiltering_data();
177
178     void sorting(); // XXX should take all managers
179     void sorting_data();
180
181     void multiSorting();
182     void multiSorting_data();
183
184     void invalidFiltering_data();
185     void invalidFiltering();
186
187     void allFiltering_data();
188     void allFiltering();
189
190     void fetchHint_data();
191     void fetchHint();
192 };
193
194 tst_QContactManagerFiltering::tst_QContactManagerFiltering()
195 {
196     // In order to make our tests reliable, set the C locale
197     QLocale::setDefault(QLocale::c());
198
199 #if defined(Q_OS_UNIX) && !defined(QT_USE_ICU)
200     // Without ICU, we also need to set the locale on unix
201     ::setlocale(LC_ALL, "C");
202 #endif
203 }
204
205 tst_QContactManagerFiltering::~tst_QContactManagerFiltering()
206 {
207 }
208
209 void tst_QContactManagerFiltering::initTestCase()
210 {
211     managerDataHolder.reset(new QContactManagerDataHolder());
212
213     // firstly, build a list of the managers we wish to test.
214     QStringList managerNames = QContactManager::availableManagers();
215
216     /* Known one that will not pass */
217     managerNames.removeAll("invalid");
218     managerNames.removeAll("testdummy");
219     managerNames.removeAll("teststaticdummy");
220     managerNames.removeAll("maliciousplugin");
221     // Symbiansim backend does not support the required details for these
222     // tests to pass. Symbiansim backend specific unit test tst_simcm is
223     // testing filtering instead.
224     managerNames.removeAll("symbiansim");
225
226     // Some internal engines on Maemo6
227     managerNames.removeAll("social");
228     managerNames.removeAll("simcard");
229     managerNames.removeAll("com.nokia.messaging.contacts.engines.mail.contactslookup");
230
231     foreach(QString mgr, managerNames) {
232         QMap<QString, QString> params;
233         QString mgrUri = QContactManager::buildUri(mgr, params);
234         QContactManager* cm = QContactManager::fromUri(mgrUri);
235         cm->setObjectName(mgr);
236         managers.append(cm);
237
238         if (mgr == "memory") {
239             params.insert("id", "tst_QContactManager");
240             mgrUri = QContactManager::buildUri(mgr, params);
241             cm = QContactManager::fromUri(mgrUri);
242             cm->setObjectName("memory[params]");
243             managers.append(cm);
244         }
245     }
246
247     // for each manager that we wish to test, prepare the model.
248     foreach (QContactManager* cm, managers) {
249         QList<QContactId> addedContacts = prepareModel(cm);
250         if (addedContacts != contactsAddedToManagers.values(cm)) {
251             qDebug() << "prepareModel returned:" << addedContacts;
252             qDebug() << "contactsAdded are:    " << contactsAddedToManagers.values(cm);
253             qFatal("returned list different from saved contacts list!");
254         }
255     }
256
257 #ifdef INCLUDE_TESTACTIONS
258     qDebug() << "Finished preparing each manager for test!  About to load test actions:";
259     QServiceManager sm;
260     QStringList allServices = sm.findServices();
261     foreach(const QString& serv, allServices) {
262         if (serv.startsWith("tst_qcontactmanagerfiltering:")) {
263             if (!sm.removeService(serv)) {
264                 qDebug() << " tst_qca: ctor: cleaning up test service" << serv << "failed:" << sm.error();
265             }
266         }
267     }
268     QStringList myServices;
269     myServices << "BooleanAction" << "DateAction" << "IntegerAction" << "NumberAction" << "PhoneNumberAction";
270     foreach (const QString& serv, myServices) {
271         QString builtPath = QCoreApplication::applicationDirPath() + "/plugins/contacts/xmldata/" + serv.toLower() + "service.xml";
272         if (!sm.addService(builtPath)) {
273             qDebug() << " tst_qca: ctor: unable to add" << serv << "service:" << sm.error();
274         }
275     }
276 #endif
277     qDebug() << "Done!";
278 }
279
280 void tst_QContactManagerFiltering::cleanupTestCase()
281 {
282     // first, remove any contacts that we've added to any managers.
283     foreach (QContactManager* manager, managers) {
284         QList<QContactId> contactIds = contactsAddedToManagers.values(manager);
285         manager->removeContacts(contactIds, 0);
286     }
287     contactsAddedToManagers.clear();
288
289     // finally, we can delete all of our manager instances
290     qDeleteAll(managers);
291     managers.clear();
292     defAndFieldNamesForTypePerManager.clear();
293
294     // And restore old contacts
295     managerDataHolder.reset(0);
296
297 #ifdef INCLUDE_TESTACTIONS
298     // clean up any actions/services.
299     QServiceManager sm;
300     QStringList allServices = sm.findServices();
301     foreach(const QString& serv, allServices) {
302         if (serv.startsWith("tst_qcontactmanagerfiltering:")) {
303             if (!sm.removeService(serv)) {
304                 qDebug() << " tst_qca: ctor: cleaning up test service" << serv << "failed:" << sm.error();
305             }
306         }
307     }
308 #endif
309 }
310
311 QString tst_QContactManagerFiltering::convertIds(QList<QContactId> allIds, QList<QContactId> ids, QChar minimumContact, QChar maximumContact)
312 {
313     QString ret;
314     /* Expected is of the form "abcd".. it's possible that there are some extra contacts */
315     for (int i = 0; i < ids.size(); i++) {
316         if (allIds.indexOf(ids.at(i)) >= 0) {
317             QChar curr = ('a' + allIds.indexOf(ids.at(i)));
318             if (curr >= minimumContact && curr <= maximumContact) {
319                 ret += curr;
320             }
321         }
322     }
323
324     return ret;
325 }
326
327 QTestData& tst_QContactManagerFiltering::newMRow(const char *tag, QContactManager *cm)
328 {
329     // allocate a tag
330     QString foo = QString("%1[%2]").arg(tag).arg(cm->objectName());
331     return QTest::newRow(foo.toLatin1().constData());
332 }
333
334
335 void tst_QContactManagerFiltering::detailStringFiltering_data()
336 {
337     QTest::addColumn<QContactManager *>("cm");
338     QTest::addColumn<QContactDetail::DetailType>("detailType");
339     QTest::addColumn<int>("detailField");
340     QTest::addColumn<QVariant>("value");
341     QTest::addColumn<int>("matchflags");
342     QTest::addColumn<QString>("expected");
343
344     QVariant ev; // empty variant
345     QString es; // empty string
346
347     QContactDetail::DetailType name = QContactName::Type;
348     int firstname = QContactName::FieldFirstName;
349     int lastname = QContactName::FieldLastName;
350     int middlename = QContactName::FieldMiddleName;
351     int prefixname = QContactName::FieldPrefix;
352     int suffixname = QContactName::FieldSuffix;
353     QContactDetail::DetailType nickname = QContactNickname::Type;
354     int nicknameField = QContactNickname::FieldNickname;
355     QContactDetail::DetailType emailaddr = QContactEmailAddress::Type;
356     int emailfield = QContactEmailAddress::FieldEmailAddress;
357     QContactDetail::DetailType phonenumber = QContactPhoneNumber::Type;
358     int number = QContactPhoneNumber::FieldNumber;
359
360     for (int i = 0; i < managers.size(); i++) {
361         QContactManager *manager = managers.at(i);
362         newMRow("Name == Aaro", manager) << manager << name << firstname << QVariant("Aaro") << 0 << es;
363         newMRow("Name == Aaron", manager) << manager << name << firstname << QVariant("Aaron") << 0 << "a";
364         newMRow("Name == aaron", manager) << manager << name << firstname << QVariant("aaron") << 0 << "a";
365         newMRow("Name == Aaron, case sensitive", manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchCaseSensitive) << "a";
366         newMRow("Name == aaron, case sensitive", manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchCaseSensitive) << es;
367
368         newMRow("Name == A, begins", manager) << manager << name << firstname << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << "a";
369         newMRow("Name == Aaron, begins", manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchStartsWith) << "a";
370         newMRow("Name == aaron, begins", manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchStartsWith) << "a";
371         newMRow("Name == Aaron, begins, case sensitive", manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << "a";
372         newMRow("Name == aaron, begins, case sensitive", manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << es;
373         newMRow("Name == Aaron1, begins", manager) << manager << name << firstname << QVariant("Aaron1") << (int)(QContactFilter::MatchStartsWith) << es;
374         newMRow("Last name == A, begins", manager) << manager << name << lastname << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << "abc";
375         newMRow("Last name == Aaronson, begins", manager) << manager << name << lastname << QVariant("Aaronson") << (int)(QContactFilter::MatchStartsWith) << "a";
376         newMRow("Last Name == Aaronson1, begins", manager) << manager << name << lastname << QVariant("Aaronson1") << (int)(QContactFilter::MatchStartsWith) << es;
377
378         newMRow("Name == Aar, begins", manager) << manager << name << firstname << QVariant("Aar") << (int)(QContactFilter::MatchStartsWith) << "a";
379         newMRow("Name == aar, begins", manager) << manager << name << firstname << QVariant("aar") << (int)(QContactFilter::MatchStartsWith) << "a";
380         newMRow("Name == Aar, begins, case sensitive", manager) << manager << name << firstname << QVariant("Aar") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << "a";
381         newMRow("Name == aar, begins, case sensitive", manager) << manager << name << firstname << QVariant("aar") << (int)(QContactFilter::MatchStartsWith | QContactFilter::MatchCaseSensitive) << es;
382
383         newMRow("Name == aro, contains", manager) << manager << name << firstname << QVariant("aro") << (int)(QContactFilter::MatchContains) << "a";
384         newMRow("Name == ARO, contains", manager) << manager << name << firstname << QVariant("ARO") << (int)(QContactFilter::MatchContains) << "a";
385         newMRow("Name == aro, contains, case sensitive", manager) << manager << name << firstname << QVariant("aro") << (int)(QContactFilter::MatchContains | QContactFilter::MatchCaseSensitive) << "a";
386         newMRow("Name == ARO, contains, case sensitive", manager) << manager << name << firstname << QVariant("ARO") << (int)(QContactFilter::MatchContains | QContactFilter::MatchCaseSensitive) << es;
387
388         newMRow("Name == ron, ends", manager) << manager << name << firstname << QVariant("ron") << (int)(QContactFilter::MatchEndsWith) << "a";
389         newMRow("Name == ARON, ends", manager) << manager << name << firstname << QVariant("ARON") << (int)(QContactFilter::MatchEndsWith) << "a";
390         newMRow("Name == aron, ends, case sensitive", manager) << manager << name << firstname << QVariant("aron") << (int)(QContactFilter::MatchEndsWith | QContactFilter::MatchCaseSensitive) << "a";
391         newMRow("Name == ARON, ends, case sensitive", manager) << manager << name << firstname << QVariant("ARON") << (int)(QContactFilter::MatchEndsWith | QContactFilter::MatchCaseSensitive) << es;
392         newMRow("Last name == n, ends", manager) << manager << name << lastname << QVariant("n") << (int)(QContactFilter::MatchEndsWith) << "abc";
393
394         newMRow("Name == Aaron, fixed", manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchFixedString) << "a";
395         newMRow("Name == aaron, fixed", manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchFixedString) << "a";
396         newMRow("Name == Aaron, fixed, case sensitive", manager) << manager << name << firstname << QVariant("Aaron") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchCaseSensitive) << "a";
397         newMRow("Name == aaron, fixed, case sensitive", manager) << manager << name << firstname << QVariant("aaron") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchCaseSensitive) << es;
398
399         // middle name
400         newMRow("MName == Arne", manager) << manager << name << middlename << QVariant("Arne") << (int)(QContactFilter::MatchContains) << "a";
401
402         // prefix
403         newMRow("Prefix == Sir", manager) << manager << name << prefixname << QVariant("Sir") << (int)(QContactFilter::MatchContains) << "a";
404
405         // suffix
406         newMRow("Suffix == Dr.", manager) << manager << name << suffixname << QVariant("Dr.") << (int)(QContactFilter::MatchContains) << "a";
407
408         // nickname
409         newMRow("Nickname detail exists", manager) << manager << nickname << -1 << QVariant() << 0 << "ab";
410         newMRow("Nickname == Aaron, contains", manager) << manager << nickname << nicknameField << QVariant("Aaron") << (int)(QContactFilter::MatchContains) << "a";
411
412         // email
413         newMRow("Email == Aaron@Aaronson.com", manager) << manager << emailaddr << emailfield << QVariant("Aaron@Aaronson.com") << 0 << "a";
414         newMRow("Email == Aaron@Aaronsen.com", manager) << manager << emailaddr << emailfield << QVariant("Aaron@Aaronsen.com") << 0 << es;
415
416         // phone number
417         newMRow("Phone number detail exists", manager) << manager << phonenumber << -1 << QVariant("") << 0 << "ab";
418         newMRow("Phone number = 5551212", manager) << manager << phonenumber << number << QVariant("5551212") << (int) QContactFilter::MatchExactly << "a";
419         newMRow("Phone number = 34, contains", manager) << manager << phonenumber << number << QVariant("34") << (int) QContactFilter::MatchContains << "b";
420         newMRow("Phone number = 555, starts with", manager) << manager << phonenumber << number << QVariant("555") <<  (int) QContactFilter::MatchStartsWith << "ab";
421         newMRow("Phone number = 1212, ends with", manager) << manager << phonenumber << number << QVariant("1212") << (int) QContactFilter::MatchEndsWith << "a";
422         newMRow("Phone number = 555-1212, match phone number", manager) << manager << phonenumber << number << QVariant("555-1212") << (int) QContactFilter::MatchPhoneNumber << "a"; // hyphens will be ignored by the match algorithm
423         newMRow("Phone number = 555, keypad collation", manager) << manager << phonenumber << number << QVariant("555") << (int) (QContactFilter::MatchKeypadCollation | QContactFilter::MatchStartsWith) << "ab";
424
425         /* Converting other types to strings */
426         QPair<QContactDetail::DetailType, int> defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Integer");
427         if (validDetailField(defAndFieldNames)) {
428             QTest::newRow("integer == 20") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << 0 << es;
429             QTest::newRow("integer == 20, as string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString) << "b";
430             QTest::newRow("integer == 20, begins with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchStartsWith) << "b";
431             QTest::newRow("integer == 2, begins with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("2") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchStartsWith) << "b";
432             QTest::newRow("integer == 20, ends with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchEndsWith) << "bc";
433             QTest::newRow("integer == 0, ends with, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("0") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchEndsWith) << "abc";
434             QTest::newRow("integer == 20, contains, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("20") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchContains) << "bc";
435             QTest::newRow("integer == 0, contains, string") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant("0") << (int)(QContactFilter::MatchFixedString | QContactFilter::MatchContains) << "abc";
436         }
437
438         /* Detail filter semantics: empty definition or field */
439         newMRow("Invalid type", manager) << manager << static_cast<QContactDetail::DetailType>(-1) << -1 << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << es; // empty definition name means filter matches nothing
440         newMRow("Invalid field", manager) << manager << name << -1 << QVariant("A") << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk"; // invalid field matches any with a name detail
441     }
442 }
443
444 void tst_QContactManagerFiltering::detailStringFiltering()
445 {
446     QFETCH(QContactManager*, cm);
447     QFETCH(QContactDetail::DetailType, detailType);
448     QFETCH(int, detailField);
449     QFETCH(QVariant, value);
450     QFETCH(int, matchflags);
451     QFETCH(QString, expected);
452
453     QList<QContactId> contacts = contactsAddedToManagers.values(cm);
454     QList<QContactId> ids;
455
456     QContactDetailFilter df;
457     df.setDetailType(detailType, detailField);
458     df.setValue(value);
459     df.setMatchFlags(QContactFilter::MatchFlags(matchflags));
460
461     if (cm->managerName() == "memory") {
462         /* At this point, since we're using memory, assume the filter isn't really supported */
463         QVERIFY(cm->isFilterSupported(df) == false);
464     }
465
466     ids = cm->contactIds(df);
467
468     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
469     QEXPECT_FAIL("integer == 20", "Not sure if this should pass or fail", Continue);
470     QCOMPARE_UNSORTED(output, expected);
471 }
472
473 void tst_QContactManagerFiltering::detailPhoneNumberFiltering_data()
474 {
475     QTest::addColumn<QContactManager *>("cm");
476     QTest::addColumn<QContactDetail::DetailType>("detailType");
477     QTest::addColumn<int>("detailField");
478     QTest::addColumn<QVariant>("value");
479     QTest::addColumn<int>("matchflags");
480     QTest::addColumn<QString>("expected");
481
482     // ITU-T standard keypad collation:
483     // 2 = abc, 3 = def, 4 = ghi, 5 = jkl, 6 = mno, 7 = pqrs, 8 = tuv, 9 = wxyz, 0 = space
484
485     QContactDetail::DetailType phoneType = QContactPhoneNumber::Type;
486     int phoneField = QContactPhoneNumber::FieldNumber;
487     QContactDetail::DetailType nameType = QContactName::Type;
488     int nameField = QContactName::FieldFirstName; // just test the first name.
489
490     // purely to test phone number filtering.
491     for (int i = 0; i < managers.size(); i++) {
492         QContactManager *manager = managers.at(i);
493
494         // first, keypad collation testing (ITU-T / T9 testing)
495         QTest::newRow("t9 aaron") << manager << nameType << nameField << QVariant(QString("22766")) << (int)(QContactFilter::MatchKeypadCollation) << "a";
496         QTest::newRow("t9 bob") << manager << nameType << nameField << QVariant(QString("262")) << (int)(QContactFilter::MatchKeypadCollation) << "b";
497         QTest::newRow("t9 john") << manager << nameType << nameField << QVariant(QString("5646")) << (int)(QContactFilter::MatchKeypadCollation) << "efg";
498         QTest::newRow("t9 bo") << manager << nameType << nameField << QVariant(QString("26")) << (int)(QContactFilter::MatchKeypadCollation | QContactFilter::MatchStartsWith) << "bc"; // bob, boris
499         QTest::newRow("t9 zzzz") << manager << nameType << nameField << QVariant(QString("9999")) << (int)(QContactFilter::MatchKeypadCollation) << ""; // nobody.
500
501         // now do phone number matching - first, aaron's phone number
502         QTest::newRow("a phone hyphen") << manager << phoneType << phoneField << QVariant(QString("555-1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
503         QTest::newRow("a phone plus") << manager << phoneType << phoneField << QVariant(QString("+5551212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
504         QTest::newRow("a phone brackets") << manager << phoneType << phoneField << QVariant(QString("(555)1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
505         QTest::newRow("a phone nospaces") << manager << phoneType << phoneField << QVariant(QString("5551212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
506         QTest::newRow("a phone single space") << manager << phoneType << phoneField << QVariant(QString("555 1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
507         QTest::newRow("a phone random spaces") << manager << phoneType << phoneField << QVariant(QString("55 512 12")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
508         QTest::newRow("a phone every space") << manager << phoneType << phoneField << QVariant(QString("5 5 5 1 2 1 2")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
509         QTest::newRow("a phone plus hyphen") << manager << phoneType << phoneField << QVariant(QString("+555-1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
510         QTest::newRow("a phone plus brackets") << manager << phoneType << phoneField << QVariant(QString("+5(55)1212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
511         QTest::newRow("a phone plus brackets hyphen") << manager << phoneType << phoneField << QVariant(QString("+5(55)1-212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
512         QTest::newRow("a phone plus brackets hyphen spaces") << manager << phoneType << phoneField << QVariant(QString("+5 (55) 1-212")) << (int)(QContactFilter::MatchPhoneNumber) << "a";
513
514         // XXX TODO: should we test for character to number conversions (eg, dial 1800-PESTCONTROL) etc ?
515         //QTest::newRow("a phone characters") << manager << phoneType << phoneField << QVariant(QString("jjj1a1a")) << (int)(QContactFilter::MatchPhoneNumber) << "a"; // 5551212
516         //QTest::newRow("a phone characters") << manager << phoneType << phoneField << QVariant(QString("jkl1b1a")) << (int)(QContactFilter::MatchPhoneNumber) << "a"; // 5551212
517
518         // then matches bob's phone number
519         QTest::newRow("b phone hyphen") << manager << phoneType << phoneField << QVariant(QString("555-3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
520         QTest::newRow("b phone plus") << manager << phoneType << phoneField << QVariant(QString("+5553456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
521         QTest::newRow("b phone brackets") << manager << phoneType << phoneField << QVariant(QString("(555)3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
522         QTest::newRow("b phone nospaces") << manager << phoneType << phoneField << QVariant(QString("5553456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
523         QTest::newRow("b phone single space") << manager << phoneType << phoneField << QVariant(QString("555 3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
524         QTest::newRow("b phone random spaces") << manager << phoneType << phoneField << QVariant(QString("55 534 56")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
525         QTest::newRow("b phone every space") << manager << phoneType << phoneField << QVariant(QString("5 5 5 3 4 5 6")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
526         QTest::newRow("b phone plus hyphen") << manager << phoneType << phoneField << QVariant(QString("+555-3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
527         QTest::newRow("b phone plus brackets") << manager << phoneType << phoneField << QVariant(QString("+5(55)3456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
528         QTest::newRow("b phone plus brackets hyphen") << manager << phoneType << phoneField << QVariant(QString("+5(55)3-456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
529         QTest::newRow("b phone plus brackets hyphen spaces") << manager << phoneType << phoneField << QVariant(QString("+5 (55) 3-456")) << (int)(QContactFilter::MatchPhoneNumber) << "b";
530
531         // then match no phone numbers (negative testing) -- 555-9999 matches nobody in our test set.
532         QTest::newRow("no phone hyphen") << manager << phoneType << phoneField << QVariant(QString("555-9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
533         QTest::newRow("no phone plus") << manager << phoneType << phoneField << QVariant(QString("+5559999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
534         QTest::newRow("no phone brackets") << manager << phoneType << phoneField << QVariant(QString("(555)9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
535         QTest::newRow("no phone nospaces") << manager << phoneType << phoneField << QVariant(QString("5559999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
536         QTest::newRow("no phone single space") << manager << phoneType << phoneField << QVariant(QString("555 9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
537         QTest::newRow("no phone random spaces") << manager << phoneType << phoneField << QVariant(QString("55 599 99")) << (int)(QContactFilter::MatchPhoneNumber) << "";
538         QTest::newRow("no phone every space") << manager << phoneType << phoneField << QVariant(QString("5 5 5 9 9 9 9")) << (int)(QContactFilter::MatchPhoneNumber) << "";
539         QTest::newRow("no phone plus hyphen") << manager << phoneType << phoneField << QVariant(QString("+555-9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
540         QTest::newRow("no phone plus brackets") << manager << phoneType << phoneField << QVariant(QString("+5(55)9999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
541         QTest::newRow("no phone plus brackets hyphen") << manager << phoneType << phoneField << QVariant(QString("+5(55)9-999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
542         QTest::newRow("no phone plus brackets hyphen spaces") << manager << phoneType << phoneField << QVariant(QString("+5 (55) 9-999")) << (int)(QContactFilter::MatchPhoneNumber) << "";
543
544         // then match both aaron and bob via starts with
545         QTest::newRow("ab phone starts nospace") << manager << phoneType << phoneField << QVariant(QString("555")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
546         QTest::newRow("ab phone starts hyphen") << manager << phoneType << phoneField << QVariant(QString("555-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
547         QTest::newRow("ab phone starts space") << manager << phoneType << phoneField << QVariant(QString("55 5")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
548         QTest::newRow("ab phone starts brackets") << manager << phoneType << phoneField << QVariant(QString("(555)")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
549         QTest::newRow("ab phone starts plus") << manager << phoneType << phoneField << QVariant(QString("+555")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
550         QTest::newRow("ab phone starts hyphen space") << manager << phoneType << phoneField << QVariant(QString("5 55-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
551         QTest::newRow("ab phone starts hyphen space brackets") << manager << phoneType << phoneField << QVariant(QString("5 (55)-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
552         QTest::newRow("ab phone starts hyphen space brackets plus") << manager << phoneType << phoneField << QVariant(QString("+5 (55)-")) << (int)(QContactFilter::MatchPhoneNumber | QContactFilter::MatchStartsWith) << "ab";
553     }
554 }
555
556 void tst_QContactManagerFiltering::detailPhoneNumberFiltering()
557 {
558     QFETCH(QContactManager*, cm);
559     QFETCH(QContactDetail::DetailType, detailType);
560     QFETCH(int, detailField);
561     QFETCH(QVariant, value);
562     QFETCH(int, matchflags);
563     QFETCH(QString, expected);
564
565     // note: this test is exactly the same as string filtering, but uses different fields and specific matchflags.
566
567     QList<QContactId> contacts = contactsAddedToManagers.values(cm);
568     QList<QContactId> ids;
569
570     QContactDetailFilter df;
571     df.setDetailType(detailType, detailField);
572     df.setValue(value);
573     df.setMatchFlags(QContactFilter::MatchFlags(matchflags));
574
575     if (cm->managerName() == "memory") {
576         /* At this point, since we're using memory, assume the filter isn't really supported */
577         QVERIFY(cm->isFilterSupported(df) == false);
578     }
579
580     ids = cm->contactIds(df);
581
582     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
583     //QSKIP("TODO: fix default implementation of phone number matching!");
584     QCOMPARE_UNSORTED(output, expected);
585 }
586
587 void tst_QContactManagerFiltering::detailVariantFiltering_data()
588 {
589     QTest::addColumn<QContactManager *>("cm");
590     QTest::addColumn<QContactDetail::DetailType>("detailType");
591     QTest::addColumn<int>("detailField");
592     QTest::addColumn<bool>("setValue");
593     QTest::addColumn<QVariant>("value");
594     QTest::addColumn<QString>("expected");
595
596     QVariant ev; // empty variant
597     QString es; // empty string
598     const int invalidField(666);
599
600     for (int i = 0; i < managers.size(); i++) {
601         QContactManager *manager = managers.at(i);
602
603         /* Nothings */
604         newMRow("no field", manager) << manager << static_cast<QContactDetail::DetailType>(-1) << -1 << false << ev << es;
605         newMRow("no type", manager) << manager << static_cast<QContactDetail::DetailType>(-1) << static_cast<int>(QContactName::FieldFirstName) << false << ev << es;
606
607         /* Strings (name) */
608         newMRow("first name presence", manager) << manager << QContactName::Type << static_cast<int>(QContactName::FieldFirstName) << false << ev << "abcdefghijk";
609         newMRow("first name == Aaron", manager) << manager << QContactName::Type << static_cast<int>(QContactName::FieldFirstName) << true << QVariant("Aaron") << "a";
610
611         /*
612          * Doubles
613          * B has double(4.0)
614          * C has double(4.0)
615          * D has double(-128.0)
616          */
617         QPair<QContactDetail::DetailType, int> defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Double");
618         if (validDetailField(defAndFieldNames)) {
619             newMRow("double presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "bcd";
620             QTest::newRow("double presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "bcd";
621             QTest::newRow("double presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
622             QTest::newRow("double value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
623             QTest::newRow("double value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QDateTime()) << es;
624             QTest::newRow("double value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(3.5) << es;
625             newMRow("double value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(4.0) << "bc";
626             QTest::newRow("double value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(4.0) << es;
627             QTest::newRow("double value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(-128.0) << "d";
628             QTest::newRow("double value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(-128.0) << es;
629         }
630
631         /*
632          * Integers
633          * A has 10
634          * B has 20
635          * C has -20
636          */
637         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Integer");
638         if (validDetailField(defAndFieldNames)) {
639             newMRow("integer presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "abc";
640             QTest::newRow("integer presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abc";
641             QTest::newRow("integer presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
642             QTest::newRow("integer value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(50) << es;
643             QTest::newRow("integer value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
644             QTest::newRow("integer value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(50) << es;
645             newMRow("integer value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(10) << "a";
646             QTest::newRow("integer value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(10) << es;
647             QTest::newRow("integer value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(-20) << "c";
648             QTest::newRow("integer value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(-20) << es;
649         }
650
651         /*
652          * Date times
653          * A has QDateTime(QDate(2009, 06, 29), QTime(16, 52, 23, 0))
654          * C has QDateTime(QDate(2009, 06, 29), QTime(16, 54, 17, 0))
655          */
656         const QDateTime adt(QDate(2009, 06, 29), QTime(16, 52, 23, 0));
657         const QDateTime cdt(QDate(2009, 06, 29), QTime(16, 54, 17, 0));
658
659         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("DateTime");
660         if (validDetailField(defAndFieldNames)) {
661             newMRow("datetime presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "ac";
662             QTest::newRow("datetime presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "ac";
663             QTest::newRow("datetime presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
664             QTest::newRow("datetime value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QDateTime(QDate(2100,5,13), QTime(5,5,5))) << es;
665             QTest::newRow("datetime value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
666             QTest::newRow("datetime value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QDateTime(QDate(2100,5,13), QTime(5,5,5))) << es;
667             newMRow("datetime value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(adt) << "a";
668             QTest::newRow("datetime value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(adt) << es;
669             QTest::newRow("datetime value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(cdt)<< "c";
670             QTest::newRow("datetime value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(cdt) << es;
671         }
672
673         /*
674          * Dates
675          * A has QDate(1988, 1, 26)
676          * B has QDate(2492, 5, 5)
677          * D has QDate(2770, 10, 1)
678          */
679         const QDate ad(1988, 1, 26);
680         const QDate bd(2492, 5, 5);
681         const QDate dd(2770, 10, 1);
682
683         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Date");
684         if (validDetailField(defAndFieldNames)) {
685             newMRow("date presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "abd";
686             QTest::newRow("date presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abd";
687             QTest::newRow("date presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
688             QTest::newRow("date value (no match)") << manager << defAndFieldNames.first <<defAndFieldNames.second << true << QVariant(QDate(2100,5,13)) << es;
689             QTest::newRow("date value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
690             QTest::newRow("date value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QDate(2100,5,13)) << es;
691             newMRow("date value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(ad) << "a";
692             QTest::newRow("date value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(ad) << es;
693             QTest::newRow("date value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(bd) << es;
694             QTest::newRow("date value 3 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(dd) << es;
695             QTest::newRow("date value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(bd)<< "b";
696             QTest::newRow("date value 3") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(dd)<< "d";
697         }
698
699         /*
700          * Times
701          * A has QTime(16,52,23,0)
702          * B has QTime(15,52,23,0)
703          */
704         const QTime at = QTime(16,52,23,0);
705         const QTime bt = QTime(15,52,23,0);
706
707         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Time");
708         if (validDetailField(defAndFieldNames)) {
709             newMRow("time presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "ab";
710             QTest::newRow("time presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "ab";
711             QTest::newRow("time presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
712             QTest::newRow("time value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QTime(5,5,5)) << es;
713             QTest::newRow("time value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
714             QTest::newRow("time value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QTime(5,5,5)) << es;
715             newMRow("time value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(at) << "a";
716             QTest::newRow("time value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(at) << es;
717             QTest::newRow("time value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(bt)<< "b";
718             QTest::newRow("time value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(bt) << es;
719         }
720
721
722         /*
723          * Bool
724          * A has bool(true)
725          * B has bool(false)
726          * C has bool(false)
727          */
728         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Bool");
729         if (validDetailField(defAndFieldNames)) {
730             newMRow("bool presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "abc";
731             QTest::newRow("bool presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abc";
732             QTest::newRow("bool presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
733             QTest::newRow("bool value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(4.0) << es;
734             newMRow("bool value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(true) << "a";
735             QTest::newRow("bool value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(true) << es;
736             QTest::newRow("bool value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(false) << "bc";
737             QTest::newRow("bool value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(false) << es;
738         }
739
740         /*
741          * LongLong
742          * C has LongLong(8000000000LL)
743          * D has LongLong(-14000000000LL)
744          */
745         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("LongLong");
746         if (validDetailField(defAndFieldNames)) {
747             newMRow("longlong presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "cd";
748             QTest::newRow("longlong presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "cd";
749             QTest::newRow("longlong presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
750             QTest::newRow("longlong value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(50000000000LL) << es;
751             QTest::newRow("longlong value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
752             QTest::newRow("longlong value (wrong field, no match)") << manager << defAndFieldNames.first<< invalidField << true << QVariant(50000000000LL) << es;
753             newMRow("longlong value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(8000000000LL) << "c";
754             QTest::newRow("longlong value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(8000000000LL) << es;
755             QTest::newRow("longlong value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(-14000000000LL) << "d";
756             QTest::newRow("longlong value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(-14000000000LL) << es;
757         }
758
759         /*
760          * ULongLong
761          * A has ULongLong(120000000000ULL)
762          * B has ULongLong(80000000000ULL)
763          * C has ULongLong(80000000000ULL)
764          */
765         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("ULongLong");
766         if (validDetailField(defAndFieldNames)) {
767             newMRow("ulonglong presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "abc";
768             QTest::newRow("ulonglong presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "abc";
769             QTest::newRow("ulonglong presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
770             QTest::newRow("ulonglong value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(50000000000ULL) << es;
771             QTest::newRow("ulonglong value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
772             QTest::newRow("ulonglong value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(50000000000ULL) << es;
773             newMRow("ulonglong value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(120000000000ULL) << "a";
774             QTest::newRow("ulonglong value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(120000000000ULL) << es;
775             QTest::newRow("ulonglong value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(80000000000ULL) << "bc";
776             QTest::newRow("ulonglong value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(80000000000ULL) << es;
777         }
778
779         /*
780          * UInt
781          * B has UInt(4000000000u)
782          * D has UInt(3000000000u)
783          */
784         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("UInt");
785         if (validDetailField(defAndFieldNames)) {
786             newMRow("unsigned integer presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "bd";
787             QTest::newRow("unsigned integer presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "bd";
788             QTest::newRow("unsigned integer presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
789             QTest::newRow("unsigned integer value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3500000000u) << es;
790             QTest::newRow("unsigned integer value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
791             QTest::newRow("unsigned integer value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(3500000000u) << es;
792             newMRow("unsigned integer value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(4000000000u) << "b";
793             QTest::newRow("unsigned integer value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(4000000000u) << es;
794             QTest::newRow("unsigned integer value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3000000000u) << "d";
795             QTest::newRow("unsigned integer value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(3000000000u) << es;
796         }
797
798         /*
799          * Char
800          * B has QChar('b')
801          * C has QChar('c')
802          */
803         const QChar bchar('b');
804         const QChar cchar('c');
805         defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Char");
806         if (validDetailField(defAndFieldNames)) {
807             newMRow("char presence", manager) << manager << defAndFieldNames.first << -1 << false << ev << "bc";
808             QTest::newRow("char presence (inc field)") << manager << defAndFieldNames.first << defAndFieldNames.second << false << ev << "bc";
809             QTest::newRow("char presence (wrong field)") << manager << defAndFieldNames.first << invalidField << false << ev << es;
810             QTest::newRow("char value (no match)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(QChar('a')) << es;
811             QTest::newRow("char value (wrong type)") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(3.5) << es;
812             QTest::newRow("char value (wrong field, no match)") << manager << defAndFieldNames.first << invalidField << true << QVariant(QChar('a')) << es;
813             newMRow("char value", manager) << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(bchar) << "b";
814             QTest::newRow("char value (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(bchar) << es;
815             QTest::newRow("char value 2") << manager << defAndFieldNames.first << defAndFieldNames.second << true << QVariant(cchar)<< "c";
816             QTest::newRow("char value 2 (wrong field)") << manager << defAndFieldNames.first << invalidField << true << QVariant(cchar) << es;
817         }
818     }
819 }
820
821 void tst_QContactManagerFiltering::detailVariantFiltering()
822 {
823     QFETCH(QContactManager*, cm);
824     QFETCH(QContactDetail::DetailType, detailType);
825     QFETCH(int, detailField);
826     QFETCH(bool, setValue);
827     QFETCH(QVariant, value);
828     QFETCH(QString, expected);
829
830     QList<QContactId> contacts = contactsAddedToManagers.values(cm);
831     QList<QContactId> ids;
832
833     QContactDetailFilter df;
834     df.setDetailType(detailType, detailField);
835     if (setValue)
836         df.setValue(value);
837
838     if (cm->managerName() == "memory") {
839         /* At this point, since we're using memory, assume the filter isn't really supported */
840         QVERIFY(cm->isFilterSupported(df) == false);
841     }
842
843     ids = cm->contactIds(df);
844
845     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
846     QCOMPARE_UNSORTED(output, expected);
847 }
848
849 void tst_QContactManagerFiltering::rangeFiltering_data()
850 {
851     QTest::addColumn<QContactManager *>("cm");
852     QTest::addColumn<QContactDetail::DetailType>("detailType");
853     QTest::addColumn<int>("detailField");
854     QTest::addColumn<QVariant>("minrange");
855     QTest::addColumn<QVariant>("maxrange");
856     QTest::addColumn<bool>("setrfs");
857     QTest::addColumn<int>("rangeflagsi");
858     QTest::addColumn<bool>("setmfs");
859     QTest::addColumn<int>("matchflagsi");
860     QTest::addColumn<QString>("expected");
861
862     QVariant ev; // empty variant
863     QString es; // empty string
864     const int invalidField(666);
865
866     QContactDetail::DetailType nameType = QContactName::Type;
867     int firstname = QContactName::FieldFirstName;
868
869     QContactDetail::DetailType phoneType = QContactPhoneNumber::Type;
870     int phonenum = QContactPhoneNumber::FieldNumber;
871
872     int csflag = (int)QContactFilter::MatchCaseSensitive;
873
874     for (int i = 0; i < managers.size(); i++) {
875         QContactManager *manager = managers.at(i);
876
877         /* First, cover the "empty detailType / detailField / ranges" cases */
878         newMRow("invalid detailType", manager) << manager << QContactDetail::TypeUndefined << firstname << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << es;
879         newMRow("defn presence test", manager) << manager << nameType << -1 << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << "abcdefghijk";
880         newMRow("field presence test", manager) << manager << phoneType << phonenum << QVariant() << QVariant() << false << 0 << true << 0 << "ab";
881         newMRow("good type, bad field", manager) << manager << nameType << invalidField << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << es;
882         newMRow("bad def", manager) << manager << static_cast<QContactDetail::DetailType>(-1) << -1 << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << es;
883
884         /* Presence for fields that aren't there */
885         newMRow("defn presence test negative", manager) << manager << QContactFamily::Type << -1 << ev << ev << false << 0 << false << 0 << es;
886         newMRow("field presence test negative", manager) << manager << QContactFamily::Type << invalidField << ev << ev << false << 0 << false << 0 << es;
887         newMRow("defn yes, field no presence test negative", manager) << manager << nameType << invalidField << ev << ev << false << 0 << false << 0 << es;
888
889         newMRow("no max, all results", manager) << manager << nameType << firstname << QVariant("a") << QVariant() << false << 0 << true << 0 << "abcdefghijk";
890         newMRow("no max, some results", manager) << manager << nameType << firstname << QVariant("bob") << QVariant() << false << 0 << true << 0 << "bcdefghijk";
891         newMRow("no max, no results", manager) << manager << nameType << firstname << QVariant("ZamBeZI") << QVariant() << false << 0 << true << 0 << es;
892         newMRow("no min, all results", manager) << manager << nameType << firstname << QVariant() << QVariant("zambezi") << false << 0 << true << 0 << "abcdefghijk";
893         newMRow("no min, some results", manager) << manager << nameType << firstname << QVariant() << QVariant("bOb") << false << 0 << true << 0 << "a";
894         newMRow("no min, no results", manager) << manager << nameType << firstname << QVariant() << QVariant("aardvark") << false << 0 << true << 0 << es;
895
896         /* now case sensitive */
897         newMRow("no max, cs, all results", manager) << manager << nameType << firstname << QVariant("A") << QVariant() << false << 0 << true << csflag << "abcdefghijk";
898         newMRow("no max, cs, some results", manager) << manager << nameType << firstname << QVariant("Bob") << QVariant() << false << 0 << true << csflag << "bcdefghijk";
899         newMRow("no max, cs, no results", manager) << manager << nameType << firstname << QVariant("Xambezi") << QVariant() << false << 0 << true << csflag << "hijk";
900         newMRow("no min, cs, most results", manager) << manager << nameType << firstname << QVariant() << QVariant("Xambezi") << false << 0 << true << csflag << "abcdefg";
901         newMRow("no min, cs, some results", manager) << manager << nameType << firstname << QVariant() << QVariant("Bob") << false << 0 << true << csflag << "a";
902         newMRow("no min, cs, no results", manager) << manager << nameType << firstname << QVariant() << QVariant("Aardvark") << false << 0 << true << csflag << es;
903         newMRow("no max, cs, badcase, all results", manager) << manager << nameType << firstname << QVariant("A") << QVariant() << false << 0 << true << csflag << "abcdefghijk";
904 #ifdef Q_OS_SYMBIAN
905         qWarning() << "Test case \"no max, cs, badcase, some results\" will fail on symbian platform because of QString::localeAwareCompare is not actually locale aware";
906 #endif
907         newMRow("no max, cs, badcase, some results", manager) << manager << nameType << firstname << QVariant("bob") << QVariant() << false << 0 << true << csflag
908 #ifdef QT_USE_ICU
909                                                               // Case sensitivity is handled differently with/without ICU (in one case, the char sequence is
910                                                               // 'A-Za-z', in the other it is 'AaBb..Zz') - the results are therefore highly divergent
911                                                               << "bcdefghijk";
912 #else
913                                                               << "hj";
914 #endif
915         newMRow("no max, cs, badcase, no results", manager) << manager << nameType << firstname << QVariant("XAMBEZI") << QVariant() << false << 0 << true << csflag << "hijk";
916         newMRow("no min, cs, badcase, all results", manager) << manager << nameType << firstname << QVariant() << QVariant("XAMBEZI") << false << 0 << true << csflag << "abcdefg";
917 #ifdef Q_OS_SYMBIAN
918         qWarning() << "Test case \"no min, cs, badcase, some results\" will fail on symbian platform because of QString::localeAwareCompare is not actually locale aware";
919 #endif
920         newMRow("no min, cs, badcase, some results", manager) << manager << nameType << firstname << QVariant() << QVariant("BOB") << false << 0 << true << csflag
921 #ifdef QT_USE_ICU
922                                                               << "ab";
923 #else
924                                                               << "a";
925 #endif
926         newMRow("no min, cs, badcase, no results", manager) << manager << nameType << firstname << QVariant() << QVariant("AARDVARK") << false << 0 << true << csflag << es;
927
928         /* 'a' has phone number ("5551212") */
929         QTest::newRow("range1") << manager << phoneType << phonenum << QVariant("5551200") << QVariant("5551220") << false << 0 << false << 0 << "a";
930
931         /* A(Aaron Aaronson), B(Bob Aaronsen), C(Boris Aaronsun), D(Dennis FitzMacyntire) */
932         // string range matching - no matchflags set.
933         QTest::newRow("string range - no matchflags - 1") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << false << 0 << true << 0 << "a";
934         QTest::newRow("string range - no matchflags - 2") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "a";
935         QTest::newRow("string range - no matchflags - 3") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "a";
936         QTest::newRow("string range - no matchflags - 4") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "ab";
937         QTest::newRow("string range - no matchflags - 5") << manager << nameType << firstname << QVariant("A") << QVariant("Bob") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "ab";
938         QTest::newRow("string range - no matchflags - 6") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "c";
939         QTest::newRow("string range - no matchflags - 7") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "b";
940         QTest::newRow("string range - no matchflags - 8") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << 0 << "bc";
941         QTest::newRow("string range - no matchflags - 9") << manager << nameType << firstname << QVariant("Bob") << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "";
942         QTest::newRow("string range - no matchflags - 10") << manager << nameType << firstname << QVariant("Barry") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << 0 << "bc";
943
944         // string range matching - QContactFilter::MatchStartsWith should produce the same results as without matchflags set.
945         QTest::newRow("string range - startswith - 1") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "a";
946         QTest::newRow("string range - startswith - 2") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "a";
947         QTest::newRow("string range - startswith - 3") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "ab";
948         QTest::newRow("string range - startswith - 4") << manager << nameType << firstname << QVariant("A") << QVariant("Bo") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "ab";
949         QTest::newRow("string range - startswith - 5") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "c";
950         QTest::newRow("string range - startswith - 6") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "bc";
951         QTest::newRow("string range - startswith - 7") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "bc";
952         QTest::newRow("string range - startswith - 8") << manager << nameType << firstname << QVariant("Bo") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "c";
953         QTest::newRow("string range - startswith - 9") << manager << nameType << firstname << QVariant("Barry") << QVariant("C") << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "bc";
954
955         // Open ended starts with
956         QTest::newRow("string range - startswith open top - 1") << manager << nameType << firstname << QVariant("A") << ev << true << (int)(QContactDetailRangeFilter::IncludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk";
957         QTest::newRow("string range - startswith open top - 2") << manager << nameType << firstname << QVariant("A") << ev << true << (int)(QContactDetailRangeFilter::ExcludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk";
958         QTest::newRow("string range - startswith open top - 3") << manager << nameType << firstname << QVariant("Aaron") << ev << true << (int)(QContactDetailRangeFilter::IncludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "abcdefghijk";
959         QTest::newRow("string range - startswith open top - 4") << manager << nameType << firstname << QVariant("Aaron") << ev << true << (int)(QContactDetailRangeFilter::ExcludeLower) << true << (int)(QContactFilter::MatchStartsWith) << "bcdefghijk";
960         QTest::newRow("string range - startswith open bottom - 1") << manager << nameType << firstname << ev << QVariant("Borit") << true << (int)(QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "abc";
961         QTest::newRow("string range - startswith open bottom - 2") << manager << nameType << firstname << ev << QVariant("Borit") << true << (int)(QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "abc";
962         QTest::newRow("string range - startswith open bottom - 3") << manager << nameType << firstname << ev << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::IncludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "abc";
963         QTest::newRow("string range - startswith open bottom - 4") << manager << nameType << firstname << ev << QVariant("Boris") << true << (int)(QContactDetailRangeFilter::ExcludeUpper) << true << (int)(QContactFilter::MatchStartsWith) << "ab";
964
965         /* A(10), B(20), C(-20) */
966         // Now integer range testing
967         QPair<QContactDetail::DetailType, int> defAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Integer");
968         if (validDetailField(defAndFieldNames)) {
969             QTest::newRow("int range - no rangeflags - 1") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant(9) << false << 0 << false << 0 << es;
970             QTest::newRow("int range - no rangeflags - 2") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant(10) << false << 0 << false << 0 << es;
971             QTest::newRow("int range - no rangeflags - 3") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant(11) << false << 0 << false << 0 << "a";
972             QTest::newRow("int range - no rangeflags - 4") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << false << 0 << false << 0 << es;
973             QTest::newRow("int range - rangeflags - 1") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper) << false << 0 << es;
974             QTest::newRow("int range - rangeflags - 2") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::ExcludeUpper) << false << 0 << es;
975             QTest::newRow("int range - rangeflags - 3") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << es;
976             QTest::newRow("int range - rangeflags - 4") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(10) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "a";
977             QTest::newRow("int range - rangeflags - 5") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(10) << QVariant(11) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "a";
978             QTest::newRow("int range - rangeflags - 6") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(11) << QVariant(11) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << es;
979             QTest::newRow("int range - rangeflags - 7") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(-30) << QVariant(-19) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "c";
980             QTest::newRow("int range - rangeflags - 8") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(-20) << QVariant(-30) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << es;
981             QTest::newRow("int range - rangeflags - variant - 1") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant(9) << QVariant() << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "ab";
982             QTest::newRow("int range - rangeflags - variant - 2") << manager << defAndFieldNames.first << defAndFieldNames.second << QVariant() << QVariant(11) << true << (int)(QContactDetailRangeFilter::IncludeLower | QContactDetailRangeFilter::IncludeUpper) << false << 0 << "ac";
983         }
984     }
985 }
986
987 void tst_QContactManagerFiltering::rangeFiltering()
988 {
989     QFETCH(QContactManager*, cm);
990     QFETCH(QContactDetail::DetailType, detailType);
991     QFETCH(int, detailField);
992     QFETCH(QVariant, minrange);
993     QFETCH(QVariant, maxrange);
994     QFETCH(bool, setrfs);
995     QFETCH(int, rangeflagsi);
996     QFETCH(bool, setmfs);
997     QFETCH(int, matchflagsi);
998     QFETCH(QString, expected);
999
1000     QContactDetailRangeFilter::RangeFlags rangeflags = (QContactDetailRangeFilter::RangeFlags)rangeflagsi;
1001     QContactFilter::MatchFlags matchflags = (QContactFilter::MatchFlags) matchflagsi;
1002
1003     QList<QContactId> contacts = contactsAddedToManagers.values(cm);
1004     QList<QContactId> ids;
1005
1006     /* Build the range filter */
1007     QContactDetailRangeFilter drf;
1008     drf.setDetailType(detailType, detailField);
1009     if (setrfs)
1010         drf.setRange(minrange, maxrange, rangeflags);
1011     else
1012         drf.setRange(minrange, maxrange);
1013     if (setmfs)
1014         drf.setMatchFlags(matchflags);
1015
1016     if (cm->managerName() == "memory") {
1017         /* At this point, since we're using memory, assume the filter isn't really supported */
1018         QVERIFY(cm->isFilterSupported(drf) == false);
1019     }
1020     ids = cm->contactIds(drf);
1021
1022     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
1023     QEXPECT_FAIL("string range - startswith - 3", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1024     QEXPECT_FAIL("string range - startswith - 4", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1025     QEXPECT_FAIL("string range - startswith - 5", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1026     QEXPECT_FAIL("string range - startswith - 8", "No handling for startsWith exists in QContactDetailRangeFilter implementation", Continue);
1027     QCOMPARE_UNSORTED(output, expected);
1028 }
1029
1030 void tst_QContactManagerFiltering::intersectionFiltering_data()
1031 {
1032     QTest::addColumn<QContactManager *>("cm");
1033     QTest::addColumn<bool>("firstfilter");
1034     QTest::addColumn<int>("fftype"); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1035     QTest::addColumn<QContactDetail::DetailType>("ffdetailtype");
1036     QTest::addColumn<int>("ffdetailfield");
1037     QTest::addColumn<bool>("ffsetvalue");
1038     QTest::addColumn<QVariant>("ffvalue");
1039     QTest::addColumn<QVariant>("ffminrange");
1040     QTest::addColumn<QVariant>("ffmaxrange");
1041     QTest::addColumn<bool>("secondfilter");
1042     QTest::addColumn<int>("sftype");
1043     QTest::addColumn<QContactDetail::DetailType>("sfdetailtype");
1044     QTest::addColumn<int>("sfdetailfield");
1045     QTest::addColumn<bool>("sfsetvalue");
1046     QTest::addColumn<QVariant>("sfvalue");
1047     QTest::addColumn<QVariant>("sfminrange");
1048     QTest::addColumn<QVariant>("sfmaxrange");
1049     QTest::addColumn<QString>("order");
1050     QTest::addColumn<QString>("expected");
1051
1052     QString es; // empty string.
1053
1054     for (int i = 0; i < managers.size(); i++) {
1055         QContactManager *manager = managers.at(i);
1056
1057         // for the following tests, terminology:
1058         // X will be an (empty) intersection filter created in the test
1059         // Y will be the first filter defined here
1060         // Z will be the second filter defined here
1061
1062         // WITH Y AND Z AS DETAIL FILTERS (with no overlap between Y and Z results)
1063         // For these tests, Y matches "bc" and Z matches "a"
1064         // X && Y - X empty so es
1065         QPair<QContactDetail::DetailType, int> integerDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Integer");
1066         QPair<QContactDetail::DetailType, int> booleanDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Bool");
1067         if (validDetailField(integerDefAndFieldNames) && validDetailField(booleanDefAndFieldNames)) {
1068             QTest::newRow("A1") << manager
1069                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1070                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1071                                 << "XY" << es;
1072             // Y && X - X empty so es
1073             QTest::newRow("A2") << manager
1074                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1075                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1076                                 << "YX" << es;
1077             // Y && Z  - matches "a" and "bc" - so intersected = es
1078             QTest::newRow("A3") << manager
1079                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1080                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1081                                 << "YZ" << es;
1082             // Z && Y - matches "bc" and "a" - so intersected = es
1083             QTest::newRow("A4") << manager
1084                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1085                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1086                                 << "ZY" << es;
1087             // X && Z - X empty so es
1088             QTest::newRow("A5") << manager
1089                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1090                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1091                                 << "XZ" << es;
1092             // Z && X - X empty so es
1093             QTest::newRow("A6") << manager
1094                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1095                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1096                                 << "ZX" << es;
1097             // X && Y && Z - X empty so es
1098             QTest::newRow("A7") << manager
1099                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1100                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1101                                 << "XYZ" << es;
1102             // X && Z && Y - X empty so es
1103             QTest::newRow("A8") << manager
1104                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1105                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1106                                 << "XZY" << es;
1107             // Y && X && Z - X empty so es
1108             QTest::newRow("A9") << manager
1109                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1110                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1111                                 << "YXZ" << es;
1112             // Z && X && Y - X empty so es
1113             QTest::newRow("A10") << manager
1114                                  << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1115                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1116                                  << "ZXY" << es;
1117             // Y && Z && X - X empty so es
1118             QTest::newRow("A11") << manager
1119                                  << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1120                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1121                                  << "YZX" << es;
1122             // Z && Y && X - X empty so es
1123             QTest::newRow("A12") << manager
1124                                  << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1125                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1126                                  << "ZYX" << es;
1127
1128             // WITH Y AND Z AS DETAIL FILTERS (with some overlap between Y and Z results)
1129             // For these tests, Y matches "bc", Z matches "b"
1130             // X && Y - X empty so es
1131             QTest::newRow("B1") << manager
1132                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1133                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1134                                 << "XY" << es;
1135             // Y && X - X empty so es
1136             QTest::newRow("B2") << manager
1137                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1138                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1139                                 << "YX" << es;
1140             // Y && Z  - matches "b" and "bc" - so intersected = "b"
1141             QTest::newRow("B3") << manager
1142                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1143                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1144                                 << "YZ" << "b";
1145             // Z && Y - matches "bc" and "b" - so intersected = "b"
1146             QTest::newRow("B4") << manager
1147                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1148                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1149                                 << "ZY" << "b";
1150             // X && Z - X empty so es
1151             QTest::newRow("B5") << manager
1152                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1153                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1154                                 << "XZ" << es;
1155             // Z && X - X empty so es
1156             QTest::newRow("B6") << manager
1157                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1158                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1159                                 << "ZX" << es;
1160             // X && Y && Z - X empty so es
1161             QTest::newRow("B7") << manager
1162                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1163                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1164                                 << "XYZ" << es;
1165             // X && Z && Y - X empty so es
1166             QTest::newRow("B8") << manager
1167                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1168                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1169                                 << "XZY" << es;
1170             // Y && X && Z - X empty so es
1171             QTest::newRow("B9") << manager
1172                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1173                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1174                                 << "YXZ" << es;
1175             // Z && X && Y - X empty so es
1176             QTest::newRow("B10") << manager
1177                                  << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1178                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1179                                  << "ZXY" << es;
1180             // Y && Z && X - X empty so es
1181             QTest::newRow("B11") << manager
1182                                  << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1183                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1184                                  << "YZX" << es;
1185             // Z && Y && X - X empty so es
1186             QTest::newRow("B12") << manager
1187                                  << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1188                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1189                                  << "ZYX" << es;
1190         }
1191
1192         //---------------------------
1193
1194         // WITH Y AND Z AS RANGE FILTERS (with no overlap between Y and Z results)
1195         // For these tests, Y matches "a", Z matches "b"
1196         // X && Y - X empty so es
1197         if (validDetailField(integerDefAndFieldNames)) {
1198             QTest::newRow("C1") << manager
1199                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1200                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1201                                 << "XY" << es;
1202             // Y && X - X empty so es
1203             QTest::newRow("C2") << manager
1204                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1205                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1206                                 << "YX" << es;
1207             // Y && Z - no overlap so es
1208             QTest::newRow("C3") << manager
1209                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1210                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1211                                 << "YZ" << es;
1212             // Z && Y - no overlap so es
1213             QTest::newRow("C4") << manager
1214                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1215                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1216                                 << "ZY" << es;
1217             // X && Z - X empty so es
1218             QTest::newRow("C5") << manager
1219                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1220                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1221                                 << "XZ" << es;
1222             // Z && X - X empty so es
1223             QTest::newRow("C6") << manager
1224                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1225                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1226                                 << "ZX" << es;
1227             // X && Y && Z - X empty so es
1228             QTest::newRow("C7") << manager
1229                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1230                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1231                                 << "XYZ" << es;
1232             // X && Z && Y - X empty so es
1233             QTest::newRow("C8") << manager
1234                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1235                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1236                                 << "XZY" << es;
1237             // Y && X && Z - X empty so es
1238             QTest::newRow("C9") << manager
1239                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1240                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1241                                 << "YXZ" << es;
1242             // Z && X && Y - X empty so es
1243             QTest::newRow("C10") << manager
1244                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1245                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1246                                  << "ZXY" << es;
1247             // Y && Z && X - X empty so es
1248             QTest::newRow("C11") << manager
1249                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1250                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1251                                  << "YZX" << es;
1252             // Z && Y && X - X empty so es
1253             QTest::newRow("C12") << manager
1254                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1255                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1256                                  << "ZYX" << es;
1257
1258             // WITH Y AND Z AS RANGE FILTERS (with some overlap between Y and Z results)
1259             // For these tests, Y matches "ab", Z matches "b"
1260             // X && Y - X empty so es
1261             QTest::newRow("D1") << manager
1262                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1263                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1264                                 << "XY" << es;
1265             // Y && X - X empty so es
1266             QTest::newRow("D2") << manager
1267                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1268                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1269                                 << "YX" << es;
1270             // Y && Z - Y matches "ab", Z matches "b", intersection = "b"
1271             QTest::newRow("D3") << manager
1272                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1273                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1274                                 << "YZ" << "b";
1275             // Z && Y - Y matches "ab", Z matches "b", intersection = "b"
1276             QTest::newRow("D4") << manager
1277                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1278                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1279                                 << "ZY" << "b";
1280             // X && Z - X empty so es
1281             QTest::newRow("D5") << manager
1282                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1283                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1284                                 << "XZ" << es;
1285             // Z && X - X empty so es
1286             QTest::newRow("D6") << manager
1287                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1288                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1289                                 << "ZX" << es;
1290             // X && Y && Z - X empty so es
1291             QTest::newRow("D7") << manager
1292                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1293                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1294                                 << "XYZ" << es;
1295             // X && Z && Y - X empty so es
1296             QTest::newRow("D8") << manager
1297                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1298                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1299                                 << "XZY" << es;
1300             // Y && X && Z - X empty so es
1301             QTest::newRow("D9") << manager
1302                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1303                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1304                                 << "YXZ" << es;
1305             // Z && X && Y - X empty so es
1306             QTest::newRow("D10") << manager
1307                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1308                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1309                                  << "ZXY" << es;
1310             // Y && Z && X - X empty so es
1311             QTest::newRow("D11") << manager
1312                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1313                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1314                                  << "YZX" << es;
1315             // Z && Y && X - X empty so es
1316             QTest::newRow("D12") << manager
1317                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1318                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1319                                  << "ZYX" << es;
1320         }
1321     }
1322 }
1323
1324 void tst_QContactManagerFiltering::intersectionFiltering()
1325 {
1326     QFETCH(QContactManager*, cm);
1327     QFETCH(bool, firstfilter);
1328     QFETCH(int, fftype); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1329     QFETCH(QContactDetail::DetailType, ffdetailtype);
1330     QFETCH(int, ffdetailfield);
1331     QFETCH(bool, ffsetvalue);
1332     QFETCH(QVariant, ffvalue);
1333     QFETCH(QVariant, ffminrange);
1334     QFETCH(QVariant, ffmaxrange);
1335     QFETCH(bool, secondfilter);
1336     QFETCH(int, sftype);
1337     QFETCH(QContactDetail::DetailType, sfdetailtype);
1338     QFETCH(int, sfdetailfield);
1339     QFETCH(bool, sfsetvalue);
1340     QFETCH(QVariant, sfvalue);
1341     QFETCH(QVariant, sfminrange);
1342     QFETCH(QVariant, sfmaxrange);
1343     QFETCH(QString, order);
1344     QFETCH(QString, expected);
1345
1346     QContactFilter *x = new QContactIntersectionFilter();
1347     QContactFilter *y = 0, *z = 0;
1348
1349     if (firstfilter) {
1350         switch (fftype) {
1351             case 1: // detail filter
1352                 y = new QContactDetailFilter();
1353                 static_cast<QContactDetailFilter*>(y)->setDetailType(ffdetailtype, ffdetailfield);
1354                 if (ffsetvalue)
1355                     static_cast<QContactDetailFilter*>(y)->setValue(ffvalue);
1356                 break;
1357             case 2: // range filter
1358                 y = new QContactDetailRangeFilter();
1359                 static_cast<QContactDetailRangeFilter*>(y)->setDetailType(ffdetailtype, ffdetailfield);
1360                 static_cast<QContactDetailRangeFilter*>(y)->setRange(ffminrange, ffmaxrange);
1361                 break;
1362             case 3: // group membership filter
1363             case 4: // union filter
1364             case 5: // intersection filter
1365                 break;
1366
1367             default:
1368                 QVERIFY(false); // force fail.
1369             break;
1370         }
1371     }
1372
1373     if (secondfilter) {
1374         switch (sftype) {
1375             case 1: // detail filter
1376                 z = new QContactDetailFilter();
1377                 static_cast<QContactDetailFilter*>(z)->setDetailType(sfdetailtype, sfdetailfield);
1378                 if (sfsetvalue)
1379                     static_cast<QContactDetailFilter*>(z)->setValue(sfvalue);
1380                 break;
1381             case 2: // range filter
1382                 z = new QContactDetailRangeFilter();
1383                 static_cast<QContactDetailRangeFilter*>(z)->setDetailType(sfdetailtype, sfdetailfield);
1384                 static_cast<QContactDetailRangeFilter*>(z)->setRange(sfminrange, sfmaxrange);
1385                 break;
1386             case 3: // group membership filter
1387             case 4: // union filter
1388             case 5: // intersection filter
1389                 break;
1390
1391             default:
1392                 QVERIFY(false); // force fail.
1393             break;
1394         }
1395     }
1396
1397     // control variables - order: starts, ends, mids
1398     bool sX = false;
1399     bool sY = false;
1400     bool sZ = false;
1401     bool eX = false;
1402     bool eY = false;
1403     bool eZ = false;
1404     bool mX = false;
1405     bool mY = false;
1406     bool mZ = false;
1407
1408     if (order.startsWith("X"))
1409         sX = true;
1410     if (order.startsWith("Y"))
1411         sY = true;
1412     if (order.startsWith("Z"))
1413         sZ = true;
1414     if (order.endsWith("X"))
1415         eX = true;
1416     if (order.endsWith("Y"))
1417         eY = true;
1418     if (order.endsWith("Z"))
1419         eZ = true;
1420     if (order.size() > 2) {
1421         if (order.at(1) == 'X')
1422             mX = true;
1423         if (order.at(1) == 'Y')
1424             mY = true;
1425         if (order.at(1) == 'Z')
1426             mZ = true;
1427     }
1428
1429     // now perform the filtering.
1430     QContactIntersectionFilter resultFilter;
1431     if (sX) {
1432         if (mY && eZ)
1433             resultFilter = *x & *y & *z;
1434         else if (mZ && eY)
1435             resultFilter = *x & *z & *y;
1436         else if (eY)
1437             resultFilter = *x & *y;
1438         else if (eZ)
1439             resultFilter = *x & *z;
1440     } else if (sY) {
1441         if (mX && eZ)
1442             resultFilter = *y & *x & *z;
1443         else if (mZ && eX)
1444             resultFilter = *y & *z & *x;
1445         else if (eX)
1446             resultFilter = *y & *x;
1447         else if (eZ)
1448             resultFilter = *y & *z;
1449     } else if (sZ) {
1450         if (mX && eY)
1451             resultFilter = *z & *x & *y;
1452         else if (mY && eX)
1453             resultFilter = *z & *y & *x;
1454         else if (eX)
1455             resultFilter = *z & *x;
1456         else if (eY)
1457             resultFilter = *z & *y;
1458     }
1459
1460     QList<QContactId> contacts = contactsAddedToManagers.values(cm);
1461     QList<QContactId> ids;
1462
1463     ids = cm->contactIds(resultFilter);
1464
1465     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
1466     QCOMPARE_UNSORTED(output, expected);
1467
1468     delete x;
1469     if (y) delete y;
1470     if (z) delete z;
1471 }
1472
1473 void tst_QContactManagerFiltering::unionFiltering_data()
1474 {
1475     QTest::addColumn<QContactManager *>("cm");
1476     QTest::addColumn<bool>("firstfilter");
1477     QTest::addColumn<int>("fftype"); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1478     QTest::addColumn<QContactDetail::DetailType>("ffdetailtype");
1479     QTest::addColumn<int>("ffdetailfield");
1480     QTest::addColumn<bool>("ffsetvalue");
1481     QTest::addColumn<QVariant>("ffvalue");
1482     QTest::addColumn<QVariant>("ffminrange");
1483     QTest::addColumn<QVariant>("ffmaxrange");
1484     QTest::addColumn<bool>("secondfilter");
1485     QTest::addColumn<int>("sftype");
1486     QTest::addColumn<QContactDetail::DetailType>("sfdetailtype");
1487     QTest::addColumn<int>("sfdetailfield");
1488     QTest::addColumn<bool>("sfsetvalue");
1489     QTest::addColumn<QVariant>("sfvalue");
1490     QTest::addColumn<QVariant>("sfminrange");
1491     QTest::addColumn<QVariant>("sfmaxrange");
1492     QTest::addColumn<QString>("order");
1493     QTest::addColumn<QString>("expected");
1494
1495     QString es; // empty string.
1496
1497     for (int i = 0; i < managers.size(); i++) {
1498         QContactManager *manager = managers.at(i);
1499
1500         // for the following tests, terminology:
1501         // X will be an (empty) union filter created in the test
1502         // Y will be the first filter defined here
1503         // Z will be the second filter defined here
1504
1505         // WITH Y AND Z AS DETAIL FILTERS (with no overlap between Y and Z results)
1506         // For these tests, Y matches "bc" and Z matches "a"
1507         // X || Y - X empty, Y matches "bc" so union = "bc"
1508         QPair<QContactDetail::DetailType, int> integerDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Integer");
1509         QPair<QContactDetail::DetailType, int> booleanDefAndFieldNames = defAndFieldNamesForTypePerManager.value(manager).value("Bool");
1510         if (validDetailField(integerDefAndFieldNames) && validDetailField(booleanDefAndFieldNames)) {
1511             QTest::newRow("A1") << manager
1512                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1513                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1514                                 << "XY" << "bc";
1515             // Y || X - Y matches "bc", X empty so union = "bc"
1516             QTest::newRow("A2") << manager
1517                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1518                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(10) << QVariant() << QVariant()
1519                                 << "YX" << "bc";
1520             // Y || Z  - Y matches "bc" and Z matches "a" - so union = "abc"
1521             QTest::newRow("A3") << manager
1522                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1523                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1524                                 << "YZ" << "abc";
1525             // Z || Y - Y matches "bc" and Z matches "a" - so union = "abc"
1526             QTest::newRow("A4") << manager
1527                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1528                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1529                                 << "ZY" << "abc";
1530             // X || Z - X empty, Z matches "a" so "a"
1531             QTest::newRow("A5") << manager
1532                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << false << QVariant(false) << QVariant() << QVariant()
1533                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1534                                 << "XZ" << "a";
1535             // Z || X - X empty, Z matches "a" so "a"
1536             QTest::newRow("A6") << manager
1537                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << false << QVariant(false) << QVariant() << QVariant()
1538                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1539                                 << "ZX" << "a";
1540             // X || Y || Z - X empty, Y matches "bc", Z matches "a" so "abc"
1541             QTest::newRow("A7") << manager
1542                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1543                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1544                                 << "XYZ" << "abc";
1545             // X || Z || Y - X empty, Y matches "bc", Z matches "a" so "abc"
1546             QTest::newRow("A8") << manager
1547                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1548                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1549                                 << "XZY" << "abc";
1550             // Y || X || Z - X empty, Y matches "bc", Z matches "a" so "abc"
1551             QTest::newRow("A9") << manager
1552                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1553                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1554                                 << "YXZ" << "abc";
1555             // Z || X || Y - X empty, Y matches "bc", Z matches "a" so "abc"
1556             QTest::newRow("A10") << manager
1557                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1558                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1559                                  << "ZXY" << "abc";
1560             // Y || Z || X - X empty, Y matches "bc", Z matches "a" so "abc"
1561             QTest::newRow("A11") << manager
1562                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1563                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1564                                  << "YZX" << "abc";
1565             // Z || Y || X - X empty, Y matches "bc", Z matches "a" so "abc"
1566             QTest::newRow("A12") << manager
1567                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1568                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(10) << QVariant() << QVariant()
1569                                  << "ZYX" << "abc";
1570
1571             // WITH Y AND Z AS DETAIL FILTERS (with some overlap between Y and Z results)
1572             // For these tests, Y matches "bc", Z matches "b"
1573             // X || Y - X empty, Y matches "b", so "bc"
1574             QTest::newRow("B1") << manager
1575                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1576                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1577                                 << "XY" << "bc";
1578             // Y || X - X empty, Y matches "bc", so "bc"
1579             QTest::newRow("B2") << manager
1580                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1581                                 << false << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(20) << QVariant() << QVariant()
1582                                 << "YX" << "bc";
1583             // Y || Z  - X empty, Y matches "bc", Z matches "b" so "bc"
1584             QTest::newRow("B3") << manager
1585                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1586                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1587                                 << "YZ" << "bc";
1588             // Z || Y - X empty, Y matches "bc", Z matches "b" so "bc"
1589             QTest::newRow("B4") << manager
1590                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1591                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1592                                 << "ZY" << "bc";
1593             // X || Z - X empty, Z matches "b" so "b"
1594             QTest::newRow("B5") << manager
1595                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1596                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1597                                 << "XZ" << "b";
1598             // Z || X - X empty, Z matches "b" so "b"
1599             QTest::newRow("B6") << manager
1600                                 << false << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1601                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1602                                 << "ZX" << "b";
1603             // X || Y || Z - X empty, Y matches "bc", Z matches "b" so "bc"
1604             QTest::newRow("B7") << manager
1605                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1606                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1607                                 << "XYZ" << "bc";
1608             // X || Z || Y - X empty, Y matches "bc", Z matches "b" so "bc"
1609             QTest::newRow("B8") << manager
1610                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1611                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1612                                 << "XZY" << "bc";
1613             // Y || X || Z - X empty, Y matches "bc", Z matches "b" so "bc"
1614             QTest::newRow("B9") << manager
1615                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1616                                 << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1617                                 << "YXZ" << "bc";
1618             // Z || X || Y - X empty, Y matches "bc", Z matches "b" so "bc"
1619             QTest::newRow("B10") << manager
1620                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1621                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1622                                  << "ZXY" << "bc";
1623             // Y || Z || X - X empty, Y matches "bc", Z matches "b" so "bc"
1624             QTest::newRow("B11") << manager
1625                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1626                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1627                                  << "YZX" << "bc";
1628             // Z || Y || X - X empty, Y matches "bc", Z matches "b" so "bc"
1629             QTest::newRow("B12") << manager
1630                                 << true << 1 << booleanDefAndFieldNames.first << booleanDefAndFieldNames.second << true << QVariant(false) << QVariant() << QVariant()
1631                                  << true << 1 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << true << QVariant(20) << QVariant() << QVariant()
1632                                  << "ZYX" << "bc";
1633         }
1634
1635         //---------------------------
1636
1637         // WITH Y AND Z AS RANGE FILTERS (with no overlap between Y and Z results)
1638         // For these tests, Y matches "a", Z matches "b"
1639         // X || Y - X empty, Y matches "a" so "a"
1640         if (validDetailField(integerDefAndFieldNames)) {
1641             QTest::newRow("C1") << manager
1642                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1643                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1644                                 << "XY" << "a";
1645             // Y || X - X empty, Y matches "a" so "a"
1646             QTest::newRow("C2") << manager
1647                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1648                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1649                                 << "YX" << "a";
1650             // Y || Z - Y matches "a", Z matches "b" so "ab"
1651             QTest::newRow("C3") << manager
1652                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1653                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1654                                 << "YZ" << "ab";
1655             // Z || Y - Y matches "a", Z matches "b" so "ab"
1656             QTest::newRow("C4") << manager
1657                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1658                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1659                                 << "ZY" << "ab";
1660             // X || Z - X empty, Z matches "b" so "b"
1661             QTest::newRow("C5") << manager
1662                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1663                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1664                                 << "XZ" << "b";
1665             // Z || X - X empty, Z matches "b" so "b"
1666             QTest::newRow("C6") << manager
1667                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1668                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1669                                 << "ZX" << "b";
1670             // X || Y || Z - X empty, Y matches "a", Z matches "b" so "ab"
1671             QTest::newRow("C7") << manager
1672                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1673                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1674                                 << "XYZ" << "ab";
1675             // X || Z || Y - X empty, Y matches "a", Z matches "b" so "ab"
1676             QTest::newRow("C8") << manager
1677                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1678                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1679                                 << "XZY" << "ab";
1680             // Y || X || Z - X empty, Y matches "a", Z matches "b" so "ab"
1681             QTest::newRow("C9") << manager
1682                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1683                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1684                                 << "YXZ" << "ab";
1685             // Z || X || Y - X empty, Y matches "a", Z matches "b" so "ab"
1686             QTest::newRow("C10") << manager
1687                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1688                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1689                                  << "ZXY" << "ab";
1690             // Y || Z || X - X empty, Y matches "a", Z matches "b" so "ab"
1691             QTest::newRow("C11") << manager
1692                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1693                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1694                                  << "YZX" << "ab";
1695             // Z || Y || X - X empty, Y matches "a", Z matches "b" so "ab"
1696             QTest::newRow("C12") << manager
1697                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(15)
1698                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1699                                  << "ZYX" << "ab";
1700
1701             // WITH Y AND Z AS RANGE FILTERS (with some overlap between Y and Z results)
1702             // For these tests, Y matches "ab", Z matches "b"
1703             // X || Y - X empty, Y matches "ab" so "ab"
1704             QTest::newRow("D1") << manager
1705                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1706                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1707                                 << "XY" << "ab";
1708             // Y || X - X empty, Y matches "ab" so "ab"
1709             QTest::newRow("D2") << manager
1710                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1711                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1712                                 << "YX" << "ab";
1713             // Y || Z - Y matches "ab", Z matches "b", union = "ab"
1714             QTest::newRow("D3") << manager
1715                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1716                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1717                                 << "YZ" << "ab";
1718             // Z || Y - Y matches "ab", Z matches "b", union = "ab"
1719             QTest::newRow("D4") << manager
1720                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1721                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1722                                 << "ZY" << "ab";
1723             // X || Z - X empty, Z matches "b" so "b"
1724             QTest::newRow("D5") << manager
1725                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1726                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1727                                 << "XZ" << "b";
1728             // Z || X - X empty, Z matches "b" so "b"
1729             QTest::newRow("D6") << manager
1730                                 << false << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1731                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1732                                 << "ZX" << "b";
1733             // X || Y || Z - X empty, Y matches "ab", Z matches "b" so "ab"
1734             QTest::newRow("D7") << manager
1735                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1736                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1737                                 << "XYZ" << "ab";
1738             // X || Z || Y - X empty, Y matches "ab", Z matches "b" so "ab"
1739             QTest::newRow("D8") << manager
1740                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1741                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1742                                 << "XZY" << "ab";
1743             // Y || X || Z - X empty, Y matches "ab", Z matches "b" so "ab"
1744             QTest::newRow("D9") << manager
1745                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1746                                 << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1747                                 << "YXZ" << "ab";
1748             // Z || X || Y - X empty, Y matches "ab", Z matches "b" so "ab"
1749             QTest::newRow("D10") << manager
1750                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1751                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1752                                  << "ZXY" << "ab";
1753             // Y || Z || X - X empty, Y matches "ab", Z matches "b" so "ab"
1754             QTest::newRow("D11") << manager
1755                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1756                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1757                                  << "YZX" << "ab";
1758             // Z || Y || X - X empty, Y matches "ab", Z matches "b" so "ab"
1759             QTest::newRow("D12") << manager
1760                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(5) << QVariant(25)
1761                                  << true << 2 << integerDefAndFieldNames.first << integerDefAndFieldNames.second << false << QVariant(0) << QVariant(15) << QVariant(25)
1762                                  << "ZYX" << "ab";
1763         }
1764     }
1765 }
1766
1767 void tst_QContactManagerFiltering::unionFiltering()
1768 {
1769     QFETCH(QContactManager*, cm);
1770     QFETCH(bool, firstfilter);
1771     QFETCH(int, fftype); // 1 = detail, 2 = detailrange, 3 = groupmembership, 4 = union, 5 = intersection
1772     QFETCH(QContactDetail::DetailType, ffdetailtype);
1773     QFETCH(int, ffdetailfield);
1774     QFETCH(bool, ffsetvalue);
1775     QFETCH(QVariant, ffvalue);
1776     QFETCH(QVariant, ffminrange);
1777     QFETCH(QVariant, ffmaxrange);
1778     QFETCH(bool, secondfilter);
1779     QFETCH(int, sftype);
1780     QFETCH(QContactDetail::DetailType, sfdetailtype);
1781     QFETCH(int, sfdetailfield);
1782     QFETCH(bool, sfsetvalue);
1783     QFETCH(QVariant, sfvalue);
1784     QFETCH(QVariant, sfminrange);
1785     QFETCH(QVariant, sfmaxrange);
1786     QFETCH(QString, order);
1787     QFETCH(QString, expected);
1788
1789     QContactFilter *x = new QContactUnionFilter();
1790     QContactFilter *y = 0, *z = 0;
1791
1792     if (firstfilter) {
1793         switch (fftype) {
1794             case 1: // detail filter
1795                 y = new QContactDetailFilter();
1796                 static_cast<QContactDetailFilter*>(y)->setDetailType(ffdetailtype, ffdetailfield);
1797                 if (ffsetvalue)
1798                     static_cast<QContactDetailFilter*>(y)->setValue(ffvalue);
1799                 break;
1800             case 2: // range filter
1801                 y = new QContactDetailRangeFilter();
1802                 static_cast<QContactDetailRangeFilter*>(y)->setDetailType(ffdetailtype, ffdetailfield);
1803                 static_cast<QContactDetailRangeFilter*>(y)->setRange(ffminrange, ffmaxrange);
1804                 break;
1805             case 3: // group membership filter
1806             case 4: // union filter
1807             case 5: // intersection filter
1808                 break;
1809
1810             default:
1811                 QVERIFY(false); // force fail.
1812             break;
1813         }
1814     }
1815
1816     if (secondfilter) {
1817         switch (sftype) {
1818             case 1: // detail filter
1819                 z = new QContactDetailFilter();
1820                 static_cast<QContactDetailFilter*>(z)->setDetailType(sfdetailtype, sfdetailfield);
1821                 if (sfsetvalue)
1822                     static_cast<QContactDetailFilter*>(z)->setValue(sfvalue);
1823                 break;
1824             case 2: // range filter
1825                 z = new QContactDetailRangeFilter();
1826                 static_cast<QContactDetailRangeFilter*>(z)->setDetailType(sfdetailtype, sfdetailfield);
1827                 static_cast<QContactDetailRangeFilter*>(z)->setRange(sfminrange, sfmaxrange);
1828                 break;
1829             case 3: // group membership filter
1830             case 4: // union filter
1831             case 5: // intersection filter
1832                 break;
1833
1834             default:
1835                 QVERIFY(false); // force fail.
1836             break;
1837         }
1838     }
1839
1840     // control variables - order: starts, ends, mids
1841     bool sX = false;
1842     bool sY = false;
1843     bool sZ = false;
1844     bool eX = false;
1845     bool eY = false;
1846     bool eZ = false;
1847     bool mX = false;
1848     bool mY = false;
1849     bool mZ = false;
1850
1851     if (order.startsWith("X"))
1852         sX = true;
1853     if (order.startsWith("Y"))
1854         sY = true;
1855     if (order.startsWith("Z"))
1856         sZ = true;
1857     if (order.endsWith("X"))
1858         eX = true;
1859     if (order.endsWith("Y"))
1860         eY = true;
1861     if (order.endsWith("Z"))
1862         eZ = true;
1863     if (order.size() > 2) {
1864         if (order.at(1) == 'X')
1865             mX = true;
1866         if (order.at(1) == 'Y')
1867             mY = true;
1868         if (order.at(1) == 'Z')
1869             mZ = true;
1870     }
1871
1872     // now perform the filtering.
1873     QContactUnionFilter resultFilter;
1874     if (sX) {
1875         if (mY && eZ)
1876             resultFilter = *x | *y | *z;
1877         else if (mZ && eY)
1878             resultFilter = *x | *z | *y;
1879         else if (eY)
1880             resultFilter = *x | *y;
1881         else if (eZ)
1882             resultFilter = *x | *z;
1883     } else if (sY) {
1884         if (mX && eZ)
1885             resultFilter = *y | *x | *z;
1886         else if (mZ && eX)
1887             resultFilter = *y | *z | *x;
1888         else if (eX)
1889             resultFilter = *y | *x;
1890         else if (eZ)
1891             resultFilter = *y | *z;
1892     } else if (sZ) {
1893         if (mX && eY)
1894             resultFilter = *z | *x | *y;
1895         else if (mY && eX)
1896             resultFilter = *z | *y | *x;
1897         else if (eX)
1898             resultFilter = *z | *x;
1899         else if (eY)
1900             resultFilter = *z | *y;
1901     }
1902
1903     QList<QContactId> contacts = contactsAddedToManagers.values(cm);
1904     QList<QContactId> ids;
1905
1906     ids = cm->contactIds(resultFilter);
1907
1908     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
1909     QCOMPARE_UNSORTED(output, expected);
1910
1911     delete x;
1912     if (y) delete y;
1913     if (z) delete z;
1914 }
1915
1916 void tst_QContactManagerFiltering::relationshipFiltering_data()
1917 {
1918     QTest::addColumn<QContactManager *>("cm");
1919     QTest::addColumn<int>("relatedContactRole");
1920     QTest::addColumn<QString>("relationshipType");
1921     QTest::addColumn<char>("relatedContact");
1922     QTest::addColumn<QString>("expected");
1923
1924     const int firstRole(static_cast<int>(QContactRelationship::First));
1925     const int secondRole(static_cast<int>(QContactRelationship::Second));
1926     const int eitherRole(static_cast<int>(QContactRelationship::Either));
1927
1928     for (int i = 0; i < managers.size(); i++) {
1929         QContactManager *manager = managers.at(i);
1930
1931         // HasMember
1932         QTest::newRow("RF-1") << manager << secondRole << QContactRelationship::HasMember() << '\0' << "a";
1933         QTest::newRow("RF-2") << manager << firstRole << QContactRelationship::HasMember() << '\0' << "b";
1934         QTest::newRow("RF-3") << manager << eitherRole << QContactRelationship::HasMember() << '\0' << "ab";
1935
1936         // match any contact that has an assistant
1937         QTest::newRow("RF-4") << manager << secondRole << QContactRelationship::HasAssistant() << '\0' << "a";
1938         // match any contact that is an assistant
1939         QTest::newRow("RF-5") << manager << firstRole << QContactRelationship::HasAssistant() << '\0' << "b";
1940         // match any contact that has an assistant or is an assistant
1941         QTest::newRow("RF-6") << manager << eitherRole << QContactRelationship::HasAssistant() << '\0' << "ab";
1942
1943         // IsSameAs
1944         QTest::newRow("RF-7") << manager << secondRole << QContactRelationship::IsSameAs() << '\0' << "a";
1945         QTest::newRow("RF-8") << manager << firstRole << QContactRelationship::IsSameAs() << '\0' << "b";
1946         QTest::newRow("RF-9") << manager << eitherRole << QContactRelationship::IsSameAs() << '\0' << "ab";
1947
1948         // Aggregates
1949         QTest::newRow("RF-10") << manager << secondRole << QContactRelationship::Aggregates() << '\0' << "a";
1950         QTest::newRow("RF-11") << manager << firstRole << QContactRelationship::Aggregates() << '\0' << "b";
1951         QTest::newRow("RF-12") << manager << eitherRole << QContactRelationship::Aggregates() << '\0' << "ab";
1952
1953         // HasManager
1954         QTest::newRow("RF-13") << manager << secondRole << QContactRelationship::HasManager() << '\0' << "a";
1955         QTest::newRow("RF-14") << manager << firstRole << QContactRelationship::HasManager() << '\0' << "b";
1956         QTest::newRow("RF-15") << manager << eitherRole << QContactRelationship::HasManager() << '\0' << "ab";
1957
1958         // HasSpouse
1959         QTest::newRow("RF-16") << manager << secondRole << QContactRelationship::HasSpouse() << '\0' << "a";
1960         QTest::newRow("RF-17") << manager << firstRole << QContactRelationship::HasSpouse() << '\0' << "b";
1961         QTest::newRow("RF-18") << manager << eitherRole << QContactRelationship::HasSpouse() << '\0' << "ab";
1962
1963         // Unknown relationship
1964         QTest::newRow("RF-19") << manager << secondRole << QStringLiteral("UnknownRelationship") << '\0' << "a";
1965         QTest::newRow("RF-20") << manager << firstRole << QStringLiteral("UnknownRelationship") << '\0' << "b";
1966         QTest::newRow("RF-21") << manager << eitherRole << QStringLiteral("UnknownRelationship") << '\0' << "ab";
1967
1968         // match any contact that is the related contact in a relationship with contact-A
1969         QTest::newRow("RF-22") << manager << secondRole << QString() << 'a' << "";
1970         // match any contact has contact-A as the related contact
1971         QTest::newRow("RF-23") << manager << firstRole << QString() << 'a' << "b";
1972         // match any contact that has any relationship with contact-A
1973         QTest::newRow("RF-24") << manager << eitherRole << QString() << 'a' << "b";
1974
1975         // match any contact that is the related contact in a relationship with contact-B
1976         QTest::newRow("RF-25") << manager << secondRole << QString() << 'b' << "a";
1977         // match any contact has contact-B as the related contact
1978         QTest::newRow("RF-26") << manager << firstRole << QString() << 'b' << "";
1979         // match any contact that has any relationship with contact-B
1980         QTest::newRow("RF-27") << manager << eitherRole << QString() << 'b' << "a";
1981     }
1982 }
1983
1984 QContact tst_QContactManagerFiltering::createContact(QContactManager* cm, QContactType::TypeValues type, const QString &name)
1985 {
1986     QContact contact;
1987     contact.setType(type);
1988     QContactName contactName;
1989     for (int i = QContactName::FieldPrefix; i <= QContactName::FieldSuffix; ++i) {
1990         contactName.setValue(i, name);
1991     }
1992     contact.saveDetail(&contactName);
1993     cm->saveContact(&contact);
1994     return contact;
1995 }
1996
1997 void tst_QContactManagerFiltering::relationshipFiltering()
1998 {
1999     QFETCH(QContactManager*, cm);
2000     QFETCH(int, relatedContactRole);
2001     QFETCH(QString, relationshipType);
2002     QFETCH(char, relatedContact);
2003     QFETCH(QString, expected);
2004
2005     // TODO: A little re-factoring could be used to make the test case more readable
2006
2007     // 1. Create contacts to be used in relationship testing
2008     QContact contactA;
2009     if(relationshipType == QContactRelationship::HasMember()) {
2010         // Change contact type to group as this is required at least by symbian backend
2011         // TODO: should it be possible to query this constraint from the backend?
2012         contactA = createContact(cm, QContactType::TypeGroup, "ContactA");
2013     } else {
2014         contactA = createContact(cm, QContactType::TypeContact, "ContactA");
2015     }
2016     QContact contactB = createContact(cm, QContactType::TypeContact, "ContactB");
2017
2018     // 2. Create the relationship between the contacts
2019     QContact first;
2020     first.setId(contactA.id());
2021     QContact second;
2022     second.setId(contactB.id());
2023
2024     QContactRelationship h2i;
2025     h2i.setFirst(first);
2026     h2i.setSecond(second);
2027     h2i.setRelationshipType(relationshipType);
2028     // save and check error code
2029     bool succeeded = false;
2030     if(cm->isRelationshipTypeSupported(relationshipType, contactA.type())
2031         && cm->isRelationshipTypeSupported(relationshipType, contactB.type())) {
2032         succeeded = true;
2033         QVERIFY(cm->saveRelationship(&h2i));
2034         QCOMPARE(cm->error(), QContactManager::NoError);
2035     } else {
2036         QVERIFY(!cm->saveRelationship(&h2i));
2037         QCOMPARE(cm->error(), QContactManager::NotSupportedError);
2038     }
2039
2040     // 3. Construct the filter
2041     QContactRelationshipFilter crf;
2042     crf.setRelatedContactRole(static_cast<QContactRelationship::Role>(relatedContactRole));
2043     crf.setRelationshipType(relationshipType);
2044     if (relatedContact == 'a') {
2045         crf.setRelatedContact(first);
2046     } else if (relatedContact == 'b') {
2047         crf.setRelatedContact(second);
2048     }
2049
2050     // 4. Grab the filtering results
2051     QList<QContactId> contacts;
2052     contacts.append(contactA.id());
2053     contacts.append(contactB.id());
2054     QList<QContactId> ids = cm->contactIds(crf);
2055     QString output = convertIds(contacts, ids, 'a', 'k'); // don't include the convenience filtering contacts
2056
2057     // Check that a different relationship type does not match
2058     crf.setRelationshipType(QStringLiteral("Some other type"));
2059     QList<QContactId> ids2 = cm->contactIds(crf);
2060
2061     // 5. Remove the created relationship and contacts
2062     if(succeeded) {
2063         // Check that an existing relationship can be removed
2064         QVERIFY(cm->removeRelationship(h2i));
2065         QCOMPARE(cm->error(), QContactManager::NoError);
2066     } else {
2067         // Check that non-existing relationship cannot be removed
2068         QVERIFY(!cm->removeRelationship(h2i));
2069         //TODO: what is the expected error code?
2070         //QCOMPARE(cm->error(), QContactManager::DoesNotExistError);
2071     }
2072     foreach (const QContactId& cid, contacts) {
2073         cm->removeContact(cid);
2074     }
2075
2076     // 6. Verify the filtering result
2077     if(succeeded) {
2078         QCOMPARE_UNSORTED(output, expected);
2079         QCOMPARE(ids2, QList<QContactId>());
2080     } else {