1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34//TESTED_COMPONENT=src/organizer
35
36#include <QtTest/QtTest>
37#include <QtCore/QUuid>
38
39#include <QtOrganizer/qorganizer.h>
40#include <QtOrganizer/qorganizeritemchangeset.h>
41#include "../qorganizermanagerdataholder.h"
42
43#include <QtOrganizer/qorganizernote.h>
44#include <QtOrganizer/qorganizerevent.h>
45
46QTORGANIZER_USE_NAMESPACE
47
48// to get QFETCH to work with the template expression...
49typedef QMap<QString,QString> tst_QOrganizerManager_QStringMap;
50Q_DECLARE_METATYPE(tst_QOrganizerManager_QStringMap)
51Q_DECLARE_METATYPE(QList<QOrganizerItemId>)
52
53/* A class that no backend can support */
54class UnsupportedMetatype {
55 int foo;
56};
57Q_DECLARE_METATYPE(UnsupportedMetatype)
58Q_DECLARE_METATYPE(QOrganizerItem)
59Q_DECLARE_METATYPE(QOrganizerManager::Error)
60Q_DECLARE_METATYPE(QList<QDate>)
61Q_DECLARE_METATYPE(QList<QOrganizerItemDetail::DetailType>);
62
63static inline QOrganizerItemId makeItemId(uint id)
64{
65 return QOrganizerItemId(QStringLiteral("qtorganizer:basic:"), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
66}
67
68static inline QOrganizerCollectionId makeCollectionId(uint id)
69{
70 return QOrganizerCollectionId(QStringLiteral("qtorganizer:basic:"), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
71}
72
73
74class tst_QOrganizerManager : public QObject
75{
76Q_OBJECT
77
78public:
79 tst_QOrganizerManager();
80 virtual ~tst_QOrganizerManager();
81
82private:
83 void dumpOrganizerItemDifferences(const QOrganizerItem& a, const QOrganizerItem& b);
84 void dumpOrganizerItem(const QOrganizerItem &c);
85 void dumpOrganizerItems(QOrganizerManager *cm);
86 bool isSuperset(const QOrganizerItem& ca, const QOrganizerItem& cb);
87 QList<QOrganizerItemDetail> removeAllDefaultDetails(const QList<QOrganizerItemDetail>& details);
88 void addManagers(); // add standard managers to the data
89
90 QScopedPointer<QOrganizerManagerDataHolder> managerDataHolder;
91
92public slots:
93 void initTestCase();
94 void cleanupTestCase();
95private slots:
96
97 void doDump();
98 void doDump_data() {addManagers();}
99
100 /* Special test with special data */
101 void uriParsing();
102 void recurrenceWithGenerator();
103 void todoRecurrenceWithGenerator();
104 void dateRange();
105
106 /* Tests that are run on all managers */
107 void metadata();
108 void nullIdOperations();
109 void add();
110 void saveRecurrence();
111 void persistence();
112 void addExceptions();
113 void modifyRecurrence();
114 void addExceptionsWithGuid();
115 void update();
116 void remove();
117 void batch();
118 void observerDeletion();
119 void signalEmission();
120 void detailOrders();
121 void itemType();
122 void collections();
123 void dataSerialization();
124 void itemFetch();
125 void todoItemFetch();
126 void itemFetchV2();
127 void itemFilterFetch();
128 void spanOverDays();
129 void incompleteTodoTime();
130 void recurrence();
131 void idComparison();
132 void emptyItemManipulation();
133 void partialSave();
134
135 /* Tests that take no data */
136 void errorStayingPut();
137 void ctors();
138 void invalidManager();
139 void memoryManager();
140 void changeSet();
141 void fetchHint();
142 void testFilterFunction();
143 void testReminder();
144 void testIntersectionFilter();
145 void testNestCompoundFilter();
146 void testUnionFilter();
147 void testItemOccurrences();
148
149 /* Special test with special data */
150 void uriParsing_data();
151 void recurrenceWithGenerator_data();
152 void todoRecurrenceWithGenerator_data();
153 void dateRange_data();
154 /* Tests that are run on all managers */
155 void metadata_data() {addManagers();}
156 void nullIdOperations_data() {addManagers();}
157 void add_data() {addManagers();}
158 void saveRecurrence_data() {addManagers();}
159 void persistence_data() {addManagers();}
160 void addExceptions_data() {addManagers();}
161 void addExceptionsWithGuid_data() {addManagers();}
162 void modifyRecurrence_data() {addManagers();}
163 void update_data() {addManagers();}
164 void remove_data() {addManagers();}
165 void batch_data() {addManagers();}
166 void signalEmission_data() {addManagers();}
167 void detailOrders_data() {addManagers();}
168 void itemType_data() {addManagers();}
169 void collections_data() {addManagers();}
170 void dataSerialization_data() {addManagers();}
171 void itemFetch_data() {addManagers();}
172 void todoItemFetch_data() {addManagers();}
173 void itemFetchV2_data() {addManagers();}
174 void itemFilterFetch_data() {addManagers();}
175 void spanOverDays_data() {addManagers();}
176 void incompleteTodoTime_data() {addManagers();}
177 void recurrence_data() {addManagers();}
178 void idComparison_data() {addManagers();}
179 void testReminder_data() {addManagers();}
180 void testIntersectionFilter_data() {addManagers();}
181 void testNestCompoundFilter_data() {addManagers();}
182 void testUnionFilter_data() {addManagers();}
183 void emptyItemManipulation_data() {addManagers();}
184 void partialSave_data() {addManagers();}
185 void testItemOccurrences_data(){addManagers();}
186
187 void testTags_data() { addManagers(); }
188 void testTags();
189
190 void testExtendedDetail_data() { addManagers(); }
191 void testExtendedDetail();
192
193 void testAttendee_data() { addManagers(); }
194 void testAttendee();
195
196 void testRsvp_data() { addManagers(); }
197 void testRsvp();
198
199 void testClassification_data() { addManagers(); }
200 void testClassification();
201
202 void testVersion_data() { addManagers(); }
203 void testVersion();
204};
205
206tst_QOrganizerManager::tst_QOrganizerManager()
207{
208}
209
210tst_QOrganizerManager::~tst_QOrganizerManager()
211{
212}
213
214void tst_QOrganizerManager::initTestCase()
215{
216 managerDataHolder.reset(other: new QOrganizerManagerDataHolder());
217
218 /* Make sure these other test plugins are NOT loaded by default */
219 // These are now removed from the list of managers in addManagers()
220 QVERIFY(!QOrganizerManager::availableManagers().contains("testdummy"));
221 QVERIFY(!QOrganizerManager::availableManagers().contains("teststaticdummy"));
222}
223
224void tst_QOrganizerManager::cleanupTestCase()
225{
226 managerDataHolder.reset(other: 0);
227}
228
229void tst_QOrganizerManager::dumpOrganizerItemDifferences(const QOrganizerItem& ca, const QOrganizerItem& cb)
230{
231 // Try to narrow down the differences
232 QOrganizerItem a(ca);
233 QOrganizerItem b(cb);
234
235 // Check the display label
236 QCOMPARE(a.displayLabel(), b.displayLabel());
237
238 // Now look at the rest
239 QList<QOrganizerItemDetail> aDetails = a.details();
240 QList<QOrganizerItemDetail> bDetails = b.details();
241
242 // They can be in any order, so loop
243 // First remove any matches
244 foreach(QOrganizerItemDetail d, aDetails) {
245 foreach(QOrganizerItemDetail d2, bDetails) {
246 if(d == d2) {
247 a.removeDetail(detail: &d);
248 b.removeDetail(detail: &d2);
249 break;
250 }
251 }
252 }
253
254 // Now dump the extra details that were unmatched in A (note that DisplayLabel and Type are always present).
255 aDetails = a.details();
256 bDetails = b.details();
257 foreach(QOrganizerItemDetail d, aDetails) {
258 if (d.type() != QOrganizerItemDetail::TypeDisplayLabel && d.type() != QOrganizerItemDetail::TypeItemType)
259 qDebug() << "A item had extra detail:" << d.type() << d.values();
260 }
261 // and same for B
262 foreach(QOrganizerItemDetail d, bDetails) {
263 if (d.type() != QOrganizerItemDetail::TypeDisplayLabel && d.type() != QOrganizerItemDetail::TypeItemType)
264 qDebug() << "B item had extra detail:" << d.type() << d.values();
265 }
266
267 // now test specifically the display label and the type
268 if (a.displayLabel() != b.displayLabel()) {
269 qDebug() << "A item display label =" << a.displayLabel();
270 qDebug() << "B item display label =" << b.displayLabel();
271 }
272 if (a.type() != b.type()) {
273 qDebug() << "A item type =" << a.type();
274 qDebug() << "B item type =" << b.type();
275 }
276}
277
278bool tst_QOrganizerManager::isSuperset(const QOrganizerItem& ca, const QOrganizerItem& cb)
279{
280 // returns true if item ca is a superset of item cb
281 // we use this test instead of equality because dynamic information
282 // such as presence/location, and synthesised information such as
283 // display label and (possibly) type, may differ between a item
284 // in memory and the item in the managed store.
285
286 QOrganizerItem a(ca);
287 QOrganizerItem b(cb);
288 QList<QOrganizerItemDetail> aDetails = a.details();
289 QList<QOrganizerItemDetail> bDetails = b.details();
290
291 // They can be in any order, so loop
292 // First remove any matches
293 foreach(QOrganizerItemDetail d, aDetails) {
294 foreach(QOrganizerItemDetail d2, bDetails) {
295 if(d == d2) {
296 a.removeDetail(detail: &d);
297 b.removeDetail(detail: &d2);
298 break;
299 }
300 }
301 }
302
303 // Second remove any superset matches (eg, backend adds a field)
304 aDetails = a.details();
305 bDetails = b.details();
306 foreach (QOrganizerItemDetail d, aDetails) {
307 foreach (QOrganizerItemDetail d2, bDetails) {
308 if (d.type() == d2.type()) {
309 bool canRemove = true;
310 QMap<int, QVariant> d2map = d2.values();
311 foreach (int key, d2map.keys()) {
312 if (d.value(field: key) != d2.value(field: key)) {
313 // d can have _more_ keys than d2,
314 // but not _less_; and it cannot
315 // change the value.
316 canRemove = false;
317 }
318 }
319
320 if (canRemove) {
321 // if we get to here, we can remove the details.
322 a.removeDetail(detail: &d);
323 b.removeDetail(detail: &d2);
324 break;
325 }
326 }
327 }
328 }
329
330 // check for item type updates
331 if (a.type() != QOrganizerItemType::TypeUndefined)
332 if (b.type() != QOrganizerItemType::TypeUndefined)
333 if (a.type() != b.type())
334 return false; // nonempty type is different.
335
336 // Now check to see if b has any details remaining; if so, a is not a superset.
337 // Note that the DisplayLabel and Type can never be removed.
338 if (b.details().size() > 2
339 || (b.details().size() == 2 && (b.details().value(i: 0).type() != QOrganizerItemDetail::TypeDisplayLabel
340 || b.details().value(i: 1).type() != QOrganizerItemDetail::TypeItemType)))
341 return false;
342 return true;
343}
344
345void tst_QOrganizerManager::dumpOrganizerItem(const QOrganizerItem& item)
346{
347 QOrganizerManager m;
348 qDebug() << "OrganizerItem: " << item.id() << "(" << item.displayLabel() << ")";
349 QList<QOrganizerItemDetail> details = item.details();
350 foreach(QOrganizerItemDetail d, details) {
351 qDebug() << " " << d.type() << ":";
352 qDebug() << " Vals:" << d.values();
353 }
354}
355
356void tst_QOrganizerManager::dumpOrganizerItems(QOrganizerManager *cm)
357{
358 QList<QOrganizerItemId> ids = cm->itemIds();
359
360 qDebug() << "There are" << ids.count() << "items in" << cm->managerUri();
361
362 foreach(QOrganizerItemId id, ids) {
363 QOrganizerItem c = cm->item(itemId: id);
364 dumpOrganizerItem(item: c);
365 }
366}
367
368void tst_QOrganizerManager::uriParsing_data()
369{
370 QTest::addColumn<QString>(name: "uri");
371 QTest::addColumn<bool>(name: "good"); // is this a good uri or not
372 QTest::addColumn<QString>(name: "manager");
373 QTest::addColumn<QMap<QString, QString> >(name: "parameters");
374
375 QMap<QString, QString> inparameters;
376 inparameters.insert(akey: "foo", avalue: "bar");
377 inparameters.insert(akey: "bazflag", avalue: QString());
378 inparameters.insert(akey: "bar", avalue: "glob");
379
380 QMap<QString, QString> inparameters2;
381 inparameters2.insert(akey: "this has spaces", avalue: QString());
382 inparameters2.insert(akey: "and& an", avalue: " &amp;");
383 inparameters2.insert(akey: "and an ", avalue: "=quals");
384
385 QTest::newRow(dataTag: "built") << QOrganizerManager::buildUri(managerName: "manager", params: inparameters) << true << "manager" << inparameters;
386 QTest::newRow(dataTag: "built with escaped parameters") << QOrganizerManager::buildUri(managerName: "manager", params: inparameters2) << true << "manager" << inparameters2;
387 QTest::newRow(dataTag: "no scheme") << "this should not split" << false << QString() << tst_QOrganizerManager_QStringMap();
388 QTest::newRow(dataTag: "wrong scheme") << "invalidscheme:foo bar" << false << QString() << tst_QOrganizerManager_QStringMap();
389 QTest::newRow(dataTag: "right scheme, no colon") << "qtorganizer" << false << QString() << tst_QOrganizerManager_QStringMap();
390 QTest::newRow(dataTag: "no manager, colon, no params") << "qtorganizer::" << false << "manager" << tst_QOrganizerManager_QStringMap();
391 QTest::newRow(dataTag: "yes manager, no colon, no params") << "qtorganizer:manager" << true << "manager" << tst_QOrganizerManager_QStringMap();
392 QTest::newRow(dataTag: "yes manager, yes colon, no params") << "qtorganizer:manager:" << true << "manager"<< tst_QOrganizerManager_QStringMap();
393 QTest::newRow(dataTag: "yes params") << "qtorganizer:manager:foo=bar&bazflag=&bar=glob" << true << "manager" << inparameters;
394 QTest::newRow(dataTag: "yes params but misformed") << "qtorganizer:manager:foo=bar&=gloo&bar=glob" << false << "manager" << inparameters;
395 QTest::newRow(dataTag: "yes params but misformed 2") << "qtorganizer:manager:=&=gloo&bar=glob" << false << "manager" << inparameters;
396 QTest::newRow(dataTag: "yes params but misformed 3") << "qtorganizer:manager:==" << false << "manager" << inparameters;
397 QTest::newRow(dataTag: "yes params but misformed 4") << "qtorganizer:manager:&&" << false << "manager" << inparameters;
398 QTest::newRow(dataTag: "yes params but misformed 5") << "qtorganizer:manager:&goo=bar" << false << "manager" << inparameters;
399 QTest::newRow(dataTag: "yes params but misformed 6") << "qtorganizer:manager:goo&bar" << false << "manager" << inparameters;
400 QTest::newRow(dataTag: "yes params but misformed 7") << "qtorganizer:manager:goo&bar&gob" << false << "manager" << inparameters;
401 QTest::newRow(dataTag: "yes params but misformed 8") << "qtorganizer:manager:==&&==&goo=bar" << false << "manager" << inparameters;
402 QTest::newRow(dataTag: "yes params but misformed 9") << "qtorganizer:manager:foo=bar=baz" << false << "manager" << inparameters;
403 QTest::newRow(dataTag: "yes params but misformed 10") << "qtorganizer:manager:foo=bar=baz=glob" << false << "manager" << inparameters;
404 QTest::newRow(dataTag: "no manager but yes params") << "qtorganizer::foo=bar&bazflag=&bar=glob" << false << QString() << inparameters;
405 QTest::newRow(dataTag: "no manager or params") << "qtorganizer::" << false << QString() << inparameters;
406 QTest::newRow(dataTag: "no manager or params or colon") << "qtorganizer:" << false << QString() << inparameters;
407}
408
409void tst_QOrganizerManager::addManagers()
410{
411 QTest::addColumn<QString>(name: "uri");
412
413 QStringList managers = QOrganizerManager::availableManagers();
414
415 /* Known one that will not pass */
416 managers.removeAll(t: "invalid");
417 managers.removeAll(t: "skeleton");
418 managers.removeAll(t: "testdummy");
419 managers.removeAll(t: "teststaticdummy");
420 managers.removeAll(t: "maliciousplugin");
421
422 foreach(QString mgr, managers) {
423 QMap<QString, QString> params;
424 QTest::newRow(dataTag: QString("mgr='%1'").arg(a: mgr).toLatin1().constData()) << QOrganizerManager::buildUri(managerName: mgr, params);
425 if (mgr == "memory") {
426 params.insert(akey: "id", avalue: "tst_QOrganizerManager");
427 QTest::newRow(dataTag: QString("mgr='%1', params").arg(a: mgr).toLatin1().constData()) << QOrganizerManager::buildUri(managerName: mgr, params);
428 }
429 }
430}
431
432void tst_QOrganizerManager::metadata()
433{
434 // ensure that the backend is publishing its metadata (name / parameters / uri) correctly
435 QFETCH(QString, uri);
436 QScopedPointer<QOrganizerManager> cm(new QOrganizerManager("memory"));
437 QVERIFY(QOrganizerManager::buildUri(cm->managerName(), cm->managerParameters()) == cm->managerUri());
438}
439
440
441void tst_QOrganizerManager::nullIdOperations()
442{
443 QFETCH(QString, uri);
444 QScopedPointer<QOrganizerManager> cm(new QOrganizerManager("memory"));
445 QVERIFY(!cm->removeItem(QOrganizerItemId()));
446 QVERIFY(cm->error() == QOrganizerManager::DoesNotExistError);
447
448
449 QOrganizerItem c = cm->item(itemId: QOrganizerItemId());
450 QVERIFY(c.id() == QOrganizerItemId());
451 QVERIFY(c.isEmpty());
452 QVERIFY(cm->error() == QOrganizerManager::DoesNotExistError);
453
454
455 /* TODO: rewrite tests using toString() / fromString()
456 // test that streaming null ids doesn't crash.
457 {
458 QOrganizerItemId nullId;
459 QByteArray buffer;
460 QDataStream outBufferStream(&buffer, QIODevice::WriteOnly);
461 outBufferStream << nullId;
462 QVERIFY(buffer.length() > 0);
463
464 QDataStream inBufferStream(buffer);
465 QOrganizerItemId id;
466 inBufferStream >> id;
467 QVERIFY(id == nullId);
468 }
469
470 {
471 QOrganizerItemId nullid;
472 QByteArray buffer;
473 QDataStream outBufferStream(&buffer, QIODevice::WriteOnly);
474 outBufferStream << nullid;
475 QVERIFY(buffer.length() > 0);
476
477 // cannot stream in local ids; must stream in entire ids.
478 //QDataStream inBufferStream(buffer);
479 //QOrganizerItemId id;
480 //inBufferStream >> id;
481 //QVERIFY(id == nullid);
482 }
483
484 {
485 QOrganizerCollectionId nullId;
486 QByteArray buffer;
487 QDataStream outBufferStream(&buffer, QIODevice::WriteOnly);
488 outBufferStream << nullId;
489 QVERIFY(buffer.length() > 0);
490
491 QDataStream inBufferStream(buffer);
492 QOrganizerCollectionId id;
493 inBufferStream >> id;
494 QVERIFY(id == nullId);
495 }
496
497 {
498 QOrganizerCollectionId nullLocalId;
499 QByteArray buffer;
500 QDataStream outBufferStream(&buffer, QIODevice::WriteOnly);
501 outBufferStream << nullLocalId;
502 QVERIFY(buffer.length() > 0);
503
504 // cannot stream in local ids; must stream in entire ids.
505 //QDataStream inBufferStream(buffer);
506 //QOrganizerCollectionLocalId id;
507 //inBufferStream >> id;
508 //QVERIFY(id == nullLocalId);
509 }
510 */
511}
512
513void tst_QOrganizerManager::uriParsing()
514{
515 QFETCH(QString, uri);
516 QFETCH(bool, good);
517 QFETCH(QString, manager);
518 QFETCH(tst_QOrganizerManager_QStringMap, parameters);
519
520 QString outmanager;
521 QMap<QString, QString> outparameters;
522
523 if (good) {
524 /* Good split */
525 /* Test splitting */
526 QVERIFY(QOrganizerManager::parseUri(uri, 0, 0)); // no out parms
527
528 // 1 out param
529 QVERIFY(QOrganizerManager::parseUri(uri, &outmanager, 0));
530 QCOMPARE(manager, outmanager);
531 QVERIFY(QOrganizerManager::parseUri(uri, 0, &outparameters));
532
533 QCOMPARE(parameters, outparameters);
534
535 outmanager.clear();
536 outparameters.clear();
537 QVERIFY(QOrganizerManager::parseUri(uri, &outmanager, &outparameters));
538
539 QCOMPARE(manager, outmanager);
540 QCOMPARE(parameters, outparameters);
541 } else {
542 /* bad splitting */
543 outmanager.clear();
544 outparameters.clear();
545 QVERIFY(QOrganizerManager::parseUri(uri, 0, 0) == false);
546 QVERIFY(QOrganizerManager::parseUri(uri, &outmanager, 0) == false);
547 QVERIFY(outmanager.isEmpty());
548 QVERIFY(QOrganizerManager::parseUri(uri, 0, &outparameters) == false);
549 QVERIFY(outparameters.isEmpty());
550
551 /* make sure the in parameters don't change with a bad split */
552 outmanager = manager;
553 outparameters = parameters;
554 QVERIFY(QOrganizerManager::parseUri(uri, &outmanager, 0) == false);
555 QCOMPARE(manager, outmanager);
556 QVERIFY(QOrganizerManager::parseUri(uri, 0, &outparameters) == false);
557 QCOMPARE(parameters, outparameters);
558 }
559}
560
561void tst_QOrganizerManager::ctors()
562{
563 /* test the different ctors to make sure we end up with the same uri */
564 QVERIFY(QOrganizerManager::availableManagers().count() >= 1); // invalid, and probably something else
565 QVERIFY(QOrganizerManager::availableManagers().contains("invalid"));
566 QString defaultStore = QOrganizerManager::availableManagers().value(i: 0);
567
568 qDebug() << "Available managers:" << QOrganizerManager::availableManagers();
569
570 QMap<QString, QString> randomParameters;
571 randomParameters.insert(akey: "something", avalue: "old");
572 randomParameters.insert(akey: "something...", avalue: "new");
573 randomParameters.insert(akey: "something ", avalue: "borrowed");
574 randomParameters.insert(akey: " something", avalue: "blue");
575
576 QObject parent;
577
578 QOrganizerManager cm; // default
579 QOrganizerManager cm2(defaultStore);
580 QOrganizerManager cm3(defaultStore, QMap<QString, QString>());
581 //QOrganizerManager cm4(cm.managerUri()); // should fail
582
583 QScopedPointer<QOrganizerManager> cm5(QOrganizerManager::fromUri(uri: QOrganizerManager::buildUri(managerName: defaultStore, params: QMap<QString, QString>())));
584 QScopedPointer<QOrganizerManager> cm6(QOrganizerManager::fromUri(uri: cm.managerUri())); // uri is not a name; should fail.
585 QScopedPointer<QOrganizerManager> cm9(QOrganizerManager::fromUri(uri: QString(), parent: &parent));
586
587 QVERIFY(cm9->parent() == &parent);
588
589 /* OLD TEST WAS THIS: */
590 //QCOMPARE(cm.managerUri(), cm2.managerUri());
591 //QCOMPARE(cm.managerUri(), cm3.managerUri());
592 //QCOMPARE(cm.managerUri(), cm5->managerUri());
593 //QCOMPARE(cm.managerUri(), cm6->managerUri());
594 //QCOMPARE(cm.managerUri(), cm9->managerUri());
595 /* NEW TEST IS THIS: Test that the names of the managers are the same */
596 QCOMPARE(cm.managerName(), cm2.managerName());
597 QCOMPARE(cm.managerName(), cm3.managerName());
598 QCOMPARE(cm.managerName(), cm5->managerName());
599 QCOMPARE(cm.managerName(), cm6->managerName());
600 QCOMPARE(cm.managerName(), cm9->managerName());
601
602 //QVERIFY(cm.managerUri() != cm4.managerUri());
603
604 /* Test that we get invalid stores when we do silly things */
605 QOrganizerManager em("non existent");
606 QOrganizerManager em2("non existent", QMap<QString, QString>());
607 QOrganizerManager em3("memory", randomParameters);
608
609 /* Also invalid, since we don't have one of these anyway */
610 QScopedPointer<QOrganizerManager> em4(QOrganizerManager::fromUri(uri: "invalid uri"));
611 QScopedPointer<QOrganizerManager> em5(QOrganizerManager::fromUri(uri: QOrganizerManager::buildUri(managerName: "nonexistent", params: QMap<QString, QString>())));
612 QScopedPointer<QOrganizerManager> em6(QOrganizerManager::fromUri(uri: em3.managerUri()));
613
614
615 /*
616 * Sets of stores that should be equivalent:
617 * - 1, 2, 4, 5
618 * - 3, 6
619 */
620
621 /* First some URI testing for equivalent stores */
622 QVERIFY(em.managerUri() == em2.managerUri());
623 QVERIFY(em.managerUri() == em5->managerUri());
624 QVERIFY(em.managerUri() == em4->managerUri());
625 QVERIFY(em2.managerUri() == em4->managerUri());
626 QVERIFY(em2.managerUri() == em5->managerUri());
627 QVERIFY(em4->managerUri() == em5->managerUri());
628
629 QVERIFY(em3.managerUri() == em6->managerUri());
630
631 /* Test the stores that should not be the same */
632 QVERIFY(em.managerUri() != em3.managerUri());
633 QVERIFY(em.managerUri() != em6->managerUri());
634
635 /* now the components */
636 QCOMPARE(em.managerName(), QString("invalid"));
637 QCOMPARE(em2.managerName(), QString("invalid"));
638 QCOMPARE(em3.managerName(), QString("memory"));
639 QCOMPARE(em4->managerName(), QString("invalid"));
640 QCOMPARE(em5->managerName(), QString("invalid"));
641 QCOMPARE(em6->managerName(), QString("memory"));
642 QCOMPARE(em.managerParameters(), tst_QOrganizerManager_QStringMap());
643 QCOMPARE(em2.managerParameters(), tst_QOrganizerManager_QStringMap());
644 QCOMPARE(em4->managerParameters(), tst_QOrganizerManager_QStringMap());
645 QCOMPARE(em5->managerParameters(), tst_QOrganizerManager_QStringMap());
646 QCOMPARE(em3.managerParameters(), em6->managerParameters()); // memory engine discards the given params, replaces with id.
647
648
649 // Finally test the platform specific engines are actually the defaults
650 QCOMPARE(defaultStore, QString("invalid"));
651}
652
653void tst_QOrganizerManager::doDump()
654{
655 // Only do this if it has been explicitly selected
656 if (QCoreApplication::arguments().contains(str: "doDump")) {
657 QFETCH(QString, uri);
658 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
659
660 dumpOrganizerItems(cm: cm.data());
661 }
662}
663
664Q_DECLARE_METATYPE(QVariant)
665
666void tst_QOrganizerManager::add()
667{
668 QFETCH(QString, uri);
669 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
670
671 // Use note & todo item depending on backend support
672 QOrganizerItemType::ItemType type;
673 if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeNote))
674 type = QOrganizerItemType::TypeNote;
675 else if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeTodo))
676 type = QOrganizerItemType::TypeTodo;
677 else
678 QSKIP("This manager does not support note or todo item");
679
680 QOrganizerItem item;
681 item.setType(type);
682 item.setDisplayLabel("This is a note");
683 item.setDescription("This note is a particularly notey note");
684 int currCount = cm->itemIds().count();
685 QVERIFY(cm->saveItem(&item));
686 QVERIFY(cm->error() == QOrganizerManager::NoError);
687
688 QVERIFY(!item.id().managerUri().isEmpty());
689 QVERIFY(!item.id().isNull());
690 QCOMPARE(cm->itemIds().count(), currCount+1);
691
692 QOrganizerItem added = cm->item(itemId: item.id());
693 QVERIFY(added.id() == item.id());
694
695 if (!isSuperset(ca: added, cb: item)) {
696 // XXX TODO: fix the isSuperset so that it ignores timestamps.
697 //dumpOrganizerItems(cm.data());
698 //dumpOrganizerItemDifferences(added, note);
699 QCOMPARE(added, item);
700 }
701
702 // now try adding an item that does not exist in the database with non-zero id
703 QOrganizerItem nonexistentItem;
704 nonexistentItem.setType(type);
705 nonexistentItem.setDisplayLabel("Another note.");
706 nonexistentItem.setDescription("This is `another note`'s description");
707 QVERIFY(cm->saveItem(&nonexistentItem)); // should work
708 QVERIFY(cm->removeItem(nonexistentItem.id())); // now nonexistentItem has an id which does not exist
709
710 QVERIFY(!cm->saveItem(&nonexistentItem)); // hence, should fail
711 QCOMPARE(cm->error(), QOrganizerManager::DoesNotExistError);
712 nonexistentItem.setId(QOrganizerItemId());
713 QVERIFY(cm->saveItem(&nonexistentItem)); // after setting id to zero, should save
714 QVERIFY(cm->removeItem(nonexistentItem.id()));
715
716 // now try adding a "megaevent"
717 // - get list of all definitions supported by the manager
718 // - add one detail of each definition to a item
719 // - save the item
720 // - read it back
721 // - ensure that it's the same.
722#if 0 // This test is currently excluded; can it be reinstated?
723 QOrganizerEvent megaevent;
724 QMap<QString, QOrganizerItemDetailDefinition> defmap = cm->detailDefinitions(QOrganizerItemType::TypeEvent);
725 QList<QOrganizerItemDetailDefinition> defs = defmap.values();
726 foreach (const QOrganizerItemDetailDefinition def, defs) {
727
728 // This is probably read-only
729 if (def.name() == QOrganizerItemTimestamp::DefinitionName)
730 continue;
731
732 // otherwise, create a new detail of the given type and save it to the item
733 QOrganizerItemDetail det(def.name());
734 QMap<QString, QOrganizerItemDetailFieldDefinition> fieldmap = def.fields();
735 QStringList fieldKeys = fieldmap.keys();
736 foreach (const QString& fieldKey, fieldKeys) {
737 // get the field, and check to see that it's not constrained.
738 QOrganizerItemDetailFieldDefinition currentField = fieldmap.value(fieldKey);
739
740 // Attempt to create a worthy value
741 if (!currentField.allowableValues().isEmpty()) {
742 // we want to save a value that will be accepted.
743 if (currentField.dataType() == QVariant::StringList)
744 det.setValue(fieldKey, QStringList() << currentField.allowableValues().first().toString());
745 else if (currentField.dataType() == QVariant::List)
746 det.setValue(fieldKey, QVariantList() << currentField.allowableValues().first());
747 else
748 det.setValue(fieldKey, currentField.allowableValues().first());
749 } else {
750 // any value of the correct type will be accepted
751 bool savedSuccessfully = false;
752 QVariant dummyValue = QVariant(fieldKey); // try to get some unique string data
753 if (currentField.dataType() < static_cast<int>(QVariant::UserType)) {
754 QVariant::Type type = static_cast<QVariant::Type>(currentField.dataType());
755 // It is not a user-defined type
756 if (dummyValue.canConvert(type)) {
757 savedSuccessfully = dummyValue.convert(type);
758 if (savedSuccessfully) {
759 // we have successfully created a (supposedly) valid field for this detail.
760 det.setValue(fieldKey, dummyValue);
761 continue;
762 }
763 }
764
765 // nope, couldn't save the string value (test); try a date.
766 dummyValue = QVariant(QDate::currentDate());
767 if (dummyValue.canConvert(type)) {
768 savedSuccessfully = dummyValue.convert(type);
769 if (savedSuccessfully) {
770 // we have successfully created a (supposedly) valid field for this detail.
771 det.setValue(fieldKey, dummyValue);
772 continue;
773 }
774 }
775
776 // nope, couldn't convert a string or a date - try the integer value (42)
777 dummyValue = QVariant(42);
778 if (dummyValue.canConvert(type)) {
779 savedSuccessfully = dummyValue.convert(type);
780 if (savedSuccessfully) {
781 // we have successfully created a (supposedly) valid field for this detail.
782 det.setValue(fieldKey, dummyValue);
783 continue;
784 }
785 }
786 }
787
788 // if we get here, we don't know what sort of value can be saved...
789 }
790 }
791 if (!det.isEmpty())
792 megaevent.saveDetail(&det);
793 }
794
795 QVERIFY(cm->saveItem(&megaevent)); // must be able to save since built from definitions.
796 QOrganizerItem retrievedMegaitem = cm->item(megaevent.id());
797 if (!isSuperset(retrievedMegaitem, megaevent)) {
798 dumpOrganizerItemDifferences(megaevent, retrievedMegaitem);
799 }
800
801 // now a item with many details of a particular definition
802 // if the detail is not unique it should then support minumum of two of the same kind
803 // const int nrOfdetails = 2;
804 // XXX TODO.
805#endif
806}
807
808void tst_QOrganizerManager::saveRecurrence()
809{
810 QFETCH(QString, uri);
811 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
812
813 QOrganizerEvent event;
814 event.setDisplayLabel(QStringLiteral("meeting"));
815 event.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
816 event.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(12, 0, 0)));
817 QOrganizerRecurrenceRule rrule;
818 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
819 rrule.setLimit(QDate(2011, 1, 1));
820 rrule.setInterval(2);
821 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Monday << Qt::Tuesday);
822 rrule.setDaysOfMonth(QSet<int>() << 1 << 2);
823 rrule.setDaysOfYear(QSet<int>() << 1 << 2);
824 rrule.setMonthsOfYear(QSet<QOrganizerRecurrenceRule::Month>()
825 << QOrganizerRecurrenceRule::January
826 << QOrganizerRecurrenceRule::February);
827 rrule.setWeeksOfYear(QSet<int>() << 1 << 2);
828 rrule.setFirstDayOfWeek(Qt::Tuesday);
829
830 //this is disabled because certain backend doesn't support it.
831 //rrule.setPositions(QSet<int>() << 1 << 2);
832
833 event.setRecurrenceRule(rrule);
834 event.setExceptionRule(rrule);
835 QSet<QDate> rdates;
836 rdates << QDate(2010, 1, 4) << QDate(2010, 4, 1);
837 event.setRecurrenceDates(rdates);
838 event.setExceptionDates(rdates);
839
840 QVERIFY(cm->saveItem(&event));
841 QOrganizerEvent savedEvent(cm->item(itemId: event.id()));
842 QCOMPARE(event.recurrenceRule(), savedEvent.recurrenceRule());
843 QCOMPARE(event.exceptionRule(), savedEvent.exceptionRule());
844 QCOMPARE(event.recurrenceDates(), savedEvent.recurrenceDates());
845 QCOMPARE(event.exceptionDates(), savedEvent.exceptionDates());
846}
847
848void tst_QOrganizerManager::persistence()
849{
850 // Test that changes in one manager are visible from another
851 QFETCH(QString, uri);
852 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
853 if (cm->managerName() == "memory")
854 return; // memory engine is not persistent
855
856 cm->removeItems(itemIds: cm->itemIds());
857 QScopedPointer<QOrganizerManager> cm2(QOrganizerManager::fromUri(uri));
858 QCOMPARE(cm->items().size(), 0);
859
860 // Add an event
861 QOrganizerEvent event;
862 event.setDisplayLabel(QStringLiteral("meeting"));
863 event.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
864 event.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(12, 0, 0)));
865 QVERIFY(cm->saveItem(&event));
866 QTest::qWait(ms: 500);
867 QCOMPARE(cm->items().size(), 1);
868 QCOMPARE(cm2->items().size(), 1);
869
870 // Remove the event
871 cm->removeItems(itemIds: cm->itemIds());
872 QTest::qWait(ms: 500);
873 QCOMPARE(cm->items().size(), 0);
874 QCOMPARE(cm2->items().size(), 0);
875
876//#if 0
877 // This is disabled because it'll fail on managers that don't support collections
878
879 // Remove all non-default collections
880 QList<QOrganizerCollection> collections(cm->collections());
881 QOrganizerCollectionId defaultCollectionId(cm->defaultCollectionId());
882 foreach (const QOrganizerCollection &col, collections) {
883 QOrganizerCollectionId id(col.id());
884 if (id != defaultCollectionId)
885 cm->removeCollection(collectionId: id);
886 }
887 QTest::qWait(ms: 500);
888 QCOMPARE(cm2->collections().size(), cm->collections().size());
889
890 QOrganizerCollection collection;
891 collection.setMetaData(key: QOrganizerCollection::KeyName, QStringLiteral("test collection"));
892 QVERIFY(cm->saveCollection(&collection));
893 QTest::qWait(ms: 500);
894 QCOMPARE(cm2->collections().size(), cm->collections().size());
895//#endif
896}
897
898void tst_QOrganizerManager::addExceptions()
899{
900 QFETCH(QString, uri);
901 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
902
903 QOrganizerEvent event;
904 event.setDisplayLabel(QStringLiteral("meeting"));
905 event.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
906 event.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(12, 0, 0)));
907 QOrganizerRecurrenceRule rrule;
908 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
909 rrule.setLimit(3);
910 event.setRecurrenceRule(rrule);
911 QVERIFY(cm->saveItem(&event));
912 QVERIFY(!event.id().isNull());
913 event = cm->item(itemId: event.id());
914 // the guid must be set so when it is exported to iCalendar, the relationship can be represented
915 QVERIFY(!event.guid().isEmpty());
916
917 QList<QOrganizerItem> items =
918 cm->itemOccurrences(parentItem: event, startDateTime: QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)),
919 endDateTime: QDateTime(QDate(2010, 2, 1), QTime(0, 0, 0)));
920 QCOMPARE(items.size(), 3);
921 QOrganizerItem secondItem = items.at(i: 1);
922 QCOMPARE(secondItem.type(), QOrganizerItemType::TypeEventOccurrence);
923 QOrganizerEventOccurrence secondEvent = static_cast<QOrganizerEventOccurrence>(secondItem); // not sure this is the best way...
924 QCOMPARE(secondEvent.startDateTime(), QDateTime(QDate(2010, 1, 8), QTime(11, 0, 0)));
925 QCOMPARE(secondEvent.id(), QOrganizerItemId());
926 QCOMPARE(secondEvent.parentId(), event.id());
927
928 // save a change to an occurrence's detail (ie. create an exception)
929 secondEvent.setDisplayLabel(QStringLiteral("seminar"));
930 QVERIFY(cm->saveItem(&secondEvent));
931 event = cm->item(itemId: event.id()); // reload the event to pick up any changed exception dates.
932 items = cm->itemOccurrences(parentItem: event, startDateTime: QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)),
933 endDateTime: QDateTime(QDate(2010, 2, 1), QTime(0, 0, 0)));
934 QCOMPARE(items.size(), 3); // shouldn't change the count.
935
936 // save a change to an occurrence's time
937 QOrganizerEventOccurrence thirdEvent = static_cast<QOrganizerEventOccurrence>(items.at(i: 2));
938 QCOMPARE(thirdEvent.id(), QOrganizerItemId());
939 QCOMPARE(thirdEvent.parentId(), event.id());
940 thirdEvent.setStartDateTime(QDateTime(QDate(2010, 1, 15), QTime(13, 0, 0)));
941 thirdEvent.setEndDateTime(QDateTime(QDate(2010, 1, 15), QTime(14, 0, 0)));
942 QVERIFY(cm->saveItem(&thirdEvent));
943 event = cm->item(itemId: event.id()); // reload the event to pick up any changed exception dates.
944 items = cm->itemOccurrences(parentItem: event, startDateTime: QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)),
945 endDateTime: QDateTime(QDate(2010, 2, 1), QTime(0, 0, 0)));
946 QCOMPARE(items.size(), 3); // shouldn't change the count.
947
948 QOrganizerItem firstItem;
949 bool foundFirst = false;
950 bool foundSecond = false;
951 bool foundThird = false;
952 foreach (const QOrganizerItem& item, items) {
953 if (item.id().isNull()) {
954 foundFirst = true;
955 firstItem = item;
956 }
957
958 if (item.id() == secondEvent.id()) {
959 foundSecond = true;
960 secondEvent = item;
961 }
962
963 if (item.id() == thirdEvent.id()) {
964 foundThird = true;
965 thirdEvent = item;
966 }
967 }
968
969 // check that saving an exception doesn't change other items
970 QVERIFY(foundFirst); // there should still be one "generated" occurrence
971 QCOMPARE(firstItem.displayLabel(), QStringLiteral("meeting")); // and it should have the original label.
972 // item occurrences which are not exceptions should have zero id
973 QVERIFY(firstItem.id().isNull());
974
975 // the exception's changes have been persisted
976 QVERIFY(foundSecond);
977 QCOMPARE(secondEvent.displayLabel(), QStringLiteral("seminar"));
978 // item occurrences which are persisted exceptions should have non-zero id
979 QVERIFY(!secondEvent.id().isNull());
980
981 QVERIFY(foundThird);
982 QCOMPARE(thirdEvent.startDateTime(), QDateTime(QDate(2010, 1, 15), QTime(13, 0, 0)));
983 QCOMPARE(thirdEvent.endDateTime(), QDateTime(QDate(2010, 1, 15), QTime(14, 0, 0)));
984 QVERIFY(!thirdEvent.id().isNull());
985
986 // remove persisted exception, it should not modify parent item's exception dates
987 cm->removeItem(itemId: secondEvent.id());
988 event = cm->item(itemId: event.id()); // reload the event to pick up any changed exception dates.
989 items = cm->itemOccurrences(parentItem: event, startDateTime: QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)),
990 endDateTime: QDateTime(QDate(2010, 2, 1), QTime(0, 0, 0)));
991 QCOMPARE(items.size(), 2); // shouldn't change the count.
992
993 // remove the parent item, persisted exceptions should be removed also
994
995 cm->removeItem(itemId: event.id());
996 QVERIFY(cm->item(thirdEvent.id()).isEmpty());
997
998}
999
1000void tst_QOrganizerManager::modifyRecurrence()
1001{
1002 QFETCH(QString, uri);
1003 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
1004
1005 QOrganizerEvent event;
1006 event.setDisplayLabel(QStringLiteral("recurring meeting"));
1007 event.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
1008 event.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(12, 0, 0)));
1009 QOrganizerRecurrenceRule rrule;
1010 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
1011 rrule.setLimit(QDate(2014, 1, 1));
1012 event.setRecurrenceRule(rrule);
1013 QVERIFY(cm->saveItem(&event));
1014 QVERIFY(!event.id().isNull());
1015 event = cm->item(itemId: event.id());
1016 // the guid must be set so when it is exported to iCalendar, the relationship can be represented
1017 QVERIFY(!event.guid().isEmpty());
1018 QList<QOrganizerItem> items = cm->itemOccurrences(parentItem: event);
1019 QCOMPARE(items.size(), 5);
1020 QOrganizerItem secondItem = items.at(i: 1);
1021 QCOMPARE(secondItem.type(), QOrganizerItemType::TypeEventOccurrence);
1022 QOrganizerEventOccurrence secondEvent = static_cast<QOrganizerEventOccurrence>(secondItem); // not sure this is the best way...
1023 QCOMPARE(secondEvent.startDateTime(), QDateTime(QDate(2011, 1, 1), QTime(11, 0, 0)));
1024 QCOMPARE(secondEvent.id(), QOrganizerItemId());
1025 QCOMPARE(secondEvent.parentId(), event.id());
1026
1027 // save a change to an occurrence's detail (ie. create an exception)
1028 secondEvent.setDisplayLabel(QStringLiteral("exceptional display label"));
1029 QVERIFY(cm->saveItem(&secondEvent));
1030 event = cm->item(itemId: event.id()); // reload the event to pick up any changed exception dates.
1031 items = cm->itemOccurrences(parentItem: event);
1032 QCOMPARE(items.size(), 5); // shouldn't change the count.
1033
1034 // save a change to an occurrence's time
1035 QOrganizerEventOccurrence thirdEvent = static_cast<QOrganizerEventOccurrence>(items.at(i: 2));
1036 QCOMPARE(thirdEvent.id(), QOrganizerItemId());
1037 QCOMPARE(thirdEvent.parentId(), event.id());
1038 thirdEvent.setStartDateTime(QDateTime(QDate(2012, 1, 2), QTime(15, 0, 0)));
1039 thirdEvent.setEndDateTime(QDateTime(QDate(2012, 1, 2), QTime(16, 0, 0)));
1040 QVERIFY(cm->saveItem(&thirdEvent));
1041 event = cm->item(itemId: event.id()); // reload the event to pick up any changed exception dates.
1042 items = cm->itemOccurrences(parentItem: event);
1043 QCOMPARE(items.size(), 5); // shouldn't change the count.
1044
1045 QCOMPARE(items[0].id(), QOrganizerItemId());
1046 QCOMPARE(items[1].id(), secondEvent.id());
1047 QCOMPARE(items[2].id(), thirdEvent.id());
1048 QCOMPARE(items[3].id(), QOrganizerItemId());
1049 QCOMPARE(items[4].id(), QOrganizerItemId());
1050
1051 // modify recurrence rule
1052 rrule.setLimit(QDate(2011, 1, 1));
1053 event.setRecurrenceRule(rrule);
1054 QVERIFY(cm->saveItem(&event));
1055 items = cm->itemOccurrences(parentItem: event);
1056 QCOMPARE(items.size(), 2); // only one generated and one exception should be left
1057
1058 // use different function to fetch events
1059 items = cm->items();
1060 QCOMPARE(items.size(), 2); // only one generated and one exception should be left
1061}
1062
1063
1064/*test ItemOccurrences function maxCount parameters*/
1065void tst_QOrganizerManager::testItemOccurrences()
1066{
1067 //Get the uri value
1068 QFETCH (QString, uri);
1069 //Create the QOrganizerManager
1070 QScopedPointer<QOrganizerManager> cm (QOrganizerManager::fromUri (uri));
1071
1072 //Create the weekly recurrence event data that is used by the test
1073 QOrganizerEvent event;
1074 event.setDisplayLabel (QStringLiteral ("meeting"));
1075 event.setStartDateTime (QDateTime (QDate (2010, 1, 1), QTime (11, 0, 0)));
1076 event.setEndDateTime (QDateTime (QDate (2010, 1, 1), QTime (12, 0, 0)));
1077
1078 //Create weekly recurrence rule and count limit is 3
1079 QOrganizerRecurrenceRule rrule;
1080 rrule.setFrequency (QOrganizerRecurrenceRule::Weekly);
1081 rrule.setLimit (3);
1082 event.setRecurrenceRule (rrule);
1083
1084 //Save the event
1085 QVERIFY (cm->saveItem (&event));
1086
1087 //Varify the event data guid
1088 QVERIFY (!event.id().isNull ());
1089 event = cm->item (itemId: event.id ());
1090 //The guid(Globally unique identifier) must be set so when it is exported to iCalendar, the relationship can be represented
1091 QVERIFY (!event.guid().isEmpty ());
1092
1093 //Use default parameter value to fetch
1094 QList<QOrganizerItem> items = cm->itemOccurrences(
1095 parentItem: event, //parantItem
1096 startDateTime: QDateTime (QDate (2010, 1, 1), QTime (0, 0, 0)), //start date
1097 endDateTime: QDateTime (QDate (2010, 2, 1), QTime (0, 0, 0)) //end date
1098 );
1099 //The result should be same as rrule's limitation 3
1100 QCOMPARE(items.size(), 3);
1101
1102 //Assign maxCount negative value to get same result as default value
1103 QList<QOrganizerItem> items2 = cm->itemOccurrences(
1104 parentItem: event, //parantItem
1105 startDateTime: QDateTime (QDate (2010, 1, 1), QTime (0, 0, 0)), //start date
1106 endDateTime: QDateTime (QDate (2010, 2, 1), QTime (0, 0, 0)), //end date
1107 maxCount: -5 //maxCount
1108 );
1109 //The result should be same as rrule's limitation
1110 QCOMPARE(items2.size(), 3);
1111
1112 //Assign maxCount bigger value to get same result as default value
1113 QList<QOrganizerItem> items3 = cm->itemOccurrences(
1114 parentItem: event,
1115 startDateTime: QDateTime (QDate (2010, 1, 1), QTime (0, 0, 0)),
1116 endDateTime: QDateTime (QDate (2010, 2, 1), QTime (0, 0, 0)),
1117 maxCount: 4
1118 );
1119 //The result should be same as rrule's limitation since the maxCount is bigger than the actually data
1120 QCOMPARE(items3.size(), 3);
1121
1122/*------------------------------------------------------------------------
1123 Create 2nd Daily event data, now We have Weekly and Daily 2 different events and make the situation more complex.
1124 maxCount is also smaller than the actual item data.
1125*/
1126 //Create 2nd Daily event data and limitation is 20
1127 QOrganizerEvent event2;
1128 event2.setDisplayLabel (QStringLiteral ("meeting2"));
1129 event2.setStartDateTime (QDateTime (QDate (2010, 1, 1), QTime (11, 0, 0)));
1130 event2.setEndDateTime (QDateTime (QDate (2010, 1, 1), QTime (12, 0, 0)));
1131 rrule.setFrequency (QOrganizerRecurrenceRule::Daily);
1132 rrule.setLimit (20);
1133 event2.setRecurrenceRule (rrule);
1134 QVERIFY (cm->saveItem (&event2));
1135 event2 = cm->item (itemId: event2.id ());
1136 // The guid must be set so when it is exported to iCalendar, the relationship can be represented
1137 QVERIFY (!event2.guid().isEmpty ());
1138
1139 //Use default maxCount parameter value to fetch
1140 QList<QOrganizerItem> items4 = cm->itemOccurrences(
1141 parentItem: event2,
1142 startDateTime: QDateTime (QDate (2010, 1, 1), QTime (0, 0, 0)),
1143 endDateTime: QDateTime (QDate (2010, 2, 1), QTime (0, 0, 0))
1144 );
1145
1146 //The result should be same as rrule's limitation 20
1147 QCOMPARE (items4.size (), 20);
1148
1149 //Normal daily event items fetch with 5 max count limitation
1150 QList<QOrganizerItem> items5 = cm->itemOccurrences(
1151 parentItem: event2,
1152 startDateTime: QDateTime (QDate (2010, 1, 1), QTime (0, 0, 0)),
1153 endDateTime: QDateTime (QDate (2010, 2, 1), QTime (0, 0, 0)),
1154 maxCount: 5
1155 );
1156 //The result should be same as maxCount 5 which is smaller than event rrule's limitation 20
1157 QCOMPARE (items5.size (), 5);
1158
1159 //Normal daily event items fetch with 0 max count limitation
1160 QList<QOrganizerItem> items6 = cm->itemOccurrences(
1161 parentItem: event2,
1162 startDateTime: QDateTime (QDate (2010, 1, 1), QTime (0, 0, 0)),
1163 endDateTime: QDateTime (QDate (2010, 2, 1), QTime (0, 0, 0)),
1164 maxCount: 0
1165 );
1166 //The result should be 0
1167 QCOMPARE (items6.size (), 0);
1168}
1169
1170void tst_QOrganizerManager::addExceptionsWithGuid()
1171{
1172 // It should be possible to save an exception that has at least an originalDate and either a
1173 // guid or a parentId. If guid and parentId are both specified, the client should
1174 // ensure they are consistent and the manager should fail if they are not. If only one of the
1175 // guid or parentId are specified, the manager should generate the other one.
1176 // This test case tests all of this.
1177 QFETCH(QString, uri);
1178 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
1179
1180 // Set up some recurring items
1181 QOrganizerEvent christmas;
1182 christmas.setGuid("christmas");
1183 christmas.setStartDateTime(QDateTime(QDate(2009, 12, 25), QTime(0, 0, 0)));
1184 christmas.setEndDateTime(QDateTime(QDate(2009, 12, 26), QTime(0, 0, 0)));
1185 christmas.setDisplayLabel(QStringLiteral("Christmas"));
1186 QOrganizerRecurrenceRule rrule;
1187 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
1188 christmas.setRecurrenceRule(rrule);
1189 QVERIFY(cm->saveItem(&christmas));
1190 QVERIFY(!christmas.id().managerUri().isEmpty());
1191 QVERIFY(!christmas.id().isNull());
1192
1193 QOrganizerEvent newYearsDay;
1194 newYearsDay.setGuid("newyear");
1195 newYearsDay.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)));
1196 newYearsDay.setEndDateTime(QDateTime(QDate(2010, 1, 2), QTime(0, 0, 0)));
1197 newYearsDay.setDisplayLabel(QStringLiteral("New Years Day"));
1198 newYearsDay.setRecurrenceRule(rrule);
1199 QVERIFY(cm->saveItem(&newYearsDay));
1200
1201 QOrganizerTodo report;
1202 report.setGuid("report");
1203 report.setDueDateTime(QDateTime(QDate(2010, 1, 11), QTime(0, 0, 0)));
1204 report.setDisplayLabel(QStringLiteral("Report"));
1205 QVERIFY(cm->saveItem(&report));
1206
1207 // The tests:
1208 // exception with no guid or parentId fails
1209 QOrganizerEventOccurrence exception;
1210 exception.setOriginalDate(QDate(2010, 12, 25));
1211 exception.setStartDateTime(QDateTime(QDate(2010, 12, 25), QTime(0, 0, 0)));
1212 exception.setEndDateTime(QDateTime(QDate(2010, 12, 26), QTime(0, 0, 0)));
1213 exception.setDisplayLabel(QStringLiteral("Xmas"));
1214// if (cm->detailDefinitions(QOrganizerItemType::TypeEventOccurrence).contains(QOrganizerItemComment::DefinitionName))
1215// exception.addComment(QLatin1String("With the in-laws"));
1216 QVERIFY(!cm->saveItem(&exception));
1217 QCOMPARE(cm->error(), QOrganizerManager::InvalidOccurrenceError);
1218
1219 // exception with invalid guid fails
1220 exception.setId(QOrganizerItemId());
1221 exception.setGuid(QStringLiteral("halloween"));
1222 QVERIFY(!cm->saveItem(&exception));
1223 QCOMPARE(cm->error(), QOrganizerManager::InvalidOccurrenceError);
1224
1225 // with the guid set, it should work
1226 exception.setId(QOrganizerItemId());
1227 exception.setGuid(QStringLiteral("christmas"));
1228 QVERIFY(cm->saveItem(&exception));
1229 QVERIFY(!exception.id().isNull());
1230 QOrganizerEventOccurrence savedException = cm->item(itemId: exception.id());
1231 QCOMPARE(savedException.parentId(), christmas.id()); // parentId should be set by manager
1232
1233 // with the id, guid and the parentId all set and consistent, it should work
1234 exception = savedException;
1235 QVERIFY(cm->saveItem(&exception));
1236 savedException = cm->item(itemId: exception.id());
1237 QCOMPARE(savedException.parentId(), christmas.id());
1238
1239 // Make a fresh exception object on a fresh date to avoid clashing with the previously saved one
1240 // can't set parentId to a non-event
1241 QOrganizerEventOccurrence exception2;
1242 exception2.setOriginalDate(QDate(2011, 12, 25));
1243 exception2.setStartDateTime(QDateTime(QDate(2011, 12, 25), QTime(0, 0, 0)));
1244 exception2.setEndDateTime(QDateTime(QDate(2011, 12, 26), QTime(0, 0, 0)));
1245 exception2.setDisplayLabel(QStringLiteral("XMas"));
1246// if (cm->detailDefinitions(QOrganizerItemType::TypeEventOccurrence).contains(QOrganizerItemComment::DefinitionName))
1247// exception2.addComment(QLatin1String("With the in-laws"));
1248 exception2.setParentId(report.id()); // report is not an event
1249 QVERIFY(!cm->saveItem(&exception2));
1250 QCOMPARE(cm->error(), QOrganizerManager::InvalidOccurrenceError);
1251
1252 // can't set guid to a non-event
1253 exception2.setGuid(QStringLiteral("report"));
1254 exception2.setParentId(QOrganizerItemId());
1255 QVERIFY(!cm->saveItem(&exception2));
1256 QCOMPARE(cm->error(), QOrganizerManager::InvalidOccurrenceError);
1257
1258 // can't make the guid inconsistent with the parentId
1259 exception2.setParentId(christmas.id());
1260 exception2.setGuid(QStringLiteral("newyear"));
1261 QVERIFY(!cm->saveItem(&exception2));
1262 QCOMPARE(cm->error(), QOrganizerManager::InvalidOccurrenceError);
1263
1264 // with just the parentId set to a valid parent, it should work
1265 exception2.setGuid(QStringLiteral(""));
1266 QVERIFY(cm->saveItem(&exception2));
1267 savedException = cm->item(itemId: exception2.id());
1268 QCOMPARE(savedException.parentId(), christmas.id());
1269 QCOMPARE(savedException.guid(), QStringLiteral("christmas")); // guid should be set by manager
1270
1271 // Make a fresh exception object on a fresh date to avoid clashing with the previously saved one
1272 // exception without originalDate fails
1273 QOrganizerEventOccurrence exception3;
1274 exception3.setStartDateTime(QDateTime(QDate(2012, 12, 25), QTime(0, 0, 0)));
1275 exception3.setEndDateTime(QDateTime(QDate(2012, 12, 26), QTime(0, 0, 0)));
1276 exception3.setDisplayLabel(QStringLiteral("XMas"));
1277// if (cm->detailDefinitions(QOrganizerItemType::TypeEventOccurrence).contains(QOrganizerItemComment::DefinitionName))
1278// exception3.addComment(QLatin1String("With the in-laws"));
1279 exception3.setParentId(christmas.id());
1280 exception3.setGuid(QStringLiteral("christmas"));
1281 QVERIFY(!cm->saveItem(&exception3));
1282 QCOMPARE(cm->error(), QOrganizerManager::InvalidOccurrenceError);
1283
1284 // with original date, guid and parentId set and consistent, and id=0, it should work
1285 exception3.setOriginalDate(QDate(2012, 12, 25));
1286 QVERIFY(cm->saveItem(&exception3));
1287 QVERIFY(!exception3.id().isNull());
1288 savedException = cm->item(itemId: exception3.id());
1289 QCOMPARE(savedException.parentId(), christmas.id());
1290}
1291
1292void tst_QOrganizerManager::update()
1293{
1294 QFETCH(QString, uri);
1295 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
1296
1297 // Use note & todo item depending on backend support
1298 QOrganizerItemType::ItemType type;
1299 if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeNote))
1300 type = QOrganizerItemType::TypeNote;
1301 else if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeTodo))
1302 type = QOrganizerItemType::TypeTodo;
1303 else
1304 QSKIP("This manager does not support note or todo item");
1305
1306 // Save a new item first
1307 QOrganizerItem item;
1308 item.setType(type);
1309 item.setDisplayLabel("Yet another note");
1310 item.setDescription("Surprisingly, this note is not a particularly notey note");
1311 QVERIFY(cm->saveItem(&item));
1312 QVERIFY(cm->error() == QOrganizerManager::NoError);
1313
1314 // Update name
1315 QOrganizerItemDescription descr = item.detail(detailType: QOrganizerItemDetail::TypeDescription);
1316 descr.setDescription("This note is now slightly noteworthy");
1317 item.saveDetail(detail: &descr);
1318 QVERIFY(cm->saveItem(&item));
1319 QVERIFY(cm->error() == QOrganizerManager::NoError);
1320 descr.setDescription("This is a very noteworthy note");
1321 item.saveDetail(detail: &descr);
1322 QVERIFY(cm->saveItem(&item));
1323 QVERIFY(cm->error() == QOrganizerManager::NoError);
1324 QOrganizerItem updated = cm->item(itemId: item.id());
1325 QOrganizerItemDescription updatedDescr = updated.detail(detailType: QOrganizerItemDetail::TypeDescription);
1326 QCOMPARE(updatedDescr, descr);
1327
1328 /* Create a recurring event, update an occurrence and save (should persist as an exceptional occurrence) */
1329 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
1330 QOrganizerEvent recEvent;
1331 recEvent.setDescription("a recurring event");
1332 recEvent.setStartDateTime(QDateTime(QDate(2010, 10, 20), QTime(8, 0, 0)));
1333 recEvent.setEndDateTime(QDateTime(QDate(2010, 10, 20), QTime(10, 0, 0)));
1334 QOrganizerRecurrenceRule rrule;
1335 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
1336 rrule.setLimit(3);
1337 recEvent.setRecurrenceRule(rrule);
1338 QVERIFY(cm->saveItem(&recEvent));
1339 int persistentCount = cm->itemsForExport().size();
1340 QCOMPARE(persistentCount, 1); // just the parent
1341 QList<QOrganizerItem> items = cm->items();
1342 QCOMPARE(items.size(), 3);
1343 bool foundException = false;
1344 QOrganizerEventOccurrence exception;
1345 foreach (const QOrganizerEventOccurrence& curr, items) {
1346 if (curr.startDateTime() == QDateTime(QDate(2010, 10, 21), QTime(8, 0, 0))) {
1347 exception = curr;
1348 foundException = true;
1349 break;
1350 }
1351 }
1352 QVERIFY(foundException);
1353 exception.setDescription("different description");
1354 QVERIFY(cm->saveItem(&exception));
1355 persistentCount = cm->itemsForExport().size();
1356 QCOMPARE(persistentCount, 2); // parent plus one exception
1357 items = cm->items();
1358 QCOMPARE(items.size(), 3);
1359 foreach (const QOrganizerEventOccurrence& curr, items) {
1360 if (curr.startDateTime() == QDateTime(QDate(2010, 10, 21), QTime(8, 0, 0))) {
1361 QVERIFY(!curr.id().isNull());
1362 QCOMPARE(curr.description(), QStringLiteral("different description"));
1363 } else {
1364 QVERIFY(curr.id().isNull());
1365 }
1366 }
1367
1368 /* Save a non-updated occurrence - should still persist as an exceptional occurrence */
1369 QOrganizerEventOccurrence secondException;
1370 foreach (const QOrganizerEventOccurrence& curr, items) {
1371 if (curr.startDateTime() == QDateTime(QDate(2010, 10, 22), QTime(8, 0, 0))) {
1372 secondException = curr;
1373 foundException = true;
1374 break;
1375 }
1376 }
1377 QVERIFY(foundException);
1378 QVERIFY(cm->saveItem(&secondException)); // no changes, but should save as an exception anyway.
1379 persistentCount = cm->itemsForExport().size();
1380 QCOMPARE(persistentCount, 3); // parent plus two exceptions
1381 items = cm->items();
1382 QCOMPARE(items.size(), 3);
1383 foreach (const QOrganizerEventOccurrence& curr, items) {
1384 if (curr.startDateTime() == QDateTime(QDate(2010, 10, 20), QTime(8, 0, 0))) {
1385 QVERIFY(curr.id().isNull()); // only the first occurrence is not an exception.
1386 } else {
1387 QVERIFY(!curr.id().isNull()); // we have two exceptions this time
1388 }
1389 }
1390}
1391
1392void tst_QOrganizerManager::remove()
1393{
1394 QFETCH(QString, uri);
1395 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
1396 // for fetch results
1397 QList<QOrganizerItem> items;
1398 // for removeItems request
1399 QList<QOrganizerItem> itemList;
1400
1401 // Use note & todo item depending on backend support
1402 QOrganizerItemType::ItemType type;
1403 if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeNote))
1404 type = QOrganizerItemType::TypeNote;
1405 else if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeTodo))
1406 type = QOrganizerItemType::TypeTodo;
1407 else
1408 QSKIP("This manager does not support note or todo item");
1409
1410 // Save a new item first
1411 QOrganizerItem item;
1412 item.setType(type);
1413 item.setDisplayLabel("Not another note");
1414 item.setDescription("Yes, another note!");
1415 QVERIFY(cm->saveItem(&item));
1416 QVERIFY(cm->error() == QOrganizerManager::NoError);
1417 QVERIFY(item.id() != QOrganizerItemId());
1418
1419 // Remove the created item
1420 const int itemCount = cm->itemIds().count();
1421 QVERIFY(cm->removeItem(item.id()));
1422 QCOMPARE(cm->itemIds().count(), itemCount - 1);
1423 QVERIFY(cm->item(item.id()).isEmpty());
1424 QCOMPARE(cm->error(), QOrganizerManager::DoesNotExistError);
1425
1426 //delete item not exist
1427 QVERIFY(!cm->removeItem(item.id()));
1428 QCOMPARE(cm->error(), QOrganizerManager::DoesNotExistError);
1429
1430 //delete item id is empty
1431 QOrganizerItemId id;
1432 QVERIFY(!cm->removeItem(id));
1433 QCOMPARE(cm->error(), QOrganizerManager::DoesNotExistError);
1434
1435 // delete an event by item (not id)
1436 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
1437 QCOMPARE(cm->items().size(), 0);
1438 QOrganizerEvent event1;
1439 event1.setDisplayLabel("first event");
1440 QOrganizerEvent event2;
1441 event1.setDisplayLabel("second event");
1442 QOrganizerEvent event3;
1443 event1.setDisplayLabel("third event");
1444 itemList << event1 << event2 << event3;
1445 QVERIFY(cm->saveItems(&itemList));
1446 QVERIFY(cm->error() == QOrganizerManager::NoError);
1447 items = cm->items();
1448 QCOMPARE(cm->items().size(), 3);
1449 QVERIFY(cm->removeItem(&(items[2])));
1450 items = cm->items();
1451 QCOMPARE(cm->items().size(), 2);
1452 QVERIFY(cm->removeItems(&items));
1453 items = cm->items();
1454 QCOMPARE(cm->items().size(), 0);
1455
1456 /* Create a recurring event, save an exception, remove the recurring event should remove all children occurrences incl. persisted exceptions. */
1457 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
1458 QOrganizerEvent recEvent;
1459 recEvent.setDescription("a recurring event");
1460 recEvent.setStartDateTime(QDateTime(QDate(2010, 10, 20), QTime(8, 0, 0)));
1461 recEvent.setEndDateTime(QDateTime(QDate(2010, 10, 20), QTime(10, 0, 0)));
1462 QOrganizerRecurrenceRule rrule;
1463 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
1464 rrule.setLimit(3);
1465 recEvent.setRecurrenceRule(rrule);
1466 QVERIFY(cm->saveItem(&recEvent));
1467 items = cm->items();
1468 QCOMPARE(items.size(), 3);
1469 QOrganizerEventOccurrence exception = items.at(i: 1);
1470 exception.setStartDateTime(QDateTime(QDate(2010, 10, 21), QTime(7, 0, 0)));
1471 QVERIFY(cm->saveItem(&exception));
1472 items = cm->items();
1473 QCOMPARE(items.size(), 3);
1474 QCOMPARE(cm->itemsForExport().size(), 2);
1475 QVERIFY(cm->removeItem(recEvent.id()));
1476 QCOMPARE(cm->itemsForExport().size(), 0);
1477 QCOMPARE(cm->items().size(), 0);
1478
1479 /* Create a recurring event, save an exception, remove the saved exception should remove the persisted exception, but the exdate should remain in the parent */
1480 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
1481 recEvent.setId(QOrganizerItemId());
1482 recEvent.setDescription("a recurring event");
1483 recEvent.setStartDateTime(QDateTime(QDate(2010, 10, 20), QTime(8, 0, 0)));
1484 recEvent.setEndDateTime(QDateTime(QDate(2010, 10, 20), QTime(10, 0, 0)));
1485 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
1486 rrule.setLimit(3);
1487 recEvent.setRecurrenceRule(rrule);
1488 QVERIFY(cm->saveItem(&recEvent));
1489 items = cm->items();
1490 QCOMPARE(items.size(), 3);
1491 exception = items.at(i: 1);
1492 exception.setStartDateTime(QDateTime(QDate(2010, 10, 21), QTime(7, 0, 0)));
1493 QVERIFY(cm->saveItem(&exception));
1494 items = cm->items();
1495 QCOMPARE(items.size(), 3);
1496 QCOMPARE(cm->itemsForExport().size(), 2);
1497 QVERIFY(cm->removeItem(exception.id()));
1498 QCOMPARE(cm->itemsForExport().size(), 1); // only parent remains as persistent
1499 items = cm->items();
1500 QCOMPARE(items.size(), 2); // the exception date remains in parent, so only 2 occurrences are generated.
1501
1502 // Create a recurring event, remove a generated occurrence should add an exdate in the parent
1503 QOrganizerItem itemOccurrence = items[0];
1504 cm->removeItem(item: &itemOccurrence);
1505 items = cm->items();
1506 QCOMPARE(items.size(), 1);
1507
1508 // Remove both parent item and generated occurrence in the same request
1509 // --> request should fail because
1510 itemList.clear();
1511 itemList << recEvent << items[0];
1512 QVERIFY(cm->removeItems(&itemList));
1513 items = cm->items();
1514 QCOMPARE(cm->items().size(), 0);
1515}
1516
1517void tst_QOrganizerManager::batch()
1518{
1519 QFETCH(QString, uri);
1520 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
1521
1522 /* First test null pointer operations */
1523 QVERIFY(!cm->saveItems(NULL));
1524 QVERIFY(cm->error() == QOrganizerManager::BadArgumentError);
1525
1526 QVERIFY(!cm->removeItems(QList<QOrganizerItemId>()));
1527 QVERIFY(cm->error() == QOrganizerManager::BadArgumentError);
1528
1529 // Use note & todo item depending on backend support
1530 QOrganizerItemType::ItemType type;
1531 if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeNote))
1532 type = QOrganizerItemType::TypeNote;
1533 else if (cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeTodo))
1534 type = QOrganizerItemType::TypeTodo;
1535 else
1536 QSKIP("This manager does not support note or todo item");
1537
1538 QOrganizerItem a;
1539 QOrganizerItem b;
1540 QOrganizerItem c;
1541 a.setType(type);
1542 b.setType(type);
1543 c.setType(type);
1544
1545 /* Now add 3 items, all valid */
1546 QOrganizerItemDisplayLabel da;
1547 da.setValue(field: QOrganizerItemDisplayLabel::FieldLabel, value: "XXXXXX A Note");
1548 a.saveDetail(detail: &da);
1549
1550 QOrganizerItemDisplayLabel db;
1551 db.setValue(field: QOrganizerItemDisplayLabel::FieldLabel, value: "XXXXXX B Note");
1552 b.saveDetail(detail: &db);
1553
1554 QOrganizerItemDisplayLabel dc;
1555 dc.setValue(field: QOrganizerItemDisplayLabel::FieldLabel, value: "XXXXXX C Note");
1556 c.saveDetail(detail: &dc);
1557
1558 QList<QOrganizerItem> items;
1559 items << a << b << c;
1560
1561 QMap<int, QOrganizerManager::Error> errorMap;
1562 // Add one dummy error to test if the errors are reset
1563 errorMap.insert(akey: 0, avalue: QOrganizerManager::NoError);
1564 QVERIFY(cm->saveItems(&items));
1565 QVERIFY(cm->error() == QOrganizerManager::NoError);
1566 errorMap = cm->errorMap();
1567 QVERIFY(errorMap.count() == 0);
1568
1569 /* Make sure our items got updated too */
1570 QVERIFY(items.count() == 3);
1571 QVERIFY(items.at(0).id() != QOrganizerItemId());
1572 QVERIFY(items.at(1).id() != QOrganizerItemId());
1573 QVERIFY(items.at(2).id() != QOrganizerItemId());
1574
1575 QVERIFY(items.at(0).detail(QOrganizerItemDetail::TypeDisplayLabel) == da);
1576 QVERIFY(items.at(1).detail(QOrganizerItemDetail::TypeDisplayLabel) == db);
1577 QVERIFY(items.at(2).detail(QOrganizerItemDetail::TypeDisplayLabel) == dc);
1578
1579 /* Retrieve again */
1580 a = cm->item(itemId: items.at(i: 0).id());
1581 b = cm->item(itemId: items.at(i: 1).id());
1582 c = cm->item(itemId: items.at(i: 2).id());
1583 QVERIFY(items.at(0).detail(QOrganizerItemDetail::TypeDisplayLabel) == da);
1584 QVERIFY(items.at(1).detail(QOrganizerItemDetail::TypeDisplayLabel) == db);
1585 QVERIFY(items.at(2).detail(QOrganizerItemDetail::TypeDisplayLabel) == dc);
1586
1587 /* Now make an update to them all */
1588 QOrganizerItemDescription descr;
1589 descr.setDescription("This note looks slightly shifty");
1590
1591 QVERIFY(items[0].saveDetail(&descr));
1592 descr.setDescription("This note is definitely up to no good");
1593 QVERIFY(items[1].saveDetail(&descr));
1594 descr.setDescription("This note is a terrible note");
1595 QVERIFY(items[2].saveDetail(&descr));
1596
1597 QVERIFY(cm->saveItems(&items));
1598 QVERIFY(cm->error() == QOrganizerManager::NoError);
1599 errorMap = cm->errorMap();
1600 QVERIFY(errorMap.count() == 0);
1601
1602 /* Retrieve them and check them again */
1603 a = cm->item(itemId: items.at(i: 0).id());
1604 b = cm->item(itemId: items.at(i: 1).id());
1605 c = cm->item(itemId: items.at(i: 2).id());
1606 QVERIFY(items.at(0).detail(QOrganizerItemDetail::TypeDisplayLabel) == da);
1607 QVERIFY(items.at(1).detail(QOrganizerItemDetail::TypeDisplayLabel) == db);
1608 QVERIFY(items.at(2).detail(QOrganizerItemDetail::TypeDisplayLabel) == dc);
1609
1610 QVERIFY(a.details(QOrganizerItemDetail::TypeDescription).count() == 1);
1611 QVERIFY(b.details(QOrganizerItemDetail::TypeDescription).count() == 1);
1612 QVERIFY(c.details(QOrganizerItemDetail::TypeDescription).count() == 1);
1613
1614 QVERIFY(a.details(QOrganizerItemDetail::TypeDescription).at(0).value(QOrganizerItemDescription::FieldDescription) == "This note looks slightly shifty");
1615 QVERIFY(b.details(QOrganizerItemDetail::TypeDescription).at(0).value(QOrganizerItemDescription::FieldDescription) == "This note is definitely up to no good");
1616 QVERIFY(c.details(QOrganizerItemDetail::TypeDescription).at(0).value(QOrganizerItemDescription::FieldDescription) == "This note is a terrible note");
1617
1618 /* Now delete them all */
1619 QList<QOrganizerItemId> ids;
1620 ids << a.id() << b.id() << c.id();
1621 QVERIFY(cm->removeItems(ids));
1622 errorMap = cm->errorMap();
1623 QVERIFY(errorMap.count() == 0);
1624 QVERIFY(cm->error() == QOrganizerManager::NoError);
1625
1626 /* Make sure the items really don't exist any more */
1627 QVERIFY(cm->item(a.id()).id() == QOrganizerItemId());
1628 QVERIFY(cm->item(a.id()).isEmpty());
1629 QVERIFY(cm->error() == QOrganizerManager::DoesNotExistError);
1630 QVERIFY(cm->item(b.id()).id() == QOrganizerItemId());
1631 QVERIFY(cm->item(b.id()).isEmpty());
1632 QVERIFY(cm->error() == QOrganizerManager::DoesNotExistError);
1633 QVERIFY(cm->item(c.id()).id() == QOrganizerItemId());
1634 QVERIFY(cm->item(c.id()).isEmpty());
1635 QVERIFY(cm->error() == QOrganizerManager::DoesNotExistError);
1636
1637 /* Now try removing with all invalid ids (e.g. the ones we just removed) */
1638 ids.clear();
1639 ids << a.id() << b.id() << c.id();
1640 QVERIFY(!cm->removeItems(ids));
1641 QVERIFY(cm->error() == QOrganizerManager::DoesNotExistError);
1642 errorMap = cm->errorMap();
1643 QVERIFY(errorMap.count() == 3);
1644 QVERIFY(errorMap.values().at(0) == QOrganizerManager::DoesNotExistError);
1645 QVERIFY(errorMap.values().at(1) == QOrganizerManager::DoesNotExistError);
1646 QVERIFY(errorMap.values().at(2) == QOrganizerManager::DoesNotExistError);
1647
1648 /* Try adding some new ones again, this time one with an error */
1649 items.clear();
1650 a.setId(QOrganizerItemId());
1651 b.setId(QOrganizerItemId());
1652 c.setId(QOrganizerItemId());
1653
1654 items << a << b << c;
1655
1656// /* Make B the bad guy */
1657// QOrganizerItemDetail bad("does not exist and will break if you add it");
1658// bad.setValue("This is also bad", "Very bad");
1659// b.saveDetail(&bad);
1660
1661// QVERIFY(!cm->saveItems(&items)); // since we don't setCollectionId() in any of the items, they go in default collection.
1662// /* We can't really say what the error will be.. maybe bad argument, maybe invalid detail */
1663// QVERIFY(cm->error() != QOrganizerManager::NoError);
1664
1665// /* It's permissible to fail all the adds, or to add the successful ones */
1666// errorMap = cm->errorMap();
1667// QVERIFY(errorMap.count() > 0);
1668// QVERIFY(errorMap.count() <= 3);
1669
1670// // A might have gone through
1671// if (errorMap.keys().contains(0)) {
1672// QVERIFY(errorMap.value(0) != QOrganizerManager::NoError);
1673// QVERIFY(items.at(0).id() == QOrganizerItemId());
1674// } else {
1675// QVERIFY(items.at(0).id() != QOrganizerItemId());
1676// }
1677
1678// // B should have failed
1679// QVERIFY(errorMap.value(1) == QOrganizerManager::InvalidDetailError);
1680// QVERIFY(items.at(1).id() == QOrganizerItemId());
1681
1682// // C might have gone through
1683// if (errorMap.keys().contains(2)) {
1684// QVERIFY(errorMap.value(2) != QOrganizerManager::NoError);
1685// QVERIFY(items.at(2).id() == QOrganizerItemId());
1686// } else {
1687// QVERIFY(items.at(2).id() != QOrganizerItemId());
1688// }
1689
1690// /* Fix up B and re save it */
1691// QVERIFY(items[1].removeDetail(&bad));
1692// QVERIFY(cm->saveItems(&items));
1693// errorMap = cm->errorMap();
1694// QVERIFY(errorMap.count() == 0);
1695// QVERIFY(cm->error() == QOrganizerManager::NoError);
1696
1697 // Save and remove a fourth item. Store the id.
1698 QOrganizerItem d;
1699 d.setType(type);
1700 d.setDisplayLabel("XXXXXX D Note");
1701 QVERIFY(cm->saveItem(&d));
1702 QOrganizerItemId removedId = d.id();
1703 QVERIFY(cm->removeItem(removedId));
1704
1705 /* Now delete 3 items, but with one bad argument */
1706 ids.clear();
1707 ids << items.at(i: 0).id();
1708 ids << removedId;
1709 ids << items.at(i: 2).id();
1710
1711 QVERIFY(!cm->removeItems(ids));
1712 QVERIFY(cm->error() != QOrganizerManager::NoError);
1713
1714 /* Again, the backend has the choice of either removing the successful ones, or not */
1715 errorMap = cm->errorMap();
1716 QVERIFY(errorMap.count() > 0);
1717 QVERIFY(errorMap.count() <= 3);
1718
1719 // A might have gone through
1720 if (errorMap.keys().contains(t: 0)) {
1721 QVERIFY(errorMap.value(0) != QOrganizerManager::NoError);
1722 QVERIFY(items.at(0).id() == QOrganizerItemId());
1723 } else {
1724 QVERIFY(items.at(0).id() != QOrganizerItemId());
1725 }
1726
1727 /* B should definitely have failed */
1728 QVERIFY(errorMap.value(1) == QOrganizerManager::DoesNotExistError);
1729 QVERIFY(ids.at(1) == removedId);
1730
1731 // A might have gone through
1732 if (errorMap.keys().contains(t: 2)) {
1733 QVERIFY(errorMap.value(2) != QOrganizerManager::NoError);
1734 QVERIFY(items.at(2).id() == QOrganizerItemId());
1735 } else {
1736 QVERIFY(items.at(2).id() != QOrganizerItemId());
1737 }
1738}
1739
1740void tst_QOrganizerManager::invalidManager()
1741{
1742 /* Create an invalid manager */
1743 QOrganizerManager manager("this should never work");
1744 QVERIFY(manager.managerName() == "invalid");
1745
1746 /* Now test that all the operations fail */
1747 QVERIFY(manager.itemIds().count() == 0);
1748 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1749
1750 QOrganizerItem foo;
1751 QOrganizerItemDisplayLabel dl;
1752 dl.setLabel("some label");
1753 foo.saveDetail(detail: &dl);
1754
1755 QVERIFY(manager.saveItem(&foo) == false);
1756 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1757 QVERIFY(foo.id() == QOrganizerItemId());
1758 QVERIFY(manager.itemIds().count() == 0);
1759
1760 QVERIFY(manager.item(foo.id()).id() == QOrganizerItemId());
1761 QVERIFY(manager.item(foo.id()).isEmpty());
1762 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1763
1764 QVERIFY(manager.removeItem(foo.id()) == false);
1765 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1766
1767 QMap<int, QOrganizerManager::Error> errorMap;
1768 errorMap.insert(akey: 0, avalue: QOrganizerManager::NoError);
1769 QVERIFY(!manager.saveItems(0));
1770 errorMap = manager.errorMap();
1771 QVERIFY(errorMap.count() == 0);
1772 QVERIFY(manager.error() == QOrganizerManager::BadArgumentError);
1773
1774 /* filters */
1775 QOrganizerItemFilter f; // matches everything
1776 QOrganizerItemDetailFieldFilter dff;
1777 dff.setDetail(detailType: QOrganizerItemDetail::TypeDisplayLabel, field: QOrganizerItemDisplayLabel::FieldLabel);
1778 QVERIFY(manager.itemIds(QDateTime(), QDateTime(), QOrganizerItemFilter()).count() == 0);
1779 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1780 QVERIFY(manager.itemIds(QDateTime(), QDateTime(), dff).count() == 0);
1781 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1782 QVERIFY(manager.itemIds(QDateTime(), QDateTime(), f | f).count() == 0);
1783 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1784 QVERIFY(manager.itemIds(QDateTime(), QDateTime(), dff | dff).count() == 0);
1785 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1786
1787 QVERIFY(manager.supportedFilters().size() == 0);
1788
1789 QList<QOrganizerItem> list;
1790 list << foo;
1791
1792 QVERIFY(!manager.saveItems(&list));
1793 errorMap = manager.errorMap();
1794 QVERIFY(errorMap.count() == 0);
1795 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1796
1797 QVERIFY(!manager.removeItems(QList<QOrganizerItemId>()));
1798 errorMap = manager.errorMap();
1799 QVERIFY(errorMap.count() == 0);
1800 QVERIFY(manager.error() == QOrganizerManager::BadArgumentError);
1801
1802 QList<QOrganizerItemId> idlist;
1803 idlist << foo.id();
1804 QVERIFY(!manager.removeItems(idlist));
1805 errorMap = manager.errorMap();
1806 QVERIFY(errorMap.count() == 0);
1807 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1808
1809 /* Collections */
1810 QOrganizerCollection testCollection;
1811 testCollection.setExtendedMetaData(key: "test", value: "example");
1812 QVERIFY(!manager.saveCollection(&testCollection));
1813 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError || manager.error() == QOrganizerManager::InvalidCollectionError);
1814 QVERIFY(!manager.removeCollection(testCollection.id()));
1815 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError || manager.error() == QOrganizerManager::DoesNotExistError);
1816 QVERIFY(manager.collection(manager.defaultCollectionId()) == QOrganizerCollection());
1817 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1818 QVERIFY(manager.collections().isEmpty());
1819 QVERIFY(manager.error() == QOrganizerManager::NotSupportedError);
1820
1821 /* Requests */
1822 QOrganizerItemFetchRequest ifr;
1823 QOrganizerItemFetchForExportRequest ifer;
1824 QOrganizerItemSaveRequest isr;
1825 QOrganizerItemRemoveRequest irr;
1826 QOrganizerItemRemoveByIdRequest irbir;
1827 QOrganizerCollectionFetchRequest cfr;
1828 QOrganizerCollectionSaveRequest csr;
1829 QOrganizerCollectionRemoveRequest crr;
1830
1831 ifr.setManager(&manager);
1832 QVERIFY(!ifr.start());
1833 QVERIFY(!ifr.cancel());
1834 ifr.waitForFinished();
1835 //QVERIFY(ifr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1836
1837 ifer.setManager(&manager);
1838 QVERIFY(!ifer.start());
1839 QVERIFY(!ifer.cancel());
1840 ifer.waitForFinished();
1841 //QVERIFY(ifer.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1842
1843 isr.setManager(&manager);
1844 isr.setItem(foo);
1845 QVERIFY(!isr.start());
1846 QVERIFY(!isr.cancel());
1847 isr.waitForFinished();
1848 //QVERIFY(isr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1849
1850 irr.setManager(&manager);
1851 irr.setItem(foo);
1852
1853 QVERIFY(!irr.start());
1854 QVERIFY(!irr.cancel());
1855 irr.waitForFinished();
1856 //QVERIFY(irr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1857
1858 irbir.setManager(&manager);
1859 irbir.setItemId(foo.id());
1860
1861 qDebug() << foo.id();
1862 QVERIFY(!irbir.start());
1863 QVERIFY(!irbir.cancel());
1864 irbir.waitForFinished();
1865 //QVERIFY(irr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1866
1867
1868 cfr.setManager(&manager);
1869 QVERIFY(!cfr.start());
1870 QVERIFY(!cfr.cancel());
1871 cfr.waitForFinished();
1872 //QVERIFY(cfr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1873
1874 csr.setManager(&manager);
1875 csr.setCollection(testCollection);
1876 QVERIFY(!csr.start());
1877 QVERIFY(!csr.cancel());
1878 csr.waitForFinished();
1879 //QVERIFY(csr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1880
1881 crr.setManager(&manager);
1882 crr.setCollectionId(testCollection.id());
1883 QVERIFY(!crr.start());
1884 QVERIFY(!crr.cancel());
1885 crr.waitForFinished();
1886 //QVERIFY(crr.error() == QOrganizerManager::NotSupportedError); // XXX TODO: if start fails, should be not supported error...
1887}
1888
1889void tst_QOrganizerManager::memoryManager()
1890{
1891 QMap<QString, QString> params;
1892 QOrganizerManager m1("memory");
1893 params.insert(akey: "random", avalue: "shouldNotBeUsed");
1894 QOrganizerManager m2("memory", params);
1895 params.insert(akey: "id", avalue: "shouldBeUsed");
1896 QOrganizerManager m3("memory", params);
1897 QOrganizerManager m4("memory", params);
1898 params.insert(akey: "id", avalue: QString(""));
1899 QOrganizerManager m5("memory", params);
1900
1901 // add a item to each of m1, m2, m3
1902 QOrganizerEvent c;
1903 QOrganizerItemDisplayLabel c1dl;
1904 c1dl.setLabel("c1dl");
1905 c.saveDetail(detail: &c1dl);
1906 QVERIFY(m1.saveItem(&c));
1907 c.setId(QOrganizerItemId());
1908 QOrganizerItem c2;
1909 QOrganizerItemDisplayLabel c2dl = c2.detail(detailType: QOrganizerItemDetail::TypeDisplayLabel);
1910 c2 = c;
1911 c2dl.setLabel("c2dl");
1912 c2.saveDetail(detail: &c2dl);
1913 c2.setCollectionId(QOrganizerCollectionId());
1914 c.setCollectionId(QOrganizerCollectionId());
1915 QVERIFY(m2.saveItem(&c2)); // save c2 first; c will be given a higher id
1916 QVERIFY(m2.saveItem(&c)); // save c to m2
1917 c.setId(QOrganizerItemId());
1918 c1dl.setLabel("c3dl");
1919 c.saveDetail(detail: &c1dl);
1920 c.setCollectionId(QOrganizerCollectionId());
1921 QVERIFY(m3.saveItem(&c));
1922
1923 /* test that m1 != m2 != m3 and that m3 == m4 */
1924
1925 // check the counts are correct - especially note m4 and m3.
1926 QCOMPARE(m1.itemIds().count(), 1);
1927 QCOMPARE(m2.itemIds().count(), 2);
1928 QCOMPARE(m3.itemIds().count(), 1);
1929 QCOMPARE(m4.itemIds().count(), 1);
1930 QCOMPARE(m5.itemIds().count(), 0);
1931
1932 // remove c2 from m2 - ensure that this doesn't affect any other manager.
1933 m2.removeItem(itemId: c2.id());
1934 QCOMPARE(m1.itemIds().count(), 1);
1935 QCOMPARE(m2.itemIds().count(), 1);
1936 QCOMPARE(m3.itemIds().count(), 1);
1937 QCOMPARE(m4.itemIds().count(), 1);
1938 QCOMPARE(m5.itemIds().count(), 0);
1939
1940 // check that the items contained within are different.
1941 // note that in the m1->m2 case, only the id will be different!
1942 QVERIFY(m1.item(m1.itemIds().at(0)) != m2.item(m2.itemIds().at(0)));
1943 QVERIFY(m1.item(m1.itemIds().at(0)) != m3.item(m3.itemIds().at(0)));
1944 QVERIFY(m2.item(m2.itemIds().at(0)) != m3.item(m3.itemIds().at(0)));
1945 QVERIFY(m3.item(m3.itemIds().at(0)) == m4.item(m4.itemIds().at(0)));
1946
1947 // now, we should be able to remove from m4, and have m3 empty
1948 QVERIFY(m4.removeItem(c.id()));
1949 QCOMPARE(m3.itemIds().count(), 0);
1950 QCOMPARE(m4.itemIds().count(), 0);
1951 QCOMPARE(m5.itemIds().count(), 0);
1952}
1953
1954void tst_QOrganizerManager::recurrenceWithGenerator_data()
1955{
1956 QTest::addColumn<QString>(name: "uri");
1957 QTest::addColumn<QDate>(name: "generatorDate");
1958 QTest::addColumn<QOrganizerRecurrenceRule>(name: "recurrenceRule");
1959 QTest::addColumn<QOrganizerRecurrenceRule>(name: "exceptionRule");
1960 QTest::addColumn<QSet<QDate> >(name: "recurrenceDates");
1961 QTest::addColumn<QSet<QDate> >(name: "exceptionDates");
1962 QTest::addColumn<QDate>(name: "startDate");
1963 QTest::addColumn<QDate>(name: "endDate");
1964 QTest::addColumn<QList<QDate> >(name: "occurrenceDates");
1965
1966 QStringList managers = QOrganizerManager::availableManagers();
1967
1968 /* Known one that will not pass */
1969 managers.removeAll(t: "invalid");
1970 managers.removeAll(t: "testdummy");
1971 managers.removeAll(t: "teststaticdummy");
1972 managers.removeAll(t: "maliciousplugin");
1973 managers.removeAll(t: "skeleton");
1974
1975 QOrganizerRecurrenceRule exrule;
1976 QSet<QDate> rdates;
1977 QSet<QDate> exdates;
1978 foreach(QString mgr, managers) {
1979 QString managerUri = QOrganizerManager::buildUri(managerName: mgr, params: QMap<QString, QString>());
1980
1981 {
1982 QOrganizerRecurrenceRule rrule;
1983 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
1984 rrule.setLimit(QDate(2010, 1, 22));
1985 QTest::newRow(dataTag: QString("mgr=%1, weekly recurrence").arg(a: mgr).toLatin1().constData())
1986 << managerUri << QDate(2010, 1, 1)
1987 << rrule << exrule << rdates << exdates
1988 << QDate(2010, 1, 1) << QDate(2010, 1, 20)
1989 // stops at the 15th because the query end date is the 20th
1990 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15));
1991
1992 // change the end date of the query to 2010-02-01
1993 QTest::newRow(dataTag: QString("mgr=%1, weekly recurrence, end date is inclusive").arg(a: mgr).toLatin1().constData())
1994 << managerUri << QDate(2010, 1, 1)
1995 << rrule << exrule << rdates << exdates
1996 << QDate(2010, 1, 1) << QDate(2010, 2, 1)
1997 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15) << QDate(2010, 1, 22));
1998
1999 // Now let's fiddle with the recurrence end date and see what happens
2000 rrule.setLimit(QDate(2010, 1, 23));
2001 QTest::newRow(dataTag: QString("mgr=%1, weekly recurrence, end date observed (+1)").arg(a: mgr).toLatin1().constData())
2002 << managerUri << QDate(2010, 1, 1)
2003 << rrule << exrule << rdates << exdates
2004 << QDate(2010, 1, 1) << QDate(2010, 2, 1)
2005 // now stop on the 22nd
2006 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15) << QDate(2010, 1, 22));
2007
2008 rrule.setLimit(QDate(2010, 1, 21));
2009 QTest::newRow(dataTag: QString("mgr=%1, weekly recurrence, end date observed (-1)").arg(a: mgr).toLatin1().constData())
2010 << managerUri << QDate(2010, 1, 1)
2011 << rrule << exrule << rdates << exdates
2012 << QDate(2010, 1, 1) << QDate(2010, 2, 1)
2013 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15));
2014
2015 rrule.setLimit(QDate());
2016 rrule.setLimit(2);
2017 QTest::newRow(dataTag: QString("mgr=%1, weekly recurrence, count").arg(a: mgr).toLatin1().constData())
2018 << managerUri << QDate(2010, 1, 1)
2019 << rrule << exrule << rdates << exdates
2020 << QDate(2010, 1, 1) << QDate(2010, 2, 1)
2021 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8));
2022 }
2023
2024 {
2025 QOrganizerRecurrenceRule rrule;
2026 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
2027 rrule.setLimit(QDate(2010, 1, 5));
2028 QTest::newRow(dataTag: QString("mgr=%1, daily").arg(a: mgr).toLatin1().constData())
2029 << managerUri << QDate(2010, 1, 1)
2030 << rrule << exrule << rdates << exdates
2031 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2032 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 2)
2033 << QDate(2010, 1, 3) << QDate(2010, 1, 4)
2034 << QDate(2010, 1, 5));
2035
2036 rrule.setInterval(3);
2037 QTest::newRow(dataTag: QString("mgr=%1, daily, interval").arg(a: mgr).toLatin1().constData())
2038 << managerUri << QDate(2010, 1, 1)
2039 << rrule << exrule << rdates << exdates
2040 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2041 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 4));
2042 }
2043
2044 {
2045 QOrganizerRecurrenceRule rrule;
2046 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
2047 rrule.setFirstDayOfWeek(Qt::Monday);
2048 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Friday << Qt::Saturday << Qt::Sunday);
2049 rrule.setLimit(QDate(2010, 1, 27));
2050 QTest::newRow(dataTag: QString("mgr=%1, weekly, days of week").arg(a: mgr).toLatin1().constData())
2051 << managerUri << QDate(2010, 1, 1)
2052 << rrule << exrule << rdates << exdates
2053 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2054 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 2) << QDate(2010, 1, 3)
2055 << QDate(2010, 1, 8) << QDate(2010, 1, 9) << QDate(2010, 1, 10)
2056 << QDate(2010, 1, 15) << QDate(2010, 1, 16) << QDate(2010, 1, 17)
2057 << QDate(2010, 1, 22) << QDate(2010, 1, 23) << QDate(2010, 1, 24));
2058
2059 rrule.setInterval(3);
2060 QTest::newRow(dataTag: QString("mgr=%1, weekly, days of week, interval").arg(a: mgr).toLatin1().constData())
2061 << managerUri << QDate(2010, 1, 1)
2062 << rrule << exrule << rdates << exdates
2063 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2064 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 2) << QDate(2010, 1, 3)
2065 << QDate(2010, 1, 22) << QDate(2010, 1, 23) << QDate(2010, 1, 24));
2066 }
2067
2068 {
2069 QOrganizerRecurrenceRule rrule;
2070 rrule.setFrequency(QOrganizerRecurrenceRule::Monthly);
2071 rrule.setDaysOfMonth(QSet<int>() << 1 << 10);
2072 rrule.setLimit(QDate(2010, 4, 15));
2073 QTest::newRow(dataTag: QString("mgr=%1, monthly recurrence").arg(a: mgr).toLatin1().constData())
2074 << managerUri << QDate(2010, 1, 1)
2075 << rrule << exrule << rdates << exdates
2076 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2077 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 10)
2078 << QDate(2010, 2, 1) << QDate(2010, 2, 10)
2079 << QDate(2010, 3, 1) << QDate(2010, 3, 10)
2080 << QDate(2010, 4, 1) << QDate(2010, 4, 10));
2081
2082 rrule.setInterval(3);
2083 QTest::newRow(dataTag: QString("mgr=%1, monthly recurrence, interval").arg(a: mgr).toLatin1().constData())
2084 << managerUri << QDate(2010, 1, 1)
2085 << rrule << exrule << rdates << exdates
2086 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2087 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 10)
2088 << QDate(2010, 4, 1) << QDate(2010, 4, 10));
2089 }
2090
2091 {
2092 QOrganizerRecurrenceRule rrule;
2093 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
2094 rrule.setDaysOfYear(QSet<int>() << 1 << 32);
2095 rrule.setLimit(QDate(2012, 3, 15));
2096 QTest::newRow(dataTag: QString("mgr=%1, yearly recurrence").arg(a: mgr).toLatin1().constData())
2097 << managerUri << QDate(2010, 1, 1)
2098 << rrule << exrule << rdates << exdates
2099 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2100 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 2, 1)
2101 << QDate(2011, 1, 1) << QDate(2011, 2, 1)
2102 << QDate(2012, 1, 1) << QDate(2012, 2, 1));
2103
2104 rrule.setLimit(QDate(2013, 3, 15));
2105 rrule.setInterval(3);
2106 QTest::newRow(dataTag: QString("mgr=%1, yearly recurrence, interval").arg(a: mgr).toLatin1().constData())
2107 << managerUri << QDate(2010, 1, 1)
2108 << rrule << exrule << rdates << exdates
2109 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2110 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 2, 1)
2111 << QDate(2013, 1, 1) << QDate(2013, 2, 1));
2112 }
2113
2114 {
2115 QOrganizerRecurrenceRule rrule;
2116 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
2117 rrule.setMonthsOfYear(QSet<QOrganizerRecurrenceRule::Month>()
2118 << QOrganizerRecurrenceRule::January
2119 << QOrganizerRecurrenceRule::March);
2120 rrule.setLimit(QDate(2011, 3, 15));
2121 QTest::newRow(dataTag: QString("mgr=%1, yearly recurrence, by month").arg(a: mgr).toLatin1().constData())
2122 << managerUri << QDate(2010, 1, 1)
2123 << rrule << exrule << rdates << exdates
2124 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2125 << (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 3, 1)
2126 << QDate(2011, 1, 1) << QDate(2011, 3, 1));
2127 // The day-of-month should be inferred from the day-of-month of the original event
2128 }
2129
2130 {
2131 QOrganizerRecurrenceRule rrule;
2132 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
2133 rrule.setWeeksOfYear(QSet<int>() << 1 << 4);
2134 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Thursday);
2135 rrule.setLimit(QDate(2011, 3, 15));
2136 QTest::newRow(dataTag: QString("mgr=%1, yearly recurrence, by week").arg(a: mgr).toLatin1().constData())
2137 << managerUri << QDate(2010, 1, 7) // this is the first day of week 1
2138 << rrule << exrule << rdates << exdates
2139 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2140 << (QList<QDate>() << QDate(2010, 1, 7) << QDate(2010, 1, 28)
2141 << QDate(2011, 1, 6) << QDate(2011, 1, 27));
2142 }
2143
2144 {
2145 QOrganizerRecurrenceRule rrule;
2146 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
2147 rrule.setMonthsOfYear(QSet<QOrganizerRecurrenceRule::Month>()
2148 << QOrganizerRecurrenceRule::April);
2149 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Sunday);
2150 rrule.setPositions(QSet<int>() << 1);
2151 QTest::newRow(dataTag: QString("mgr=%1, yearly recurrence, first Sunday of April").arg(a: mgr).toLatin1().constData())
2152 << managerUri << QDate(2010, 4, 4) // this is the first Sunday of April 2010
2153 << rrule << exrule << rdates << exdates
2154 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2155 << (QList<QDate>() << QDate(2010, 4, 4)
2156 << QDate(2011, 4, 3)
2157 << QDate(2012, 4, 1)
2158 << QDate(2013, 4, 7)
2159 << QDate(2014, 4, 6));
2160 }
2161
2162 {
2163 QOrganizerRecurrenceRule rrule;
2164 rrule.setFrequency(QOrganizerRecurrenceRule::Yearly);
2165 rrule.setMonthsOfYear(QSet<QOrganizerRecurrenceRule::Month>()
2166 << QOrganizerRecurrenceRule::October);
2167 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Sunday);
2168 rrule.setPositions(QSet<int>() << -1);
2169 QTest::newRow(dataTag: QString("mgr=%1, yearly recurrence, last Sunday of October").arg(a: mgr).toLatin1().constData())
2170 << managerUri << QDate(2010, 10, 31) // this is the last Sunday of October 2010
2171 << rrule << exrule << rdates << exdates
2172 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2173 << (QList<QDate>() << QDate(2010, 10, 31)
2174 << QDate(2011, 10, 30)
2175 << QDate(2012, 10, 28)
2176 << QDate(2013, 10, 27)
2177 << QDate(2014, 10, 26));
2178 }
2179
2180 {
2181 QOrganizerRecurrenceRule rrule; // empty
2182 QSet<QDate> rdates;
2183 rdates << QDate(2010, 1, 5) << QDate(2010, 1, 8);
2184 QTest::newRow(dataTag: QString("mgr=%1, rdates").arg(a: mgr).toLatin1().constData())
2185 << managerUri << QDate(2010, 1, 1)
2186 << rrule << exrule << rdates << exdates
2187 << QDate(2010, 1, 1) << QDate(2015, 1, 1)
2188 << (QList<QDate>() << QDate(2010, 1, 1)
2189 << QDate(2010, 1, 5)
2190 << QDate(2010, 1, 8));
2191 }
2192
2193 {
2194 QOrganizerRecurrenceRule rrule;
2195 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
2196 QSet<QDate> exdates;
2197 exdates << QDate(2010, 1, 2) << QDate(2010, 1, 3);
2198 QTest::newRow(dataTag: QString("mgr=%1, exdates").arg(a: mgr).toLatin1().constData())
2199 << managerUri << QDate(2010, 1, 1)
2200 << rrule << exrule << rdates << exdates
2201 << QDate(2010, 1, 1) << QDate(2010, 1, 5)
2202 << (QList<QDate>() << QDate(2010, 1, 1)
2203 << QDate(2010, 1, 4)
2204 << QDate(2010, 1, 5));
2205 }
2206
2207 {
2208 QOrganizerRecurrenceRule rrule;
2209 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
2210 QOrganizerRecurrenceRule exrule;
2211 exrule.setFrequency(QOrganizerRecurrenceRule::Monthly);
2212 exrule.setDaysOfMonth(QSet<int>() << 2 << 3);
2213 QTest::newRow(dataTag: QString("mgr=%1, exrule").arg(a: mgr).toLatin1().constData())
2214 << managerUri << QDate(2010, 1, 1)
2215 << rrule << exrule << rdates << exdates
2216 << QDate(2010, 1, 1) << QDate(2010, 1, 5)
2217 << (QList<QDate>() << QDate(2010, 1, 1)
2218 << QDate(2010, 1, 4)
2219 << QDate(2010, 1, 5));
2220 }
2221
2222 {
2223 QOrganizerRecurrenceRule rrule;
2224 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
2225 rrule.setLimit(8);
2226 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>()
2227 << Qt::Monday
2228 << Qt::Tuesday
2229 << Qt::Wednesday);
2230 QOrganizerRecurrenceRule exrule;
2231 QTest::newRow(dataTag: QString("mgr=%1, weekly, count, days of week").arg(a: mgr).toLatin1().constData())
2232 << managerUri << QDate(2014, 1, 22)
2233 << rrule << exrule << rdates << exdates
2234 << QDate(2014, 1, 1) << QDate(2014, 5, 1)
2235 << (QList<QDate>() << QDate(2014, 1, 22) << QDate(2014, 1, 27)
2236 << QDate(2014, 1, 28) << QDate(2014, 1, 29)
2237 << QDate(2014, 2, 3) << QDate(2014, 2, 4)
2238 << QDate(2014, 2, 5) << QDate(2014, 2, 10));
2239 }
2240 }
2241}
2242
2243void tst_QOrganizerManager::recurrenceWithGenerator()
2244{
2245 QFETCH(QString, uri);
2246 QFETCH(QDate, generatorDate);
2247 QFETCH(QOrganizerRecurrenceRule, recurrenceRule);
2248 QFETCH(QOrganizerRecurrenceRule, exceptionRule);
2249 QFETCH(QSet<QDate>, recurrenceDates);
2250 QFETCH(QSet<QDate>, exceptionDates);
2251 QFETCH(QDate, startDate);
2252 QFETCH(QDate, endDate);
2253 QFETCH(QList<QDate>, occurrenceDates);
2254
2255 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
2256
2257 QOrganizerEvent event;
2258 event.setDisplayLabel("event");
2259 event.setStartDateTime(QDateTime(generatorDate, QTime(11, 0, 0)));
2260 event.setEndDateTime(QDateTime(generatorDate, QTime(11, 30, 0)));
2261 event.setRecurrenceRule(recurrenceRule);
2262 event.setExceptionRule(exceptionRule);
2263 event.setRecurrenceDates(recurrenceDates);
2264 event.setExceptionDates(exceptionDates);
2265
2266 if (cm->saveItem(item: &event)) {
2267 QList<QOrganizerItem> items = cm->itemOccurrences(parentItem: event,
2268 startDateTime: QDateTime(startDate, QTime(0, 0, 0)),
2269 endDateTime: QDateTime(endDate, QTime(23, 59, 59, 999)));
2270
2271 QList<QDate> actualDates;
2272 for (int i = 0; i < items.size(); i++) {
2273 QOrganizerItem item = items.at(i);
2274 QCOMPARE(item.type(), QOrganizerItemType::TypeEventOccurrence);
2275 QDate occurrenceDate = item.detail(detailType: QOrganizerItemDetail::TypeEventTime).value(field: QOrganizerEventTime::FieldStartDateTime).toDateTime().date();
2276 //QCOMPARE(occurrenceDate, occurrenceDates.at(i));
2277 actualDates << occurrenceDate;
2278 }
2279 if (actualDates != occurrenceDates) {
2280 qDebug() << "Actual: " << actualDates;
2281 qDebug() << "Expected: " << occurrenceDates;
2282 QCOMPARE(actualDates, occurrenceDates);
2283 }
2284 } else {
2285 // Allow backend specific limitations
2286 QCOMPARE(cm->error(), QOrganizerManager::NotSupportedError);
2287 qWarning() << "The event not supported by the backend";
2288 }
2289}
2290
2291void tst_QOrganizerManager::todoRecurrenceWithGenerator_data()
2292{
2293 recurrenceWithGenerator_data();
2294}
2295
2296// This is just a copy of recurrenceWithGenerator, but for todos, not events
2297void tst_QOrganizerManager::todoRecurrenceWithGenerator()
2298{
2299 QFETCH(QString, uri);
2300 QFETCH(QDate, generatorDate);
2301 QFETCH(QOrganizerRecurrenceRule, recurrenceRule);
2302 QFETCH(QOrganizerRecurrenceRule, exceptionRule);
2303 QFETCH(QSet<QDate>, recurrenceDates);
2304 QFETCH(QSet<QDate>, exceptionDates);
2305 QFETCH(QDate, startDate);
2306 QFETCH(QDate, endDate);
2307 QFETCH(QList<QDate>, occurrenceDates);
2308
2309 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
2310
2311 QOrganizerTodo todo;
2312 todo.setDisplayLabel("todo");
2313 todo.setStartDateTime(QDateTime(generatorDate, QTime(11, 0, 0)));
2314 todo.setDueDateTime(QDateTime(generatorDate, QTime(11, 30, 0)));
2315 todo.setRecurrenceRule(recurrenceRule);
2316 todo.setExceptionRule(exceptionRule);
2317 todo.setRecurrenceDates(recurrenceDates);
2318 todo.setExceptionDates(exceptionDates);
2319
2320 if (cm->saveItem(item: &todo)) {
2321 QList<QOrganizerItem> items = cm->itemOccurrences(parentItem: todo,
2322 startDateTime: QDateTime(startDate, QTime(0, 0, 0)),
2323 endDateTime: QDateTime(endDate, QTime(23, 59, 59, 999)));
2324
2325 QList<QDate> actualDates;
2326 for (int i = 0; i < items.size(); i++) {
2327 QOrganizerItem item = items.at(i);
2328 QCOMPARE(item.type(), QOrganizerItemType::TypeTodoOccurrence);
2329 QDate occurrenceDate = item.detail(detailType: QOrganizerItemDetail::TypeTodoTime).value(field: QOrganizerTodoTime::FieldStartDateTime).toDateTime().date();
2330 //QCOMPARE(occurrenceDate, occurrenceDates.at(i));
2331 actualDates << occurrenceDate;
2332 }
2333
2334 if (actualDates != occurrenceDates) {
2335 qDebug() << "Actual: " << actualDates;
2336 qDebug() << "Expected: " << occurrenceDates;
2337 QCOMPARE(actualDates, occurrenceDates);
2338 }
2339 } else {
2340 // Allow backend specific limitations
2341 QCOMPARE(cm->error(), QOrganizerManager::NotSupportedError);
2342 qWarning() << "The todo not supported by the backend";
2343 }
2344}
2345
2346void tst_QOrganizerManager::observerDeletion()
2347{
2348 QOrganizerManager *manager = new QOrganizerManager("memory");
2349 QOrganizerEvent c;
2350 QVERIFY(manager->saveItem(&c));
2351 QOrganizerItemId id = c.id();
2352 QOrganizerItemObserver *observer = new QOrganizerItemObserver(manager, id);
2353 Q_UNUSED(observer)
2354 delete manager;
2355 delete observer;
2356 // Test for bug MOBILITY-2566 - that QOrganizerItemObserver doesn't crash when it is
2357 // destroyed after the associated QOrganizerManager
2358}
2359
2360void tst_QOrganizerManager::signalEmission()
2361{
2362 QTest::qWait(ms: 500); // clear the signal queue
2363 QFETCH(QString, uri);
2364 QScopedPointer<QOrganizerManager> m1(QOrganizerManager::fromUri(uri));
2365
2366 qRegisterMetaType<QOrganizerItemId>(typeName: "QOrganizerItemId");
2367 qRegisterMetaType<QList<QOrganizerItemId> >(typeName: "QList<QOrganizerItemId>");
2368 qRegisterMetaType<QList<QOrganizerItemDetail::DetailType> >(typeName: "QList<QOrganizerItemDetail::DetailType>");
2369 QSignalSpy spyAdded(m1.data(), SIGNAL(itemsAdded(QList<QOrganizerItemId>)));
2370 QSignalSpy spyModified(m1.data(), SIGNAL(itemsChanged(QList<QOrganizerItemId>, QList<QOrganizerItemDetail::DetailType>)));
2371 QSignalSpy spyRemoved(m1.data(), SIGNAL(itemsRemoved(QList<QOrganizerItemId>)));
2372 QSignalSpy spyChanged(m1.data(), SIGNAL(dataChanged()));
2373
2374 QList<QVariant> args;
2375 QList<QOrganizerItemId> arg;
2376 QOrganizerTodo todo;
2377 QList<QOrganizerItem> batchAdd;
2378 QList<QOrganizerItemId> batchRemove;
2379 int addSigCount = 0; // the expected signal counts.
2380 int modSigCount = 0;
2381 int remSigCount = 0;
2382
2383 // verify add emits signal added
2384 QOrganizerItemDisplayLabel nc;
2385 nc.setLabel("label me this");
2386 QVERIFY(todo.saveDetail(&nc));
2387 QVERIFY(m1->saveItem(&todo));
2388 QOrganizerItemId cid = todo.id();
2389 QTRY_VERIFY(spyAdded.count() > addSigCount);
2390 ++addSigCount;
2391 args = spyAdded.takeFirst();
2392 --addSigCount;
2393 arg = args.first().value<QList<QOrganizerItemId> >();
2394 QVERIFY(arg.count() == 1);
2395 QCOMPARE(QOrganizerItemId(arg.at(0)), cid);
2396
2397 QScopedPointer<QOrganizerItemObserver> todo1Observer(new QOrganizerItemObserver(m1.data(), cid));
2398 QScopedPointer<QSignalSpy> spyObserverModified1(new QSignalSpy(todo1Observer.data(), SIGNAL(itemChanged(QList<QOrganizerItemDetail::DetailType>))));
2399 QScopedPointer<QSignalSpy> spyObserverRemoved1(new QSignalSpy(todo1Observer.data(), SIGNAL(itemRemoved())));
2400
2401 // verify save modified emits signal changed
2402 nc.setLabel("label me that");
2403 QVERIFY(todo.saveDetail(&nc));
2404 QVERIFY(m1->saveItem(&todo));
2405 QTRY_VERIFY(spyModified.count() > modSigCount);
2406 ++modSigCount;
2407 QTRY_VERIFY(spyObserverModified1->count() > 0);
2408 args = spyModified.takeFirst();
2409 --modSigCount;
2410 arg = args.first().value<QList<QOrganizerItemId> >();
2411 QVERIFY(arg.count() == 1);
2412 QCOMPARE(QOrganizerItemId(arg.at(0)), cid);
2413
2414 // verify remove emits signal removed
2415 QVERIFY(m1->removeItem(todo.id()));
2416 QTRY_VERIFY(spyRemoved.count() > remSigCount);
2417 QTRY_VERIFY(spyObserverRemoved1->count() > 0);
2418 args = spyRemoved.takeFirst();
2419 --remSigCount;
2420 arg = args.first().value<QList<QOrganizerItemId> >();
2421 QVERIFY(arg.count() == 1);
2422 QCOMPARE(QOrganizerItemId(arg.at(0)), cid);
2423
2424 // verify multiple adds works as advertised
2425 QOrganizerTodo todo2, todo3;
2426 QOrganizerItemDisplayLabel nc2, nc3;
2427 nc2.setLabel("Mark");
2428 nc3.setLabel("Garry");
2429 QVERIFY(todo2.saveDetail(&nc2));
2430 QVERIFY(todo3.saveDetail(&nc3));
2431 QVERIFY(m1->saveItem(&todo2));
2432 QVERIFY(m1->saveItem(&todo3));
2433 QTRY_COMPARE(spyModified.count(), modSigCount);
2434 QTRY_VERIFY(spyAdded.count() > addSigCount);
2435 addSigCount = spyAdded.count();
2436
2437 spyObserverModified1->clear();
2438 spyObserverRemoved1->clear();
2439 QScopedPointer<QOrganizerItemObserver> todo2Observer(new QOrganizerItemObserver(m1.data(), todo2.id()));
2440 QScopedPointer<QOrganizerItemObserver> todo3Observer(new QOrganizerItemObserver(m1.data(), todo3.id()));
2441 QScopedPointer<QSignalSpy> spyObserverModified2(new QSignalSpy(todo2Observer.data(), SIGNAL(itemChanged(QList<QOrganizerItemDetail::DetailType>))));
2442 QScopedPointer<QSignalSpy> spyObserverModified3(new QSignalSpy(todo3Observer.data(), SIGNAL(itemChanged(QList<QOrganizerItemDetail::DetailType>))));
2443 QScopedPointer<QSignalSpy> spyObserverRemoved2(new QSignalSpy(todo2Observer.data(), SIGNAL(itemRemoved())));
2444 QScopedPointer<QSignalSpy> spyObserverRemoved3(new QSignalSpy(todo3Observer.data(), SIGNAL(itemRemoved())));
2445
2446 // verify multiple modifies works as advertised
2447 nc2.setLabel("M.");
2448 QVERIFY(todo2.saveDetail(&nc2));
2449 QVERIFY(m1->saveItem(&todo2));
2450 nc2.setLabel("Mark");
2451 nc3.setLabel("G.");
2452 QVERIFY(todo2.saveDetail(&nc2));
2453 QVERIFY(todo3.saveDetail(&nc3));
2454 QVERIFY(m1->saveItem(&todo2));
2455 QVERIFY(m1->saveItem(&todo3));
2456 QTRY_VERIFY(spyModified.count() > modSigCount);
2457 modSigCount = spyModified.count();
2458 QTRY_VERIFY(spyObserverModified2->count() > 0);
2459 QTRY_VERIFY(spyObserverModified3->count() > 0);
2460 QCOMPARE(spyObserverModified1->count(), 0);
2461
2462 // verify multiple removes works as advertised
2463 m1->removeItem(itemId: todo3.id());
2464 m1->removeItem(itemId: todo2.id());
2465 QTRY_VERIFY(spyRemoved.count() > remSigCount);
2466 remSigCount = spyRemoved.count();
2467 QTRY_VERIFY(spyObserverRemoved2->count() > 0);
2468 QTRY_VERIFY(spyObserverRemoved3->count() > 0);
2469 QCOMPARE(spyObserverRemoved1->count(), 0);
2470
2471 QVERIFY(!m1->removeItem(todo.id())); // not saved.
2472
2473 /* Now test the batch equivalents */
2474 spyAdded.clear();
2475 spyModified.clear();
2476 spyRemoved.clear();
2477
2478 /* Batch adds - set ids to zero so add succeeds. */
2479 todo.setId(QOrganizerItemId());
2480 todo2.setId(QOrganizerItemId());
2481 todo3.setId(QOrganizerItemId());
2482 batchAdd << todo << todo2 << todo3;
2483 QMap<int, QOrganizerManager::Error> errorMap;
2484 QVERIFY(m1->saveItems(&batchAdd));
2485 errorMap = m1->errorMap();
2486
2487 QVERIFY(batchAdd.count() == 3);
2488 todo = batchAdd.at(i: 0);
2489 todo2 = batchAdd.at(i: 1);
2490 todo3 = batchAdd.at(i: 2);
2491
2492 // We want to see one itemsAdded signal listing the id's for all three items
2493 QTRY_COMPARE(spyAdded.count(), 1);
2494 {
2495 QList<QOrganizerItemId> sigids = spyAdded.takeFirst().at(i: 0).value<QList<QOrganizerItemId> >();
2496 QVERIFY(sigids.contains(todo.id()));
2497 QVERIFY(sigids.contains(todo2.id()));
2498 QVERIFY(sigids.contains(todo3.id()));
2499 }
2500 QTRY_COMPARE(spyModified.count(), 0);
2501
2502 todo1Observer.reset(other: new QOrganizerItemObserver(m1.data(), todo.id()));
2503 todo2Observer.reset(other: new QOrganizerItemObserver(m1.data(), todo2.id()));
2504 todo3Observer.reset(other: new QOrganizerItemObserver(m1.data(), todo3.id()));
2505 spyObserverModified1.reset(other: new QSignalSpy(todo1Observer.data(), SIGNAL(itemChanged(QList<QOrganizerItemDetail::DetailType>))));
2506 spyObserverModified2.reset(other: new QSignalSpy(todo2Observer.data(), SIGNAL(itemChanged(QList<QOrganizerItemDetail::DetailType>))));
2507 spyObserverModified3.reset(other: new QSignalSpy(todo3Observer.data(), SIGNAL(itemChanged(QList<QOrganizerItemDetail::DetailType>))));
2508 spyObserverRemoved1.reset(other: new QSignalSpy(todo1Observer.data(), SIGNAL(itemRemoved())));
2509 spyObserverRemoved2.reset(other: new QSignalSpy(todo2Observer.data(), SIGNAL(itemRemoved())));
2510 spyObserverRemoved3.reset(other: new QSignalSpy(todo3Observer.data(), SIGNAL(itemRemoved())));
2511 QTRY_COMPARE(spyRemoved.count(), 0);
2512
2513 /* Batch modifies */
2514 QOrganizerItemDisplayLabel modifiedName = todo.detail(detailType: QOrganizerItemDetail::TypeDisplayLabel);
2515 modifiedName.setLabel("Modified number 1");
2516 modifiedName = todo2.detail(detailType: QOrganizerItemDetail::TypeDisplayLabel);
2517 modifiedName.setLabel("Modified number 2");
2518 modifiedName = todo3.detail(detailType: QOrganizerItemDetail::TypeDisplayLabel);
2519 modifiedName.setLabel("Modified number 3");
2520
2521 batchAdd.clear();
2522 batchAdd << todo << todo2 << todo3;
2523 QVERIFY(m1->saveItems(&batchAdd));
2524 errorMap = m1->errorMap();
2525
2526 // We want to see one itemsChanged signal listing the id's for all three items.
2527 QTRY_COMPARE(spyModified.count(), 1);
2528 {
2529 QList<QOrganizerItemId> sigids = spyModified.takeFirst().at(i: 0).value<QList<QOrganizerItemId> >();
2530 QVERIFY(sigids.contains(todo.id()));
2531 QVERIFY(sigids.contains(todo2.id()));
2532 QVERIFY(sigids.contains(todo3.id()));
2533 }
2534 QTRY_COMPARE(spyObserverModified1->count(), 1);
2535 QTRY_COMPARE(spyObserverModified2->count(), 1);
2536 QTRY_COMPARE(spyObserverModified3->count(), 1);
2537
2538 /* Batch removes */
2539 batchRemove << todo.id() << todo2.id() << todo3.id();
2540 QVERIFY(m1->removeItems(batchRemove));
2541 errorMap = m1->errorMap();
2542
2543 // We want to see one itemsRemoved signal listing the id's for all three items.
2544 QTRY_COMPARE(spyRemoved.count(), 1);
2545 {
2546 QList<QOrganizerItemId> sigids = spyRemoved.takeFirst().at(i: 0).value<QList<QOrganizerItemId> >();
2547 QVERIFY(sigids.contains(todo.id()));
2548 QVERIFY(sigids.contains(todo2.id()));
2549 QVERIFY(sigids.contains(todo3.id()));
2550 }
2551 QTRY_COMPARE(spyObserverRemoved1->count(), 1);
2552 QTRY_COMPARE(spyObserverRemoved2->count(), 1);
2553 QTRY_COMPARE(spyObserverRemoved3->count(), 1);
2554
2555 QTRY_COMPARE(spyAdded.count(), 0);
2556 QTRY_COMPARE(spyModified.count(), 0);
2557
2558 /* Now some cross manager testing */
2559 if (m1->managerName() == QStringLiteral("memory"))
2560 QSKIP("Not supported by memory back-end");
2561
2562 spyAdded.clear();
2563 spyModified.clear();
2564 spyRemoved.clear();
2565 spyChanged.clear();
2566
2567
2568 // verify that signals are emitted for modifications made to other managers (same id).
2569 QScopedPointer<QOrganizerManager> m2(QOrganizerManager::fromUri(uri));
2570
2571 // add one new item
2572 QOrganizerEvent newEvent;
2573 newEvent.setStartDateTime(QDateTime::currentDateTime());
2574 newEvent.setEndDateTime(QDateTime::currentDateTime());
2575 newEvent.setDisplayLabel(QStringLiteral("a new event"));
2576
2577 QVERIFY(m2->saveItem(&newEvent));
2578 QTRY_VERIFY(spyChanged.count() || (spyAdded.count() > 0));
2579
2580 spyAdded.clear();
2581 spyModified.clear();
2582 spyRemoved.clear();
2583 spyChanged.clear();
2584
2585 // modify the item
2586 newEvent.setEndDateTime(QDateTime::currentDateTime().addDays(days: 1));
2587
2588 QVERIFY(m2->saveItem(&newEvent));
2589 QTRY_VERIFY(spyChanged.count() || (spyModified.count() > 0));
2590
2591 spyAdded.clear();
2592 spyModified.clear();
2593 spyRemoved.clear();
2594 spyChanged.clear();
2595
2596 // remove the item
2597 QVERIFY(m2->removeItem(newEvent.id()));
2598 QTRY_VERIFY(spyChanged.count() || (spyRemoved.count() > 0));
2599
2600 spyAdded.clear();
2601 spyModified.clear();
2602 spyRemoved.clear();
2603 spyChanged.clear();
2604
2605 // add several new items
2606 QOrganizerEvent moreEvents[10];
2607 for (int i = 0; i < 10; ++i) {;
2608 moreEvents[i].setStartDateTime(QDateTime::currentDateTime());
2609 moreEvents[i].setEndDateTime(QDateTime::currentDateTime());
2610 moreEvents[i].setDisplayLabel(QStringLiteral("yet another event"));
2611
2612 QVERIFY(m2->saveItem(&moreEvents[i]));
2613 }
2614 QTRY_VERIFY(spyChanged.count() || (spyAdded.count() > 0));
2615
2616 spyAdded.clear();
2617 spyModified.clear();
2618 spyRemoved.clear();
2619 spyChanged.clear();
2620
2621 // modify several items
2622 for (int i = 0; i < 10; ++i) {
2623 moreEvents[i].setEndDateTime(QDateTime::currentDateTime().addDays(days: i + 1));
2624 QVERIFY(m2->saveItem(&moreEvents[i]));
2625 }
2626 QTRY_VERIFY(spyChanged.count() || (spyModified.count() > 0));
2627
2628 spyAdded.clear();
2629 spyModified.clear();
2630 spyRemoved.clear();
2631 spyChanged.clear();
2632
2633 // remove several items
2634 for (int i = 0; i < 10; ++i)
2635 QVERIFY(m2->removeItem(moreEvents[i].id()));
2636 QTRY_VERIFY(spyChanged.count() || (spyRemoved.count() > 0));
2637
2638 spyChanged.clear();
2639
2640 QSignalSpy spyCollectionAdded(m1.data(), SIGNAL(collectionsAdded(QList<QOrganizerCollectionId>)));
2641 QSignalSpy spyCollectionModified(m1.data(), SIGNAL(collectionsChanged(QList<QOrganizerCollectionId>)));
2642 QSignalSpy spyCollectionRemoved(m1.data(), SIGNAL(collectionsRemoved(QList<QOrganizerCollectionId>)));
2643
2644 // add one collection
2645 QOrganizerCollection newCollection;
2646 newCollection.setMetaData(key: QOrganizerCollection::KeyName, value: QVariant(QStringLiteral("a new collection")));
2647
2648 QVERIFY(m2->saveCollection(&newCollection));
2649 QTRY_VERIFY(spyChanged.count() || (spyCollectionAdded.count() > 0));
2650
2651 spyCollectionAdded.clear();
2652 spyCollectionModified.clear();
2653 spyCollectionRemoved.clear();
2654 spyChanged.clear();
2655
2656 // modify one collection
2657 newCollection.setMetaData(key: QOrganizerCollection::KeyName, value: QVariant(QStringLiteral("a new collection, modified")));
2658
2659 QVERIFY(m2->saveCollection(&newCollection));
2660 QTRY_VERIFY(spyChanged.count() || (spyCollectionModified.count() > 0));
2661
2662 spyCollectionAdded.clear();
2663 spyCollectionModified.clear();
2664 spyCollectionRemoved.clear();
2665 spyChanged.clear();
2666
2667 // remove one collection
2668 QVERIFY(m2->removeCollection(newCollection.id()));
2669 QTRY_VERIFY(spyChanged.count() || (spyCollectionRemoved.count() > 0));
2670}
2671
2672void tst_QOrganizerManager::errorStayingPut()
2673{
2674 /* Make sure that when we clone a manager, we don't clone the error */
2675 QMap<QString, QString> params;
2676 params.insert(akey: "id", avalue: "error isolation test");
2677 QOrganizerManager m1("memory",params);
2678
2679 QVERIFY(m1.error() == QOrganizerManager::NoError);
2680
2681 /* Remove an invalid item to get an error */
2682 QVERIFY(m1.removeItem(QOrganizerItemId()) == false);
2683 QVERIFY(m1.error() == QOrganizerManager::DoesNotExistError);
2684
2685 /* Create a new manager with hopefully the same backend */
2686 QOrganizerManager m2("memory", params);
2687
2688 QVERIFY(m1.error() == QOrganizerManager::DoesNotExistError);
2689 QVERIFY(m2.error() == QOrganizerManager::NoError);
2690
2691 /* Cause an error on the other ones and check the first is not affected */
2692 m2.saveItems(items: 0);
2693 QVERIFY(m1.error() == QOrganizerManager::DoesNotExistError);
2694 QVERIFY(m2.error() == QOrganizerManager::BadArgumentError);
2695
2696 QOrganizerItem c;
2697 QOrganizerItemDetail d(QOrganizerItemDetail::TypeUndefined);
2698 d.setValue(field: 101, value: 5);
2699 c.saveDetail(detail: &d);
2700
2701// QVERIFY(m1.saveItem(&c) == false);
2702// QVERIFY(m1.error() == QOrganizerManager::InvalidDetailError);
2703 QVERIFY(m2.error() == QOrganizerManager::BadArgumentError);
2704}
2705
2706void tst_QOrganizerManager::changeSet()
2707{
2708 QOrganizerItemId id;
2709
2710 QOrganizerItemChangeSet changeSet;
2711 QVERIFY(changeSet.addedItems().isEmpty());
2712 QVERIFY(changeSet.changedItems().isEmpty());
2713 QVERIFY(changeSet.removedItems().isEmpty());
2714
2715 changeSet.insertAddedItem(itemId: id);
2716 QVERIFY(!changeSet.addedItems().isEmpty());
2717 QVERIFY(changeSet.changedItems().isEmpty());
2718 QVERIFY(changeSet.removedItems().isEmpty());
2719 QVERIFY(changeSet.addedItems().contains(id));
2720 changeSet.clearAddedItems();
2721 changeSet.insertAddedItems(itemIds: QList<QOrganizerItemId>() << id);
2722
2723 changeSet.insertChangedItem(itemId: id, typesChanged: QList<QOrganizerItemDetail::DetailType>());
2724 changeSet.insertChangedItems(itemIds: QList<QOrganizerItemId>() << id, typesChanged: QList<QOrganizerItemDetail::DetailType>());
2725 QCOMPARE(changeSet.changedItems().size(), 1); // set, should only be added once.
2726 QCOMPARE(changeSet.changedItems().first().second.size(), 1); // only one changed item ID
2727 QVERIFY(!changeSet.addedItems().isEmpty());
2728 QVERIFY(!changeSet.changedItems().isEmpty());
2729 QVERIFY(changeSet.removedItems().isEmpty());
2730
2731 changeSet.clearChangedItems();
2732 changeSet.insertChangedItems(itemIds: QList<QOrganizerItemId>() << id, typesChanged: QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeDescription);
2733 changeSet.insertChangedItems(itemIds: QList<QOrganizerItemId>() << id, typesChanged: QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeTag);
2734 QCOMPARE(changeSet.changedItems().size(), 2); // should be added twice with differing change types
2735 QVERIFY(!changeSet.addedItems().isEmpty());
2736 QVERIFY(!changeSet.changedItems().isEmpty());
2737 QVERIFY(changeSet.removedItems().isEmpty());
2738 QSet<QOrganizerItemId> changedIds;
2739 QSet<QOrganizerItemDetail::DetailType> changedTypes;
2740 foreach (const QOrganizerItemChangeSet::ItemChangeList &changes, changeSet.changedItems()) {
2741 changedIds |= changes.second.toSet();
2742 if (changes.second.contains(t: id)) {
2743 changedTypes |= changes.first.toSet();
2744 }
2745 }
2746 QCOMPARE(changedIds, (QList<QOrganizerItemId>() << id).toSet());
2747 QCOMPARE(changedTypes, (QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeDescription << QOrganizerItemDetail::TypeTag).toSet());
2748 changeSet.clearChangedItems();
2749 QVERIFY(changeSet.changedItems().isEmpty());
2750
2751 QList<QOrganizerItemId> l1, l2;
2752 foreach (int n, QList<int>() << 1 << 1 << 1 << 2 << 2 << 3 << 3 << 4 << 4 << 4 << 5 << 10 << 9 << 8 << 8 << 8 << 7 << 7 << 6) {
2753 ((qrand() % 2) ? l1 : l2).append(t: makeItemId(id: n));
2754 }
2755 changeSet.clearChangedItems();
2756 changeSet.insertChangedItems(itemIds: l1, typesChanged: QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeDescription << QOrganizerItemDetail::TypeTag);
2757 changeSet.insertChangedItems(itemIds: l2, typesChanged: QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeTag << QOrganizerItemDetail::TypeDescription << QOrganizerItemDetail::TypeTag);
2758 QCOMPARE(changeSet.changedItems().size(), 1);
2759 QList<QOrganizerItemId> expected((l1.toSet() | l2.toSet()).toList());
2760 qSort(c&: expected);
2761 QCOMPARE(changeSet.changedItems().first().second, expected);
2762
2763 changeSet.insertRemovedItems(itemIds: QList<QOrganizerItemId>() << id);
2764 QVERIFY(changeSet.removedItems().contains(id));
2765 changeSet.clearRemovedItems();
2766 QVERIFY(changeSet.removedItems().isEmpty());
2767
2768 QVERIFY(changeSet.dataChanged() == false);
2769 QOrganizerItemChangeSet changeSet2;
2770 changeSet2 = changeSet;
2771 QVERIFY(changeSet.addedItems() == changeSet2.addedItems());
2772 changeSet.emitSignals(engine: 0);
2773
2774 changeSet2.clearAddedItems();
2775 QVERIFY(changeSet2.addedItems().isEmpty());
2776 changeSet2.insertAddedItems(itemIds: changeSet.addedItems().toList());
2777 QVERIFY(changeSet.addedItems() == changeSet2.addedItems());
2778
2779 changeSet2.clearAll();
2780 QVERIFY(changeSet.addedItems() != changeSet2.addedItems());
2781
2782 QOrganizerItemChangeSet changeSet3(changeSet2);
2783 QVERIFY(changeSet.addedItems() != changeSet3.addedItems());
2784 QVERIFY(changeSet2.addedItems() == changeSet3.addedItems());
2785
2786 changeSet.setDataChanged(true);
2787 QVERIFY(changeSet.dataChanged() == true);
2788 QVERIFY(changeSet.dataChanged() != changeSet2.dataChanged());
2789 QVERIFY(changeSet.dataChanged() != changeSet3.dataChanged());
2790 changeSet.emitSignals(engine: 0);
2791
2792 QOrganizerCollectionId colId;
2793
2794 QOrganizerCollectionChangeSet colChangeSet;
2795 QVERIFY(colChangeSet.addedCollections().isEmpty());
2796 QVERIFY(colChangeSet.changedCollections().isEmpty());
2797 QVERIFY(colChangeSet.removedCollections().isEmpty());
2798
2799 colChangeSet.insertAddedCollection(collectionId: colId);
2800 QVERIFY(!changeSet.addedItems().isEmpty());
2801 QVERIFY(colChangeSet.changedCollections().isEmpty());
2802 QVERIFY(colChangeSet.removedCollections().isEmpty());
2803 QVERIFY(colChangeSet.addedCollections().contains(colId));
2804 colChangeSet.clearAddedCollections();
2805 colChangeSet.insertAddedCollections(collectionIds: QList<QOrganizerCollectionId>() << colId);
2806
2807 colChangeSet.insertChangedCollection(collectionId: colId);
2808 colChangeSet.insertChangedCollections(collectionIds: QList<QOrganizerCollectionId>() << colId);
2809 QVERIFY(colChangeSet.changedCollections().size() == 1); // set, should only be added once.
2810 QVERIFY(!colChangeSet.addedCollections().isEmpty());
2811 QVERIFY(!colChangeSet.changedCollections().isEmpty());
2812 QVERIFY(colChangeSet.removedCollections().isEmpty());
2813 QVERIFY(colChangeSet.changedCollections().contains(colId));
2814 colChangeSet.clearChangedCollections();
2815 QVERIFY(colChangeSet.changedCollections().isEmpty());
2816
2817 colChangeSet.insertRemovedCollections(collectionIds: QList<QOrganizerCollectionId>() << colId);
2818 QVERIFY(colChangeSet.removedCollections().contains(colId));
2819 colChangeSet.clearRemovedCollections();
2820 QVERIFY(colChangeSet.removedCollections().isEmpty());
2821
2822 QVERIFY(colChangeSet.dataChanged() == false);
2823 QOrganizerCollectionChangeSet colChangeSet2;
2824 colChangeSet2 = colChangeSet;
2825 QVERIFY(colChangeSet.addedCollections() == colChangeSet2.addedCollections());
2826 colChangeSet.emitSignals(engine: 0);
2827
2828 colChangeSet2.clearAddedCollections();
2829 QVERIFY(colChangeSet2.addedCollections().isEmpty());
2830 colChangeSet2.insertAddedCollections(collectionIds: colChangeSet.addedCollections().toList());
2831 QVERIFY(colChangeSet.addedCollections() == colChangeSet2.addedCollections());
2832
2833 colChangeSet2.clearAll();
2834 QVERIFY(colChangeSet.addedCollections() != colChangeSet2.addedCollections());
2835
2836 QOrganizerCollectionChangeSet colChangeSet3(colChangeSet2);
2837 QVERIFY(colChangeSet.addedCollections() != colChangeSet3.addedCollections());
2838 QVERIFY(colChangeSet2.addedCollections() == colChangeSet3.addedCollections());
2839
2840 colChangeSet.setDataChanged(true);
2841 QVERIFY(colChangeSet.dataChanged() == true);
2842 QVERIFY(colChangeSet.dataChanged() != colChangeSet2.dataChanged());
2843 QVERIFY(colChangeSet.dataChanged() != colChangeSet3.dataChanged());
2844 colChangeSet.emitSignals(engine: 0);
2845}
2846
2847void tst_QOrganizerManager::fetchHint()
2848{
2849 QOrganizerItemFetchHint hint;
2850 hint.setOptimizationHints(QOrganizerItemFetchHint::NoBinaryBlobs);
2851 QCOMPARE(hint.optimizationHints(), QOrganizerItemFetchHint::NoBinaryBlobs);
2852}
2853
2854void tst_QOrganizerManager::testFilterFunction()
2855{
2856 QOrganizerEvent item;
2857 item.setId(makeItemId(id: 10));
2858 item.setStartDateTime(QDateTime(QDate(2010,10,10), QTime(10,10)));
2859 item.setEndDateTime(QDateTime(QDate(2010,10,10), QTime(12,10)));
2860 item.setDisplayLabel("test");
2861 item.setCollectionId(makeCollectionId(id: 1));
2862
2863 // Test for QOrganizerItemFilter::InvalidFilter
2864 QOrganizerItemInvalidFilter fif;
2865 QVERIFY(!QOrganizerManagerEngine::testFilter(fif, item));
2866
2867 // Test for QOrganizerItemFilter::IdFilter:
2868 QOrganizerItemIdFilter fidf;
2869 fidf.setIds(QList<QOrganizerItemId>() << makeItemId(id: 10));
2870 QVERIFY(QOrganizerManagerEngine::testFilter(fidf, item));
2871
2872 // test for nonexistent id
2873 fidf.setIds(QList<QOrganizerItemId>() << makeItemId(id: 11));
2874 QVERIFY(!QOrganizerManagerEngine::testFilter(fidf, item));
2875
2876 // Test for QOrganizerItemFilter::DefaultFilter:
2877 QOrganizerItemFilter fdf;
2878 QVERIFY(fdf.type() == QOrganizerItemFilter::DefaultFilter);
2879 QVERIFY(QOrganizerManagerEngine::testFilter(fdf, item));
2880
2881 // Test for QOrganizerItemFilter::OrganizerItemDetailFieldFilter:
2882 QOrganizerItemDetailFieldFilter fdef;
2883 fdef.setDetail(detailType: QOrganizerItemDetail::TypeDisplayLabel, field: QOrganizerItemDisplayLabel::FieldLabel);
2884 fdef.setValue("invalid");
2885 // test for nonexistent label
2886 QVERIFY(!QOrganizerManagerEngine::testFilter(fdef, item));
2887
2888 fdef.setValue("test");
2889 // test for existent label
2890 QVERIFY(QOrganizerManagerEngine::testFilter(fdef, item));
2891
2892 // Test for QOrganizerItemFilter::OrganizerItemDetailRangeFilter:
2893 QOrganizerItemDetailRangeFilter fdrf;
2894 fdrf.setDetail(detailType: QOrganizerItemDetail::TypeEventTime, field: QOrganizerEventTime::FieldStartDateTime);
2895 fdrf.setRange(min: QDateTime(QDate(2010,10,9)), max: QDateTime(QDate(2010,10,11)));
2896 // test for a valid range
2897 QVERIFY(QOrganizerManagerEngine::testFilter(fdrf, item));
2898
2899 fdrf.setRange(min: QDateTime(QDate(2010,10,11)), max: QDateTime(QDate(2010,10,12)));
2900 // test for item not in the range
2901 QVERIFY(!QOrganizerManagerEngine::testFilter(fdrf, item));
2902
2903 // Test for QOrganizerItemFilter::IntersectionFilter:
2904 QOrganizerItemIntersectionFilter oiif;
2905 oiif.setFilters(QList<QOrganizerItemFilter>() << fif << fdf);
2906 // check for an invalid filter and default filter intersection
2907 QVERIFY(!QOrganizerManagerEngine::testFilter(oiif, item));
2908
2909 oiif.setFilters(QList<QOrganizerItemFilter>() << fdef << fdf);
2910 // check for a detail filter and default filter intersection
2911 QVERIFY(QOrganizerManagerEngine::testFilter(oiif, item));
2912
2913 // Test for QOrganizerItemFilter::UnionFilter:
2914 QOrganizerItemUnionFilter oiuf;
2915 oiuf.setFilters(QList<QOrganizerItemFilter>() << fif << fdf);
2916 // check for an invalid filter and default filter union
2917 QVERIFY(QOrganizerManagerEngine::testFilter(oiuf, item));
2918
2919 oiuf.setFilters(QList<QOrganizerItemFilter>() << fdef << fdf);
2920 // check for a detail filter and default filter union
2921 QVERIFY(QOrganizerManagerEngine::testFilter(oiuf, item));
2922
2923 // Test for QOrganizerItemFilter::CollectionFilter:
2924 QOrganizerItemCollectionFilter oicf;
2925 oicf.setCollectionId(makeCollectionId(id: 1));
2926 // check for existing collection id
2927 QVERIFY(QOrganizerManagerEngine::testFilter(oicf, item));
2928
2929 oicf.setCollectionId(makeCollectionId(id: 2));
2930 // check for nonexisting collection id
2931 QVERIFY(!QOrganizerManagerEngine::testFilter(oicf, item));
2932}
2933
2934
2935void tst_QOrganizerManager::dataSerialization()
2936{
2937 QFETCH(QString, uri);
2938 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
2939
2940 QOrganizerEvent event;
2941 event.setDisplayLabel("event");
2942 event.setStartDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 0, 0)));
2943 event.setEndDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 30, 0)));
2944
2945 if (cm->saveItem(item: &event)) {
2946 QByteArray buffer;
2947 QDataStream outBufferStream(&buffer, QIODevice::WriteOnly);
2948 outBufferStream << event.id().toString();
2949 QVERIFY(buffer.length() > 0);
2950
2951 QDataStream inBufferStream(buffer);
2952 QString inString;
2953 inBufferStream >> inString;
2954 QOrganizerItemId id = QOrganizerItemId::fromString(idString: inString);
2955
2956 QVERIFY(id == event.id());
2957 }
2958}
2959
2960void tst_QOrganizerManager::itemFilterFetch()
2961{
2962 // Some of the tests present on itemFetch()-tests, but this test extends the cases a bit
2963 // Preparations
2964 QFETCH(QString, uri);
2965 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
2966 QOrganizerItemExtendedDetail extDetail;
2967 QOrganizerItemComment comment;
2968 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
2969 for (int i=0; i<6; i++) {
2970 QOrganizerEvent event;
2971 event.setDisplayLabel(QString("event %1").arg(a: i));
2972 event.setStartDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 0, 0)));
2973 event.setEndDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 30, 0)));
2974 if (i==0) {
2975 // 1
2976 event.setPriority(QOrganizerItemPriority::VeryLowPriority);
2977 } else if (i==1) {
2978 // 2
2979 comment.setComment("my comment");
2980 event.saveDetail(detail: &comment);
2981 } else if (i==2) {
2982 // 3
2983 QOrganizerItemDisplayLabel label;
2984 label.setLabel("my 3rd event!");
2985 event.saveDetail(detail: &label);
2986 } else if (i==3) {
2987 // 4
2988 QOrganizerItemDisplayLabel label;
2989 label.setLabel("my 4th event!");
2990 event.saveDetail(detail: &label);
2991 } else if (i==4) {
2992 // 5
2993 event.setEndDateTime(QDateTime(QDate(2010, 10, 10), QTime(11, 0, 0)));
2994 } else if (i==5) {
2995 // 6
2996 extDetail.setName("DetailOfMine");
2997 extDetail.setData(42);
2998 event.saveDetail(detail: &extDetail);
2999 }
3000 QVERIFY(cm->saveItem(&event));
3001 }
3002 QCOMPARE(cm->items().count(), 6);
3003
3004 // DetailFieldFilter Checks
3005 QOrganizerItemDetailFieldFilter dFieldFilter;
3006 // 1
3007 dFieldFilter.setDetail(detailType: QOrganizerItemDetail::TypePriority, field: QOrganizerItemPriority::FieldPriority);
3008 dFieldFilter.setValue(QOrganizerItemPriority::VeryHighPriority);
3009 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 0);
3010 dFieldFilter.setValue(QOrganizerItemPriority::VeryLowPriority);
3011 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 1);
3012 // 2
3013 dFieldFilter.setDetail(detailType: QOrganizerItemDetail::TypeComment, field: QOrganizerItemComment::FieldComment);
3014 dFieldFilter.setValue("my comment");
3015 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 1);
3016 // 3-4
3017 dFieldFilter.setDetail(detailType: QOrganizerItemDetail::TypeDisplayLabel, field: QOrganizerItemDisplayLabel::FieldLabel);
3018 dFieldFilter.setValue("my 3rd event!");
3019 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 1);
3020 dFieldFilter.setMatchFlags(QOrganizerItemFilter::MatchEndsWith);
3021 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 1);
3022 dFieldFilter.setValue("event!");
3023 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 2);
3024 dFieldFilter.setValue("event");
3025 dFieldFilter.setMatchFlags(QOrganizerItemFilter::MatchContains);
3026 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), cm->items().count());
3027 dFieldFilter.setValue("my");
3028 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 2);
3029 dFieldFilter.setMatchFlags(QOrganizerItemFilter::MatchStartsWith);
3030 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 2);
3031 dFieldFilter.setValue("event");
3032 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 4);
3033 // 5
3034 dFieldFilter.setMatchFlags(QOrganizerItemFilter::MatchExactly);
3035 dFieldFilter.setDetail(detailType: QOrganizerItemDetail::TypeEventTime, field: QOrganizerEventTime::FieldEndDateTime);
3036 dFieldFilter.setValue(QDateTime(QDate(2010, 10, 10), QTime(11, 0, 0)));
3037 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 1);
3038 // 6
3039 dFieldFilter.setDetail(detailType: QOrganizerItemDetail::TypeExtendedDetail, field: QOrganizerItemExtendedDetail::FieldName);
3040 dFieldFilter.setValue("DetailOfMine");
3041 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFieldFilter).count(), 1);
3042
3043 // DetailFilter Checks
3044 if (cm->managerName() == QStringLiteral("memory")) {
3045 QOrganizerItemDetailFilter dFilter;
3046 // 1
3047 QOrganizerItemPriority priority;
3048 priority.setPriority(QOrganizerItemPriority::VeryHighPriority);
3049 dFilter.setDetail(priority);
3050 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 0);
3051 priority.setPriority(QOrganizerItemPriority::VeryLowPriority);
3052 dFilter.setDetail(priority);
3053 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 1);
3054 // 2
3055 dFilter.setDetail(comment);
3056 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 1);
3057 // 3-4
3058 QOrganizerItemDisplayLabel displayLabel;
3059 displayLabel.setLabel(QStringLiteral("my 3rd event!"));
3060 dFilter.setDetail(displayLabel);
3061 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 1);
3062 displayLabel.setLabel(QStringLiteral("my non existing event!"));
3063 dFilter.setDetail(displayLabel);
3064 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 0);
3065 // 5
3066 QOrganizerEventTime eventTime;
3067 eventTime.setEndDateTime(QDateTime(QDate(2010, 10, 10), QTime(11, 0, 0)));
3068 eventTime.setStartDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 0, 0)));
3069 dFilter.setDetail(eventTime);
3070 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 1);
3071 // 6
3072 dFilter.setDetail(extDetail);
3073 QCOMPARE(cm->items(QDateTime(), QDateTime(), dFilter).count(), 1);
3074 }
3075
3076}
3077
3078void tst_QOrganizerManager::itemFetch()
3079{
3080 QFETCH(QString, uri);
3081 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3082
3083 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3084
3085 QOrganizerEvent event;
3086 event.setDisplayLabel("event");
3087 event.setStartDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 0, 0)));
3088 event.setEndDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 30, 0)));
3089 QVERIFY(cm->saveItem(&event));
3090
3091 QOrganizerEvent recEvent;
3092 recEvent.setDisplayLabel("daily event");
3093 recEvent.setStartDateTime(QDateTime(QDate(2010, 9, 1), QTime(16, 0, 0)));
3094 recEvent.setEndDateTime(QDateTime(QDate(2010, 9, 1), QTime(16, 30, 0)));
3095 QOrganizerRecurrenceRule rrule;
3096 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
3097 rrule.setLimit(QDate(2010, 9, 10));
3098 recEvent.setRecurrenceRule(rrule);
3099 QVERIFY(cm->saveItem(&recEvent));
3100
3101 //fetch all recurrences
3102 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2010, 9, 8)), endDateTime: QDateTime(QDate(2010, 9, 12)));
3103 QCOMPARE(items.count(), 4); // should return event + 3 x occurrencesOfRecEvent
3104
3105 //fetch only the originating items
3106 items = cm->itemsForExport(startDateTime: QDateTime(QDate(2010, 9, 8)), endDateTime: QDateTime(QDate(2010, 9, 12)),
3107 filter: QOrganizerItemFilter(), sortOrders: QList<QOrganizerItemSortOrder>(), fetchHint: QOrganizerItemFetchHint());
3108 QCOMPARE(items.count(), 2);
3109
3110 // test semantics of items():
3111 // first - save event with multiple occurrences; call items() -- should get back just occurrences.
3112 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3113 rrule.setLimit(QDate(2010, 9, 3));
3114 recEvent.setRecurrenceRule(rrule);
3115 recEvent.setId(QOrganizerItemId());
3116 cm->saveItem(item: &recEvent);
3117 items = cm->items();
3118 QCOMPARE(items.count(), 3);
3119 foreach (const QOrganizerItem &item, items)
3120 QVERIFY(item.type() == QOrganizerItemType::TypeEventOccurrence);
3121
3122 // second - the same situation, but giving a time span that only covers the first day - should get back a single occurrence.
3123 items = cm->items(startDateTime: QDateTime(QDate(2010, 9, 1), QTime(15, 0, 0)), endDateTime: QDateTime(QDate(2010, 9, 1), QTime(18, 0, 0)));
3124 QCOMPARE(items.count(), 1);
3125 foreach (const QOrganizerItem& item, items) {
3126 QVERIFY(item.type() == QOrganizerItemType::TypeEventOccurrence);
3127 }
3128
3129 // third - save event with no recurrence; call items() -- should get back that parent, not an occurrence.
3130 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3131 recEvent.setRecurrenceRules(QSet<QOrganizerRecurrenceRule>()); // clear rrule.
3132 recEvent.setId(QOrganizerItemId());
3133 cm->saveItem(item: &recEvent);
3134 items = cm->items();
3135 QCOMPARE(items.count(), 1);
3136 foreach (const QOrganizerItem &item, items)
3137 QVERIFY(item.type() == QOrganizerItemType::TypeEvent);
3138
3139 // fourth - the same situation, but giving a time span. should still get back the parent.
3140 items = cm->items(startDateTime: QDateTime(QDate(2010, 9, 1), QTime(15, 0, 0)), endDateTime: QDateTime(QDate(2010, 9, 1), QTime(18, 0, 0)));
3141 QCOMPARE(items.count(), 1);
3142 foreach (const QOrganizerItem &item, items)
3143 QVERIFY(item.type() == QOrganizerItemType::TypeEvent);
3144
3145 // test semantics of itemsForExport():
3146 // first - save event with multiple occurrences; call ife() -- get back that parent
3147 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3148 recEvent.setRecurrenceRule(rrule);
3149 recEvent.setId(QOrganizerItemId());
3150 cm->saveItem(item: &recEvent);
3151 items = cm->itemsForExport();
3152 QCOMPARE(items.count(), 1);
3153 foreach (const QOrganizerItem& item, items) {
3154 QVERIFY(item.type() == QOrganizerItemType::TypeEvent);
3155 }
3156
3157 // second - call items, resave only the first occurrence as an exception,
3158 // call ife() -- get back parent + exception
3159 items = cm->items();
3160 QCOMPARE(items.size(), 3); // 3 occurrences.
3161 int eventCount = 0;
3162 int eventOccurrenceCount = 0;
3163 foreach (const QOrganizerItem& item, items) {
3164 if (item.type() == QOrganizerItemType::TypeEventOccurrence) {
3165 if (eventOccurrenceCount == 0) {
3166 QOrganizerEventOccurrence exception(item);
3167 exception.setDisplayLabel("exception");
3168 QVERIFY(cm->saveItem(&exception));
3169 }
3170 eventOccurrenceCount++;
3171 } else if (item.type() == QOrganizerItemType::TypeEvent) {
3172 eventCount++;
3173 }
3174 }
3175 QCOMPARE(eventOccurrenceCount, 3);
3176 QCOMPARE(eventCount, 0);
3177 items = cm->items(); // reload items after saving exception
3178 QCOMPARE(items.size(), 3); // saving the exception shouldn't have added more items.
3179 items = cm->itemsForExport();
3180 QCOMPARE(items.count(), 2);
3181 eventCount = 0;
3182 eventOccurrenceCount = 0;
3183 foreach (const QOrganizerItem& item, items) {
3184 if (item.type() == QOrganizerItemType::TypeEvent) {
3185 eventCount += 1;
3186 } else if (item.type() == QOrganizerItemType::TypeEventOccurrence) {
3187 eventOccurrenceCount += 1;
3188 }
3189 QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
3190 }
3191 QCOMPARE(eventCount, 1);
3192 QCOMPARE(eventOccurrenceCount, 1);
3193
3194 //make a parent filter and test item count
3195 QOrganizerItemDetailFieldFilter dff;
3196 dff.setDetail(detailType: QOrganizerItemDetail::TypeParent, field: QOrganizerItemParent::FieldParentId);
3197 dff.setValue(QVariant::fromValue(value: recEvent.id()));
3198 QCOMPARE(cm->items(QDateTime(), QDateTime(), dff).count(), 3);
3199 QCOMPARE(cm->itemsForExport(QDateTime(), QDateTime(), dff).count(), 2);
3200
3201 // third, have all occurrences persisted
3202 items = cm->items();
3203 QCOMPARE(items.size(), 3); // should be three occurrences
3204 foreach (const QOrganizerItem& item, items) {
3205 if (item.type() == QOrganizerItemType::TypeEventOccurrence) {
3206 QOrganizerEventOccurrence exception(item);
3207 exception.setDisplayLabel("exception");
3208 QVERIFY(cm->saveItem(&exception));
3209 }
3210 }
3211 items = cm->itemsForExport();
3212 QCOMPARE(items.size(), 4); // parent + 3 persisted exceptions
3213 eventCount = 0;
3214 eventOccurrenceCount = 0;
3215 foreach (const QOrganizerItem& item, items) {
3216 if (item.type() == QOrganizerItemType::TypeEvent) {
3217 eventCount += 1;
3218 } else if (item.type() == QOrganizerItemType::TypeEventOccurrence) {
3219 eventOccurrenceCount += 1;
3220 }
3221 QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
3222 }
3223 QCOMPARE(eventCount, 1);
3224 QCOMPARE(eventOccurrenceCount, 3);
3225
3226 // fourth, all occurrences persisted, time period excludes parent item, but it's still fetched
3227 items = cm->itemsForExport(startDateTime: QDateTime(QDate(2010, 9, 2)),
3228 endDateTime: QDateTime(QDate(2010, 9, 4)));
3229 QCOMPARE(items.size(), 3); // parent + 2 persisted exceptions
3230 eventCount = 0;
3231 eventOccurrenceCount = 0;
3232 foreach (const QOrganizerItem& item, items) {
3233 if (item.type() == QOrganizerItemType::TypeEvent) {
3234 eventCount += 1;
3235 } else if (item.type() == QOrganizerItemType::TypeEventOccurrence) {
3236 eventOccurrenceCount += 1;
3237 }
3238 QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
3239 }
3240 QCOMPARE(eventCount, 1);
3241 QCOMPARE(eventOccurrenceCount, 2);
3242
3243
3244}
3245
3246// This is mostly a copy of itemFetch(), but for todos
3247void tst_QOrganizerManager::todoItemFetch()
3248{
3249 QFETCH(QString, uri);
3250 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3251 QList<QOrganizerItem> items;
3252 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3253
3254 QOrganizerTodo todoStartDueDate;
3255 todoStartDueDate.setDisplayLabel("todo startdue");
3256 todoStartDueDate.setStartDateTime(QDateTime(QDate(2011, 3, 27), QTime(11, 0, 0)));
3257 todoStartDueDate.setDueDateTime(QDateTime(QDate(2011, 3, 29), QTime(11, 30, 0)));
3258 QVERIFY(cm->saveItem(&todoStartDueDate));
3259
3260 QOrganizerTodo todoStartDate;
3261 todoStartDate.setDisplayLabel("todo start");
3262 todoStartDate.setStartDateTime(QDateTime(QDate(2011, 3, 25), QTime(11, 0, 0)));
3263 QVERIFY(cm->saveItem(&todoStartDate));
3264
3265 QOrganizerTodo todoDueDate;
3266 todoDueDate.setDisplayLabel("todo due");
3267 todoDueDate.setDueDateTime(QDateTime(QDate(2011, 3, 25), QTime(11, 30, 0)));
3268 QVERIFY(cm->saveItem(&todoDueDate));
3269
3270 QOrganizerTodo todoNoDate;
3271 todoNoDate.setDisplayLabel("todo nodate");
3272 QVERIFY(cm->saveItem(&todoNoDate));
3273
3274 items = cm->items();
3275 QCOMPARE(items.count(), 4);
3276
3277 items = cm->items(startDateTime: QDateTime(), endDateTime: QDateTime(QDate(2011, 3, 25), QTime(13, 0, 0)));
3278 QCOMPARE(items.count(), 2);
3279
3280 items = cm->items(startDateTime: QDateTime(), endDateTime: QDateTime(QDate(2011, 3, 25), QTime(11, 15, 0)));
3281 QCOMPARE(items.count(), 1);
3282
3283 items = cm->items(startDateTime: QDateTime(QDate(2011, 3, 27), QTime(10, 0, 0)), endDateTime: QDateTime());
3284 QCOMPARE(items.count(), 1);
3285
3286 items = cm->items(startDateTime: QDateTime(QDate(2011, 3, 29), QTime(13, 0, 0)), endDateTime: QDateTime());
3287 QCOMPARE(items.count(), 0);
3288
3289 items = cm->items(startDateTime: QDateTime(QDate(2011, 3, 26), QTime(11, 0, 0)),
3290 endDateTime: QDateTime(QDate(2011, 3, 28), QTime(11, 0, 0)));
3291 QCOMPARE(items.count(), 1);
3292
3293 items = cm->items(startDateTime: QDateTime(QDate(2011, 3, 28), QTime(11, 0, 0)),
3294 endDateTime: QDateTime(QDate(2011, 3, 30), QTime(11, 0, 0)));
3295 QCOMPARE(items.count(), 1);
3296
3297 items = cm->items(startDateTime: QDateTime(QDate(2011, 3, 28), QTime(11, 0, 0)),
3298 endDateTime: QDateTime(QDate(2011, 3, 28), QTime(11, 0, 0)));
3299 QCOMPARE(items.count(), 1);
3300
3301
3302 cm->removeItems(itemIds: cm->itemIds());
3303
3304 QOrganizerTodo todo;
3305 todo.setDisplayLabel("todo");
3306 todo.setStartDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 0, 0)));
3307 todo.setDueDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 30, 0)));
3308 QVERIFY(cm->saveItem(&todo));
3309
3310 QOrganizerTodo recTodo;
3311 recTodo.setDisplayLabel("daily todo");
3312 recTodo.setStartDateTime(QDateTime(QDate(2010, 9, 1), QTime(16, 0, 0)));
3313 recTodo.setDueDateTime(QDateTime(QDate(2010, 9, 1), QTime(16, 30, 0)));
3314 QOrganizerRecurrenceRule rrule;
3315 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
3316 rrule.setLimit(QDate(2010, 9, 10));
3317 recTodo.setRecurrenceRule(rrule);
3318 QVERIFY(cm->saveItem(&recTodo));
3319
3320 //fetch all recurrences
3321 items = cm->items(startDateTime: QDateTime(QDate(2010, 9, 8)), endDateTime: QDateTime(QDate(2010, 9, 12)));
3322 QCOMPARE(items.count(), 4); // should return todo + 3 x occurrencesOfRecTodo
3323
3324 //fetch only the originating items
3325 items = cm->itemsForExport(startDateTime: QDateTime(QDate(2010, 9, 8)), endDateTime: QDateTime(QDate(2010, 9, 12)),
3326 filter: QOrganizerItemFilter(), sortOrders: QList<QOrganizerItemSortOrder>(), fetchHint: QOrganizerItemFetchHint());
3327 QCOMPARE(items.count(), 2);
3328
3329 // test semantics of items():
3330 // first - save todo with multiple occurrences; call items() -- should get back just occurrences.
3331 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3332 rrule.setLimit(QDate(2010, 9, 3));
3333 recTodo.setRecurrenceRule(rrule);
3334 recTodo.setId(QOrganizerItemId());
3335 cm->saveItem(item: &recTodo);
3336 items = cm->items();
3337 QCOMPARE(items.count(), 3);
3338 foreach (const QOrganizerItem& item, items) {
3339 QVERIFY(item.type() == QOrganizerItemType::TypeTodoOccurrence);
3340 }
3341
3342 // second - the same situation, but giving a time span that only covers the first day - should get back a single occurrence.
3343 items = cm->items(startDateTime: QDateTime(QDate(2010, 9, 1), QTime(15, 0, 0)), endDateTime: QDateTime(QDate(2010, 9, 1), QTime(18, 0, 0)));
3344 QCOMPARE(items.count(), 1);
3345 foreach (const QOrganizerItem& item, items) {
3346 QVERIFY(item.type() == QOrganizerItemType::TypeTodoOccurrence);
3347 }
3348
3349 // third - save event with no recurrence; call items() -- should get back that parent, not an occurrence.
3350 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3351 recTodo.setRecurrenceRules(QSet<QOrganizerRecurrenceRule>()); // clear rrule.
3352 recTodo.setId(QOrganizerItemId());
3353 cm->saveItem(item: &recTodo);
3354 items = cm->items();
3355 QCOMPARE(items.count(), 1);
3356 foreach (const QOrganizerItem& item, items) {
3357 QVERIFY(item.type() == QOrganizerItemType::TypeTodo);
3358 }
3359
3360 // fourth - the same situation, but giving a time span. should still get back the parent.
3361 items = cm->items(startDateTime: QDateTime(QDate(2010, 9, 1), QTime(15, 0, 0)), endDateTime: QDateTime(QDate(2010, 9, 1), QTime(18, 0, 0)));
3362 QCOMPARE(items.count(), 1);
3363 foreach (const QOrganizerItem& item, items) {
3364 QVERIFY(item.type() == QOrganizerItemType::TypeTodo);
3365 }
3366
3367 // test semantics of itemsForExport():
3368 // first - save event with multiple occurrences; call ife() -- get back that parent
3369 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3370 recTodo.setRecurrenceRule(rrule);
3371 recTodo.setId(QOrganizerItemId());
3372 cm->saveItem(item: &recTodo);
3373 items = cm->itemsForExport();
3374 QCOMPARE(items.count(), 1);
3375 foreach (const QOrganizerItem& item, items) {
3376 QVERIFY(item.type() == QOrganizerItemType::TypeTodo);
3377 }
3378
3379 // second - call items, resave only the first occurrence as an exception,
3380 // call ife() -- get back parent + exception
3381 items = cm->items();
3382 int todoCount = 0;
3383 int todoOccurrenceCount = 0;
3384 foreach (const QOrganizerItem& item, items) {
3385 if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
3386 if (todoOccurrenceCount == 0) {
3387 QOrganizerTodoOccurrence exception(item);
3388 exception.setDisplayLabel("exception");
3389 QVERIFY(cm->saveItem(&exception));
3390 }
3391 todoOccurrenceCount++;
3392 } else if (item.type() == QOrganizerItemType::TypeTodo) {
3393 todoCount++;
3394 }
3395 }
3396 QCOMPARE(todoOccurrenceCount, 3);
3397 QCOMPARE(todoCount, 0);
3398 items = cm->itemsForExport();
3399 QCOMPARE(items.count(), 2);
3400 todoCount = 0;
3401 todoOccurrenceCount = 0;
3402 foreach (const QOrganizerItem& item, items) {
3403 if (item.type() == QOrganizerItemType::TypeTodo) {
3404 todoCount += 1;
3405 } else if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
3406 todoOccurrenceCount += 1;
3407 }
3408 QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
3409 }
3410 QCOMPARE(todoCount, 1);
3411 QCOMPARE(todoOccurrenceCount, 1);
3412
3413 // third, have all occurrences persisted
3414 items = cm->items();
3415 foreach (const QOrganizerItem& item, items) {
3416 if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
3417 QOrganizerTodoOccurrence exception(item);
3418 exception.setDisplayLabel("exception");
3419 QVERIFY(cm->saveItem(&exception));
3420 }
3421 }
3422 items = cm->itemsForExport();
3423 QCOMPARE(items.size(), 4);
3424 todoCount = 0;
3425 todoOccurrenceCount = 0;
3426 foreach (const QOrganizerItem& item, items) {
3427 if (item.type() == QOrganizerItemType::TypeTodo) {
3428 todoCount += 1;
3429 } else if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
3430 todoOccurrenceCount += 1;
3431 }
3432 QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
3433 }
3434 QCOMPARE(todoCount, 1);
3435 QCOMPARE(todoOccurrenceCount, 3);
3436}
3437
3438void tst_QOrganizerManager::itemFetchV2()
3439{
3440 QFETCH(QString, uri);
3441 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3442
3443 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3444
3445 QOrganizerEvent event1;
3446 event1.setDisplayLabel("event1");
3447 event1.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
3448 event1.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 30, 0)));
3449 QOrganizerRecurrenceRule rrule;
3450 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
3451 rrule.setLimit(QDate(2010, 1, 2));
3452 event1.setRecurrenceRule(rrule);
3453 QVERIFY(cm->saveItem(&event1));
3454
3455 QOrganizerEvent event2;
3456 event2.setDisplayLabel("event2");
3457 event2.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(13, 0, 0)));
3458 event2.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(13, 30, 0)));
3459 rrule = QOrganizerRecurrenceRule();
3460 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
3461 rrule.setLimit(QDate(2010, 1, 2));
3462 event2.setRecurrenceRule(rrule);
3463 QVERIFY(cm->saveItem(&event2));
3464
3465 // Get items without a maxCount, check that they're date sorted
3466 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)), endDateTime: QDateTime());
3467 QCOMPARE(items.size(), 4);
3468 QCOMPARE(items[0].displayLabel(), QStringLiteral("event1"));
3469 QCOMPARE(items[1].displayLabel(), QStringLiteral("event2"));
3470 QCOMPARE(items[2].displayLabel(), QStringLiteral("event1"));
3471 QCOMPARE(items[3].displayLabel(), QStringLiteral("event2"));
3472
3473 // Get the next 3 items from 2010-02-01
3474 items = cm->items(startDateTime: QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)),
3475 endDateTime: QDateTime(), // no end date limit
3476 filter: QOrganizerItemFilter(),
3477 maxCount: 3); // maxCount
3478 QCOMPARE(items.size(), 3);
3479 QCOMPARE(items[0].displayLabel(), QStringLiteral("event1"));
3480 QCOMPARE(items[1].displayLabel(), QStringLiteral("event2"));
3481 QCOMPARE(items[2].displayLabel(), QStringLiteral("event1"));
3482}
3483
3484void tst_QOrganizerManager::spanOverDays()
3485{
3486 QFETCH(QString, uri);
3487 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3488
3489 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3490
3491 QOrganizerEvent event;
3492 event.setDisplayLabel("huge event");
3493 event.setStartDateTime(QDateTime(QDate(2010, 8, 9), QTime(11, 0, 0)));
3494 event.setEndDateTime(QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3495 QVERIFY(cm->saveItem(&event));
3496
3497 // just fetch one day from the event
3498 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 9)),
3499 endDateTime: QDateTime(QDate(2010, 8, 9), QTime(23,59,59)));
3500 QCOMPARE(items.count(), 1);
3501
3502 // fetch the next day
3503 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 10), QTime(0,0,0)), endDateTime: QDateTime(QDate(2010, 8, 10), QTime(23,59,59)));
3504 QCOMPARE(items.count(), 1);
3505
3506 // fetch the last day
3507 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 11), QTime(0,0,0)), endDateTime: QDateTime(QDate(2010, 11, 10), QTime(23,59,59)));
3508 QCOMPARE(items.count(), 1);
3509
3510 // fetch an interval starting before the event until infinity
3511 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 5), QTime(0,0,0)), endDateTime: QDateTime());
3512 QCOMPARE(items.count(), 1);
3513
3514 // fetch an interval ending after the event
3515 items = cm->items(startDateTime: QDateTime(), endDateTime: QDateTime(QDate(2010, 12, 10), QTime(23,59,59)));
3516 QCOMPARE(items.count(), 1);
3517
3518 // fetch an interval starting before the event and ending at almost end of the year
3519 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 5), QTime(0,0,0)), endDateTime: QDateTime(QDate(2010, 12, 10), QTime(23,59,59)));
3520 QCOMPARE(items.count(), 1);
3521
3522 // fetch an interval ending in the middle of the event
3523 items = cm->items(startDateTime: QDateTime(), endDateTime: QDateTime(QDate(2010, 8, 10), QTime(23,59,59)));
3524 QCOMPARE(items.count(), 1);
3525
3526 // fetch an interval starting from the middle of the event until infinity
3527 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 10), QTime(0,0,0)), endDateTime: QDateTime());
3528 QCOMPARE(items.count(), 1);
3529
3530 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3531
3532 QOrganizerEvent event2;
3533 QOrganizerRecurrenceRule rrule;
3534 event2.setDisplayLabel("huge recurring event");
3535 event2.setStartDateTime(QDateTime(QDate(2010, 8, 9), QTime(11, 0, 0)));
3536 event2.setEndDateTime(QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3537 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
3538 rrule.setLimit(QDate(2010, 9, 2));
3539 event2.setRecurrenceRule(rrule);
3540 QVERIFY(cm->saveItem(&event2));
3541
3542 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 8)), endDateTime: QDateTime(QDate(2010, 9, 3)));
3543 QCOMPARE(items.count(), 4);
3544 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[0]).startDateTime(), QDateTime(QDate(2010, 8, 9), QTime(11, 0, 0)));
3545 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[0]).endDateTime(), QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3546 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[1]).startDateTime(), QDateTime(QDate(2010, 8, 16), QTime(11, 0, 0)));
3547 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[1]).endDateTime(), QDateTime(QDate(2010, 8, 18), QTime(11, 30, 0)));
3548 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[2]).startDateTime(), QDateTime(QDate(2010, 8, 23), QTime(11, 0, 0)));
3549 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[2]).endDateTime(), QDateTime(QDate(2010, 8, 25), QTime(11, 30, 0)));
3550 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[3]).startDateTime(), QDateTime(QDate(2010, 8, 30), QTime(11, 0, 0)));
3551 QCOMPARE(static_cast<QOrganizerEventOccurrence>(items[3]).endDateTime(), QDateTime(QDate(2010, 9, 1), QTime(11, 30, 0)));
3552
3553 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3554 QOrganizerTodo todo;
3555 QOrganizerRecurrenceRule rrule2;
3556 todo.setDisplayLabel("huge overlapping recurring todo");
3557 todo.setStartDateTime(QDateTime(QDate(2010, 8, 9), QTime(11, 0, 0)));
3558 todo.setDueDateTime(QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3559 rrule2.setFrequency(QOrganizerRecurrenceRule::Daily);
3560 rrule2.setLimit(4);
3561 todo.setRecurrenceRule(rrule2);
3562 QVERIFY(cm->saveItem(&todo));
3563
3564 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 8)), endDateTime: QDateTime(QDate(2010, 9, 3)));
3565 QCOMPARE(items.count(), 4);
3566 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[0]).startDateTime(), QDateTime(QDate(2010, 8, 9), QTime(11, 0, 0)));
3567 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[0]).dueDateTime(), QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3568 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[1]).startDateTime(), QDateTime(QDate(2010, 8, 10), QTime(11, 0, 0)));
3569 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[1]).dueDateTime(), QDateTime(QDate(2010, 8, 12), QTime(11, 30, 0)));
3570 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[2]).startDateTime(), QDateTime(QDate(2010, 8, 11), QTime(11, 0, 0)));
3571 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[2]).dueDateTime(), QDateTime(QDate(2010, 8, 13), QTime(11, 30, 0)));
3572 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[3]).startDateTime(), QDateTime(QDate(2010, 8, 12), QTime(11, 0, 0)));
3573 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[3]).dueDateTime(), QDateTime(QDate(2010, 8, 14), QTime(11, 30, 0)));
3574}
3575
3576
3577void tst_QOrganizerManager::incompleteTodoTime()
3578{
3579 QFETCH(QString, uri);
3580 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3581 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3582 QOrganizerTodo todo;
3583 QOrganizerRecurrenceRule rrule;
3584 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
3585 rrule.setLimit(4);
3586 todo.setDisplayLabel("recurring todo without start date");
3587 todo.setDueDateTime(QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3588 todo.setRecurrenceRule(rrule);
3589 QVERIFY(cm->saveItem(&todo));
3590
3591 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 8)), endDateTime: QDateTime(QDate(2010, 9, 3)));
3592 QCOMPARE(items.count(), 4);
3593 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[0]).dueDateTime(), QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3594 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[1]).dueDateTime(), QDateTime(QDate(2010, 8, 12), QTime(11, 30, 0)));
3595 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[2]).dueDateTime(), QDateTime(QDate(2010, 8, 13), QTime(11, 30, 0)));
3596 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[3]).dueDateTime(), QDateTime(QDate(2010, 8, 14), QTime(11, 30, 0)));
3597
3598 // same test as previous, but with date limit
3599 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3600 QOrganizerTodo todo2;
3601 todo2.setDisplayLabel("recurring todo without start date with date limit");
3602 todo2.setDueDateTime(QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3603 QOrganizerRecurrenceRule rrule2;
3604 rrule2.setFrequency(QOrganizerRecurrenceRule::Daily);
3605 rrule2.setLimit(QDate(2010, 8, 13));
3606 todo2.setRecurrenceRule(rrule2);
3607 QVERIFY(cm->saveItem(&todo2));
3608
3609 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 8)), endDateTime: QDateTime(QDate(2010, 9, 3)));
3610 QCOMPARE(items.count(), 3);
3611 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[0]).dueDateTime(), QDateTime(QDate(2010, 8, 11), QTime(11, 30, 0)));
3612 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[1]).dueDateTime(), QDateTime(QDate(2010, 8, 12), QTime(11, 30, 0)));
3613 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[2]).dueDateTime(), QDateTime(QDate(2010, 8, 13), QTime(11, 30, 0)));
3614
3615 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3616 QOrganizerTodo todo3;
3617 todo3.setDisplayLabel("recurring todo without start and due date");
3618 todo3.setRecurrenceRule(rrule2);
3619 QVERIFY(cm->saveItem(&todo3));
3620 items = cm->items();
3621 QCOMPARE(items.count(), 0);
3622 items = cm->items(startDateTime: QDateTime(QDate(2010, 8, 8)), endDateTime: QDateTime(QDate(2010, 9, 3)));
3623 QCOMPARE(items.count(), 6);
3624
3625 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[0]).originalDate(), QDate(2010, 8, 8));
3626 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[1]).originalDate(), QDate(2010, 8, 9));
3627 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[2]).dueDateTime(), QDateTime());
3628 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[3]).dueDateTime(), QDateTime());
3629 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[4]).originalDate(), QDate(2010, 8, 12));
3630 QCOMPARE(static_cast<QOrganizerTodoOccurrence>(items[5]).originalDate(), QDate(2010, 8, 13));
3631 cm->removeItem(itemId: todo3.id());
3632}
3633
3634void tst_QOrganizerManager::recurrence()
3635{
3636 QFETCH(QString, uri);
3637 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3638
3639 QOrganizerEvent event;
3640 event.setDisplayLabel("recurrent event");
3641 event.setStartDateTime(QDateTime(QDate(2012, 8, 9), QTime(11, 0, 0)));
3642 event.setEndDateTime(QDateTime(QDate(2012, 8, 9), QTime(11, 30, 0)));
3643
3644 // first, test count limiting.
3645 QOrganizerRecurrenceRule rrule;
3646 rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
3647 rrule.setLimit(3);
3648 event.setRecurrenceRule(rrule);
3649 QVERIFY(cm->saveItem(&event));
3650
3651 {
3652 // Fetch all events with occurrences
3653 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9)),
3654 endDateTime: QDateTime(QDate(2012, 8, 12), QTime(23,59,59)));
3655 QCOMPARE(items.count(), 3);
3656
3657 // Fetch events for the first day
3658 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 9), QTime(23,59,59)));
3659 QCOMPARE(items.count(), 1);
3660
3661 // Fetch events for the second day
3662 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 10), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 10), QTime(23,59,59)));
3663 QCOMPARE(items.count(), 1);
3664
3665 // Create an exception on the second day
3666 QOrganizerEventOccurrence ex = static_cast<QOrganizerEventOccurrence>(items.at(i: 0));
3667 ex.setStartDateTime(QDateTime(QDate(2012, 8, 10), QTime(10, 30, 0)));
3668 QVERIFY(cm->saveItem(&ex));
3669
3670 // Fetch again the events for the second day
3671 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 10), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 10), QTime(23,59,59)));
3672 QCOMPARE(items.count(), 1);
3673 QOrganizerItem item = items.at(i: 0);
3674 QVERIFY(!item.id().isNull());
3675 QVERIFY(item.type() == QOrganizerItemType::TypeEventOccurrence);
3676
3677 // Add a normal event to the first day
3678 QOrganizerEvent event2;
3679 event2.setDisplayLabel("event");
3680 event2.setStartDateTime(QDateTime(QDate(2012, 8, 9), QTime(15, 0, 0)));
3681 event2.setEndDateTime(QDateTime(QDate(2012, 8, 9), QTime(16, 0, 0)));
3682 QVERIFY(cm->saveItem(&event2));
3683
3684 // Fetch the whole period again
3685 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9)), endDateTime: QDateTime(QDate(2012, 8, 12), QTime(23,59,59)));
3686 QCOMPARE(items.count(), 4);
3687 foreach(QOrganizerItem item, items) {
3688 // check if the item is the recurrence exception
3689 if (item.id() == ex.id()) {
3690 QOrganizerEventOccurrence exc = static_cast<QOrganizerEventOccurrence>(item);
3691 QCOMPARE(exc.guid(), ex.guid());
3692 QCOMPARE(exc.startDateTime(), ex.startDateTime());
3693 QCOMPARE(exc.endDateTime(), ex.endDateTime());
3694 } else if (item.id() == event2.id()) {
3695 // check if the item is the normal event
3696 QOrganizerEvent ev = static_cast<QOrganizerEvent>(item);
3697 QCOMPARE(ev.guid(), event2.guid());
3698 QCOMPARE(ev.startDateTime(), event2.startDateTime());
3699 QCOMPARE(ev.endDateTime(), event2.endDateTime());
3700 } else {
3701 // item must be event occurrence type and has to be a generated one
3702 QVERIFY(item.type() == QOrganizerItemType::TypeEventOccurrence);
3703 QVERIFY(item.id().isNull());
3704 }
3705 }
3706
3707 // Fetch events on a day where the recurrence is no longer valid
3708 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 12), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 12), QTime(23,59,59)));
3709 QCOMPARE(items.count(), 0);
3710 }
3711
3712 //test for unlimited count limit
3713 //for bug:MOBILITY-2125
3714 cm->removeItems(itemIds: cm->itemIds());
3715 event.setId(QOrganizerItemId());
3716 rrule.setLimit(INT_MAX);
3717 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
3718 rrule.setInterval(4);
3719 rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Friday);
3720 event.setEndDateTime(QDateTime(QDate(2013, 8, 9), QTime(11, 30, 0)));
3721 event.setRecurrenceRule(rrule);
3722 QVERIFY(cm->saveItem(&event));
3723 {
3724 // Fetch all events with occurrences
3725 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9)),
3726 endDateTime: QDateTime(QDate(2013, 8, 12), QTime(23,59,59)));
3727 QVERIFY(items.count() > 1);
3728 }
3729 // second, test date limit. The results should be the same as the count limit, if the limit date is the 11th.
3730 cm->removeItems(itemIds: cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
3731 QOrganizerRecurrenceRule rrule2;
3732 rrule2.setFrequency(QOrganizerRecurrenceRule::Daily);
3733 rrule2.setLimit(QDate(2012, 8, 11));
3734 event.setRecurrenceRule(rrule2);
3735 event.setId(QOrganizerItemId());
3736 QVERIFY(cm->saveItem(&event));
3737
3738 {
3739 // Fetch all events with occurrences
3740 QList<QOrganizerItem> items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9)),
3741 endDateTime: QDateTime(QDate(2012, 8, 12), QTime(23,59,59)));
3742 QCOMPARE(items.count(), 3);
3743
3744 // Fetch events for the first day
3745 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 9), QTime(23,59,59)));
3746 QCOMPARE(items.count(), 1);
3747
3748 // Fetch events for the second day
3749 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 10), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 10), QTime(23,59,59)));
3750 QCOMPARE(items.count(), 1);
3751
3752 // Create an exception on the second day
3753 QOrganizerEventOccurrence ex = static_cast<QOrganizerEventOccurrence>(items.at(i: 0));
3754 ex.setStartDateTime(QDateTime(QDate(2012, 8, 10), QTime(10, 30, 0)));
3755 QVERIFY(cm->saveItem(&ex));
3756
3757 // Fetch again the events for the second day
3758 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 10), QTime(0,0,0)), endDateTime: QDateTime(QDate(2012, 8, 10), QTime(23,59,59)));
3759 QCOMPARE(items.count(), 1);
3760 QOrganizerItem item = items.at(i: 0);
3761 QVERIFY(!item.id().isNull());
3762 QVERIFY(item.type() == QOrganizerItemType::TypeEventOccurrence);
3763
3764 // Add a normal event to the first day
3765 QOrganizerEvent event2;
3766 event2.setDisplayLabel("event");
3767 event2.setStartDateTime(QDateTime(QDate(2012, 8, 9), QTime(15, 0, 0)));
3768 event2.setEndDateTime(QDateTime(QDate(2012, 8, 9), QTime(16, 0, 0)));
3769 QVERIFY(cm->saveItem(&event2));
3770
3771 // Fetch the whole period again
3772 items = cm->items(startDateTime: QDateTime(QDate(2012, 8, 9)), endDateTime: QDateTime(QDate(2012, 8, 12), QTime(23,59,59)));
3773 QCOMPARE(items.count(), 4);
3774 foreach(QOrganizerItem item, items) {
3775 // check if the item is the recurrence exception
3776 if (item.id() == ex.id()) {
3777 QOrganizerEventOccurrence exc = static_cast<QOrganizerEventOccurrence>(item);
3778 QCOMPARE(exc.guid(), ex.guid());
3779 QCOMPARE(exc.startDateTime(), ex.startDateTime());
3780 QCOMPARE(exc.endDateTime(), ex.endDateTime());
3781 } else if (item.id() == event2.id()) {
3782 // check if the item is the normal event
3783 QOrganizerEvent ev = static_cast<QOrganizerEvent>(item);
3784 QCOMPARE(ev.guid(), event2.guid());
3785 QCOMPARE(ev.startDateTime(), event2.startDateTime());
3786 QCOMPARE(ev.endDateTime(), event2.endDateTime());
3787 } else {
3788 // item must be event occurrence type and has to be a generated one
3789 QVERIFY(item.type() == QOrganizerItemType::TypeEventOccurrence);
3790 QVERIFY(item.id().isNull());
3791 }
3792 }
3793 }
3794}
3795
3796void tst_QOrganizerManager::idComparison()
3797{
3798 QFETCH(QString, uri);
3799 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3800
3801 // Can we run this test?
3802 if (!cm->supportedItemTypes().contains(t: QOrganizerItemType::TypeJournal)) {
3803 QSKIP("Backend not compatible with this test");
3804 // TODO: The test should be refactored so it could run on all platforms
3805 }
3806
3807 // delete all collections in the database so that we know there can be no interference from previous test runs.
3808 QList<QOrganizerCollection> allCollections = cm->collections();
3809 for (int i = 0; i < allCollections.size(); ++i) {
3810 QOrganizerCollectionId currentId = allCollections.at(i).id();
3811 if (currentId != cm->defaultCollectionId()) {
3812 cm->removeCollection(collectionId: currentId);
3813 }
3814 }
3815
3816 // step one: make a few items and collections to save (and harvest their ids)
3817 QOrganizerEvent e1;
3818 e1.setDescription("test event one");
3819 e1.setDisplayLabel("event one");
3820 e1.setStartDateTime(QDateTime::currentDateTime());
3821 e1.setEndDateTime(QDateTime::currentDateTime().addSecs(secs: 3600));
3822
3823 QOrganizerEvent e2;
3824 e2.setDescription("test event two");
3825 e2.setDisplayLabel("event two");
3826 e2.setStartDateTime(QDateTime::currentDateTime().addDays(days: 1));
3827 e2.setEndDateTime(QDateTime::currentDateTime().addDays(days: 1).addSecs(secs: 1800));
3828
3829 QOrganizerTodo t1;
3830 QOrganizerRecurrenceRule r1;
3831 r1.setFrequency(QOrganizerRecurrenceRule::Weekly);
3832 t1.setDisplayLabel("todo one");
3833 t1.setDescription("test todo one");
3834 t1.setDueDateTime(QDateTime::currentDateTime().addDays(days: 5));
3835 t1.setRecurrenceRule(r1);
3836
3837 QOrganizerCollection c1;
3838 c1.setMetaData(key: QOrganizerCollection::KeyName, value: "IdComparisonTest");
3839
3840 // step two: save and harvest the ids
3841 QVERIFY(cm->saveItem(&e1));
3842 QVERIFY(cm->saveItem(&e2));
3843 QVERIFY(cm->saveItem(&t1));
3844 QVERIFY(cm->saveCollection(&c1));
3845 QOrganizerItemId e1id = e1.id();
3846 QOrganizerItemId e2id = e2.id();
3847 QOrganizerItemId t1id = t1.id();
3848 QOrganizerCollectionId c1id = c1.id();
3849
3850 // step three: make some basic ids as controlled data for our unit test
3851 QOrganizerItemId biid1 = makeItemId(id: 5);
3852 QOrganizerItemId biid2 = makeItemId(id: 12);
3853 QOrganizerCollectionId bcid1 = makeCollectionId(id: 5);
3854 QOrganizerCollectionId bcid2 = makeCollectionId(id: 17);
3855 QOrganizerCollectionId bcid3 = makeCollectionId(id: 15);
3856
3857 // finally: do the testing.
3858 QVERIFY(biid1 != biid2);
3859 QVERIFY(bcid1 != bcid2);
3860
3861 QVERIFY(e1id != e2id);
3862 QVERIFY(e1id != t1id);
3863
3864 QList<QOrganizerItemId> idList;
3865 idList << e1id << t1id << biid1;
3866 QVERIFY(!idList.contains(biid2));
3867 QVERIFY(!idList.contains(e2id));
3868 QVERIFY(idList.contains(e1id));
3869 QVERIFY(idList.contains(t1id));
3870 QVERIFY(idList.contains(biid1));
3871
3872 QVERIFY(((bcid1 < bcid2) || (bcid2 < bcid1)) && (bcid1 != bcid2));
3873 QVERIFY(((bcid3 < bcid2) || (bcid3 < bcid1)) && (bcid3 != bcid2));
3874 QVERIFY(((e1id < e2id) || (e2id < e1id)) && (e1id != e2id));
3875
3876 // now we do some tests which might be unstable
3877 QVERIFY(bcid1 < c1id); // collectionIds: the first comparison should be manager uri, and bcid manager uri is early in the alphabet.
3878 QVERIFY(!(c1id < bcid1)); // collectionIds: ensure that less-than is consistent no matter which is on LHS or RHS.
3879 QVERIFY(biid2 < e1id); // itemIds: first comparison should be manager uri, and biid manager uri is early in the alphabet.
3880 QVERIFY(!(e1id < biid2)); // itemIds: ensure that less-than is consistent no matter which is on LHS or RHS.
3881
3882 // null testing
3883 QOrganizerItemId n1;
3884 QOrganizerItemId n2;
3885 QVERIFY(n1 == n2); // both null means they're equal
3886 QVERIFY(!(n1 < n2)); // not less than
3887 QVERIFY(!(n2 < n1)); // and not less than with LHS/RHS swapped.
3888
3889 QVERIFY(n1 < biid1); // null id is always less than any other id
3890 QVERIFY(!(biid1 < n1));
3891 QVERIFY(n2 < e2id);
3892 QVERIFY(!(e2id < n2));
3893
3894 QVERIFY(!idList.contains(n2));
3895 idList << n1;
3896 QVERIFY(idList.contains(n2)); // any two null ids are equal, so .contains should work.
3897
3898 QMap<QOrganizerItemId, int> testMap;
3899 testMap.insert(akey: e1id, avalue: 1);
3900 testMap.insert(akey: biid1, avalue: 12);
3901 testMap.insert(akey: biid2, avalue: 11);
3902 testMap.insert(akey: t1id, avalue: 6);
3903 testMap.insert(akey: n1, avalue: 12);
3904
3905 QCOMPARE(testMap.value(e1id), 1);
3906 QCOMPARE(testMap.value(n2), 12); // again, n1 == n2.
3907 QCOMPARE(testMap.value(biid1), 12);
3908 QCOMPARE(testMap.value(biid2), 11);
3909 QCOMPARE(testMap.value(t1id), 6);
3910 QCOMPARE(testMap.value(QOrganizerItemId()), 12); // again, n1 == null
3911
3912 QVERIFY(testMap.size() == 5);
3913 testMap.remove(akey: QOrganizerItemId());
3914 QVERIFY(testMap.size() == 4);
3915 QVERIFY(testMap.value(QOrganizerItemId()) != 12); // removed this entry.
3916}
3917
3918void tst_QOrganizerManager::emptyItemManipulation()
3919{
3920 QFETCH(QString, uri);
3921 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3922
3923 QOrganizerItem i;
3924 QOrganizerEvent e;
3925 QOrganizerTodo t;
3926
3927 // attempt to save an empty item
3928 if (cm->saveItem(item: &i)) {
3929 // if the backend allowed us to save it, it should definitely allow us to remove it again.
3930 QVERIFY(cm->removeItem(i.id()));
3931 } else {
3932 // if the backend didn't allow us to save it, there should be nothing to remove.
3933 QVERIFY(!cm->removeItem(i.id()));
3934 }
3935
3936 // attempt to save an empty event.
3937 if (cm->saveItem(item: &e)) {
3938 // if the backend allowed us to save it, it should definitely allow us to remove it again.
3939 QVERIFY(cm->removeItem(e.id()));
3940 } else {
3941 // if the backend didn't allow us to save it, there should be nothing to remove.
3942 QVERIFY(!cm->removeItem(e.id()));
3943 }
3944
3945 // attempt to save an empty event.
3946 if (cm->saveItem(item: &t)) {
3947 // if the backend allowed us to save it, it should definitely allow us to remove it again.
3948 QVERIFY(cm->removeItem(t.id()));
3949 } else {
3950 // if the backend didn't allow us to save it, there should be nothing to remove.
3951 QVERIFY(!cm->removeItem(t.id()));
3952 }
3953
3954 // now attempt to remove some invalid ids.
3955 QOrganizerItemId invalidId;
3956 QVERIFY(!cm->removeItem(invalidId)); // null id
3957 invalidId = makeItemId(id: 50);
3958 QVERIFY(!cm->removeItem(invalidId)); // id from different manager
3959}
3960
3961void tst_QOrganizerManager::partialSave()
3962{
3963 QFETCH(QString, uri);
3964 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
3965
3966 QList<QOrganizerItem> items;
3967 QOrganizerEvent event = QOrganizerEvent();
3968 event.setDisplayLabel("One");
3969 event.setStartDateTime(QDateTime(QDate(2010, 12, 25), QTime(1, 0, 0)));
3970 event.setEndDateTime(QDateTime(QDate(2010, 12, 25), QTime(1, 30, 0)));
3971 event.setDescription("One description");
3972 items.append(t: event);
3973
3974 event = QOrganizerEvent();
3975 event.setDisplayLabel("Two");
3976 event.setStartDateTime(QDateTime(QDate(2010, 12, 25), QTime(2, 0, 0)));
3977 event.setEndDateTime(QDateTime(QDate(2010, 12, 25), QTime(2, 30, 0)));
3978 event.setDescription("Two description");
3979 items.append(t: event);
3980
3981 event = QOrganizerEvent();
3982 event.setDisplayLabel("Three");
3983 event.setStartDateTime(QDateTime(QDate(2010, 12, 25), QTime(3, 0, 0)));
3984 event.setEndDateTime(QDateTime(QDate(2010, 12, 25), QTime(3, 30, 0)));
3985 items.append(t: event);
3986
3987 event = QOrganizerEvent();
3988 event.setDisplayLabel("Four");
3989 event.setStartDateTime(QDateTime(QDate(2010, 12, 25), QTime(4, 0, 0)));
3990 event.setEndDateTime(QDateTime(QDate(2010, 12, 25), QTime(4, 30, 0)));
3991 items.append(t: event);
3992
3993 // First save these items
3994 QVERIFY(cm->saveItems(&items));
3995 QList<QOrganizerItem> originalItems = items;
3996
3997 items[0].setDescription("One changed description");
3998
3999 // 0) empty mask == full save
4000 QVERIFY(cm->saveItems(&items));
4001
4002 // That should have updated everything
4003 QOrganizerItem a = cm->item(itemId: originalItems[0].id());
4004 QVERIFY(a.description() == "One changed description");
4005
4006 // 1) Change the description for b, mask it out
4007 items[1].setDescription("Two changed description");
4008 QVERIFY(cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeEventTime));
4009 QVERIFY(cm->errorMap().isEmpty());
4010
4011 QOrganizerItem b = cm->item(itemId: originalItems[1].id());
4012 QCOMPARE(b.description(), QString("Two description"));
4013
4014 // 2) save a modified detail in the mask
4015 items[1].setDescription("Two changed description");
4016
4017 QVERIFY(cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeDescription));
4018 QVERIFY(cm->errorMap().isEmpty());
4019 b = cm->item(itemId: originalItems[1].id());
4020 QCOMPARE(b.description(), QString("Two changed description"));
4021
4022 // 3) Remove a description
4023 QOrganizerItemDescription desc = items[1].detail(detailType: QOrganizerItemDetail::TypeDescription);
4024 QVERIFY(items[1].removeDetail(&desc));
4025 // Mask it out, so it shouldn't work.
4026 QVERIFY(cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeEventTime));
4027 QVERIFY(cm->errorMap().isEmpty());
4028 b = cm->item(itemId: originalItems[1].id());
4029 QCOMPARE(b.details(QOrganizerItemDetail::TypeDescription).count(), 1);
4030 // Now include it in the mask
4031 QVERIFY(cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeDescription));
4032 QVERIFY(cm->errorMap().isEmpty());
4033 b = cm->item(itemId: originalItems[1].id());
4034 QCOMPARE(b.details(QOrganizerItemDetail::TypeDescription).count(), 0);
4035
4036 // 4 - New item, no details in the mask
4037 QOrganizerItem newItem = originalItems[3];
4038 newItem.setId(QOrganizerItemId());
4039
4040 items.append(t: newItem); // this is items[4]
4041 QVERIFY(cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeTag));
4042 QVERIFY(cm->errorMap().isEmpty());
4043 QVERIFY(!items[4].id().isNull()); // Saved
4044 b = cm->item(itemId: items[4].id());
4045 QCOMPARE(b.details(QOrganizerItemDetail::TypeDisplayLabel).count(), 0); // not saved
4046 QCOMPARE(b.details(QOrganizerItemDetail::TypeEventTime).count(), 0); // not saved
4047
4048 // 5 - New item, some details in the mask
4049 newItem = originalItems[2];
4050 newItem.setId(QOrganizerItemId());
4051 items.append(t: newItem); // this is items[5]
4052 QVERIFY(cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeDisplayLabel));
4053 QVERIFY(cm->errorMap().isEmpty());
4054 QVERIFY(!items[5].id().isNull()); // Saved
4055 b = cm->item(itemId: items[5].id());
4056 QCOMPARE(b.details(QOrganizerItemDetail::TypeDisplayLabel).count(), 1);
4057 QCOMPARE(b.details(QOrganizerItemDetail::TypeEventTime).count(), 0); // not saved
4058
4059 // 6 Have a non existing item in the middle followed by a save error
4060 cm->removeItem(itemId: items[4].id());
4061 QOrganizerItemDetail badDetail(QOrganizerItemDetail::TypeUndefined);
4062 badDetail.setValue(field: 101, value: "BadValue");
4063 items[5].saveDetail(detail: &badDetail);
4064 QVERIFY(!cm->saveItems(&items, QList<QOrganizerItemDetail::DetailType>() << QOrganizerItemDetail::TypeUndefined));
4065 QMap<int, QOrganizerManager::Error> errorMap = cm->errorMap();
4066// QCOMPARE(errorMap.count(), 2);
4067 QCOMPARE(errorMap[4], QOrganizerManager::DoesNotExistError);
4068// QCOMPARE(errorMap[5], QOrganizerManager::InvalidDetailError);
4069}
4070
4071void tst_QOrganizerManager::dateRange()
4072{
4073 QFETCH(QOrganizerItem, item);
4074 QFETCH(QDateTime, startPeriod);
4075 QFETCH(QDateTime, endPeriod);
4076 QFETCH(bool, result);
4077 QCOMPARE(QOrganizerManagerEngine::isItemBetweenDates(item, startPeriod, endPeriod), result);
4078}
4079
4080void tst_QOrganizerManager::dateRange_data()
4081{
4082 QTest::addColumn<QOrganizerItem>(name: "item");
4083 QTest::addColumn<QDateTime>(name: "startPeriod");
4084 QTest::addColumn<QDateTime>(name: "endPeriod");
4085 QTest::addColumn<bool>(name: "result");
4086
4087 QOrganizerEvent ev;
4088 ev.setStartDateTime(QDateTime(QDate(2010, 10, 10), QTime(10,0,0)));
4089 ev.setEndDateTime(QDateTime(QDate(2010, 10, 12), QTime(11,0,0)));
4090
4091 QTest::newRow(dataTag: "event - month") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,1)) << QDateTime(QDate(2010,10,31)) << true;
4092 QTest::newRow(dataTag: "event - first day") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,10)) << QDateTime(QDate(2010,10,10), QTime(23,59,59)) << true;
4093 QTest::newRow(dataTag: "event - second day") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,11)) << QDateTime(QDate(2010,10,11), QTime(23,59,59)) << true;
4094 QTest::newRow(dataTag: "event - last day") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,12)) << QDateTime(QDate(2010,10,12), QTime(23,59,59)) << true;
4095 QTest::newRow(dataTag: "event - undefined period") << QOrganizerItem(ev) << QDateTime() << QDateTime() << true;
4096 QTest::newRow(dataTag: "event - undefined start") << QOrganizerItem(ev) << QDateTime() << QDateTime(QDate(2010,10,11)) << true;
4097 QTest::newRow(dataTag: "event - undefined end") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,11)) << QDateTime() << true;
4098 QTest::newRow(dataTag: "event - before") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,8)) << QDateTime(QDate(2010,10,9)) << false;
4099 QTest::newRow(dataTag: "event - after") << QOrganizerItem(ev) << QDateTime(QDate(2010,10,13)) << QDateTime(QDate(2010,10,14)) << false;
4100
4101 QOrganizerTodo todo;
4102 todo.setStartDateTime(QDateTime(QDate(2010, 10, 10), QTime(10,0,0)));
4103 todo.setDueDateTime(QDateTime(QDate(2010, 10, 12), QTime(11,0,0)));
4104
4105 QTest::newRow(dataTag: "todo - month") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,1)) << QDateTime(QDate(2010,10,31)) << true;
4106 QTest::newRow(dataTag: "todo - first day") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,10)) << QDateTime(QDate(2010,10,10), QTime(23,59,59)) << true;
4107 QTest::newRow(dataTag: "todo - second day") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,11)) << QDateTime(QDate(2010,10,11), QTime(23,59,59)) << true;
4108 QTest::newRow(dataTag: "todo - last day") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,12)) << QDateTime(QDate(2010,10,12), QTime(23,59,59)) << true;
4109 QTest::newRow(dataTag: "todo - undefined period") << QOrganizerItem(todo) << QDateTime() << QDateTime() << true;
4110 QTest::newRow(dataTag: "todo - undefined start") << QOrganizerItem(todo) << QDateTime() << QDateTime(QDate(2010,10,11)) << true;
4111 QTest::newRow(dataTag: "todo - undefined end") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,11)) << QDateTime() << true;
4112 QTest::newRow(dataTag: "todo - before") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,8)) << QDateTime(QDate(2010,10,9)) << false;
4113 QTest::newRow(dataTag: "todo - after") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,13)) << QDateTime(QDate(2010,10,14)) << false;
4114
4115 todo.setDueDateTime(QDateTime());
4116 QTest::newRow(dataTag: "todo missing due date - undefined start") << QOrganizerItem(todo) << QDateTime() << QDateTime(QDate(2010,10,11)) << true;
4117 QTest::newRow(dataTag: "todo missing due date - undefined end") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,10)) << QDateTime() << true;
4118
4119 todo.setStartDateTime(QDateTime());
4120 todo.setDueDateTime(QDateTime(QDate(2010, 10, 12), QTime(11,0,0)));
4121 QTest::newRow(dataTag: "todo missing start date - undefined start") << QOrganizerItem(todo) << QDateTime() << QDateTime(QDate(2010,10,13)) << true;
4122 QTest::newRow(dataTag: "todo missing start date - undefined end") << QOrganizerItem(todo) << QDateTime(QDate(2010,10,11)) << QDateTime() << true;
4123
4124 QOrganizerJournal journal;
4125 journal.setDateTime(QDateTime(QDate(2010, 10, 10), QTime(10,0,0)));
4126 QTest::newRow(dataTag: "journal - month") << QOrganizerItem(journal) << QDateTime(QDate(2010,10,1)) << QDateTime(QDate(2010,10,31)) << true;
4127 QTest::newRow(dataTag: "journal - first day") << QOrganizerItem(journal) << QDateTime(QDate(2010,10,10)) << QDateTime(QDate(2010,10,10), QTime(23,59,59)) << true;
4128 QTest::newRow(dataTag: "journal - second day") << QOrganizerItem(journal) << QDateTime(QDate(2010,10,11)) << QDateTime(QDate(2010,10,11), QTime(23,59,59)) << false;
4129 QTest::newRow(dataTag: "journal - undefined period") << QOrganizerItem(journal) << QDateTime() << QDateTime() << true;
4130 QTest::newRow(dataTag: "journal - undefined start") << QOrganizerItem(journal) << QDateTime() << QDateTime(QDate(2010,10,11)) << true;
4131 QTest::newRow(dataTag: "journal - undefined end") << QOrganizerItem(journal) << QDateTime(QDate(2010,10,10)) << QDateTime() << true;
4132 QTest::newRow(dataTag: "journal - before") << QOrganizerItem(journal) << QDateTime(QDate(2010,10,8)) << QDateTime(QDate(2010,10,9)) << false;
4133 QTest::newRow(dataTag: "journal - after") << QOrganizerItem(journal) << QDateTime(QDate(2010,10,13)) << QDateTime(QDate(2010,10,14)) << false;
4134
4135 QOrganizerNote note;
4136 QTest::newRow(dataTag: "note") << QOrganizerItem(note) << QDateTime(QDate(2010,10,1)) << QDateTime() << false;
4137 QTest::newRow(dataTag: "note - undefined period") << QOrganizerItem(note) << QDateTime() << QDateTime() << true;
4138}
4139
4140QList<QOrganizerItemDetail> tst_QOrganizerManager::removeAllDefaultDetails(const QList<QOrganizerItemDetail>& details)
4141{
4142 QList<QOrganizerItemDetail> newlist;
4143 foreach (const QOrganizerItemDetail d, details) {
4144 if (d.type() != QOrganizerItemDetail::TypeDisplayLabel
4145 && d.type() != QOrganizerItemDetail::TypeItemType
4146 && d.type() != QOrganizerItemDetail::TypeTimestamp) {
4147 newlist << d;
4148 }
4149 }
4150 return newlist;
4151}
4152
4153void tst_QOrganizerManager::detailOrders()
4154{
4155 QFETCH(QString, uri);
4156 QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
4157
4158 QOrganizerEvent a;
4159
4160 // comments
4161 QOrganizerItemComment comment1, comment2, comment3;
4162
4163 comment1.setComment("11111111");
4164 comment2.setComment("22222222");
4165 comment3.setComment("33333333");
4166
4167 a.saveDetail(detail: &comment1);
4168 a.saveDetail(detail: &comment2);
4169 a.saveDetail(detail: &comment3);
4170
4171 QVERIFY(cm->saveItem(&a));
4172 a = cm->item(itemId: a.id());
4173
4174 QList<QOrganizerItemDetail> details = a.details(detailType: QOrganizerItemDetail::TypeComment);
4175 QVERIFY(details.count() == 3);
4176
4177 comment2 = a.details(detailType: QOrganizerItemDetail::TypeComment).at(i: 1);
4178 QVERIFY(a.removeDetail(&comment2));
4179 QVERIFY(cm->saveItem(&a));
4180 a = cm->item(itemId: a.id());
4181 details = a.details(detailType: QOrganizerItemDetail::TypeComment);
4182 QVERIFY(details.count() == 2);
4183
4184 a.saveDetail(detail: &comment2);
4185 QVERIFY(cm->saveItem(&a));
4186 a = cm->item(itemId: a.id());
4187
4188 details = a.details(detailType: QOrganizerItemDetail::TypeComment);
4189 QVERIFY(details.count() == 3);
4190
4191 //addresses
4192 {
4193 QOrganizerItemLocation address1, address2, address3;
4194
4195 address1.setLabel("Brandl St");
4196 address3 = address2 = address1;
4197
4198 a.saveDetail(detail: &address1);
4199 a.saveDetail(detail: &address2);
4200 a.saveDetail(detail: &address3);
4201
4202 QVERIFY(cm->saveItem(&a));
4203 a = cm->item(itemId: a.id());
4204
4205 QList<QOrganizerItemDetail> details = a.details(detailType: QOrganizerItemDetail::TypeLocation);
4206 QVERIFY(details.count() == 1); // 1 location - they're unique
4207
4208 // Detail keys for the moment are not persistent through an item save / fetch
4209 address3 = details.at(i: 0);
4210
4211 QVERIFY(a.removeDetail(&address3)); // remove the most recent.
4212 QVERIFY(cm->saveItem(&a));
4213 a = cm->item(itemId: a.id());
4214 details = a.details(detailType: QOrganizerItemDetail::TypeLocation);
4215 QVERIFY(details.count() == 0); // unique, remove one means none left.
4216
4217 a.saveDetail(detail: &address2);
4218 QVERIFY(cm->saveItem(&a));
4219 a = cm->item(itemId: a.id());
4220
4221 details = a.details(detailType: QOrganizerItemDetail::TypeLocation);
4222 QVERIFY(details.count() == 1); // add one back.
4223 }
4224}
4225
4226void tst_QOrganizerManager::itemType()
4227{
4228 // XXX TODO!
4229}
4230
4231void tst_QOrganizerManager::collections()
4232{
4233 // XXX TODO: break test into smaller sub-tests (per operation).
4234
4235 QFETCH(QString, uri);
4236 QScopedPointer<QOrganizerManager> oim(QOrganizerManager::fromUri(uri));
4237
4238 // delete all collections in the database so that we know there can be no interference from previous test runs.
4239 QList<QOrganizerCollection> allCollections = oim->collections();
4240 for (int i = 0; i < allCollections.size(); ++i) {
4241 QOrganizerCollectionId currentId = allCollections.at(i).id();
4242 if (currentId != oim->defaultCollectionId()) {
4243 oim->removeCollection(collectionId: currentId);
4244 }
4245 }
4246
4247 QOrganizerCollection c1, c2, c3, sc1;
4248 c1.setMetaData(key: QOrganizerCollection::KeyName, value: "Test One");
4249 c1.setMetaData(key: QOrganizerCollection::KeyDescription, value: "This collection is for testing purposes.");
4250 c1.setExtendedMetaData(key: "key", value: "value");
4251 c2.setMetaData(key: QOrganizerCollection::KeyName, value: "Test Two");
4252 c2.setMetaData(key: QOrganizerCollection::KeyColor, value: QColor(Qt::blue));
4253 // c3 doesn't have any meta-data, just an id.
4254
4255 QOrganizerEvent i1, i2, i3, i4, i5;
4256 i1.setDisplayLabel("one");
4257 i2.setDisplayLabel("two");
4258 i2.setDescription("this is the second item");
4259 i3.setDisplayLabel("three");
4260 i4.setDisplayLabel("four");
4261 i4.setGuid(QUuid::createUuid().toString());
4262 i5.setDisplayLabel("five");
4263// i5.setLocation("test location address");
4264
4265 // modify default collection
4266 if (oim->managerName() != "memory") // modifying default collection is not allowed in memory engine
4267 {
4268 int initialCollectionCount = oim->collections().size();
4269 QOrganizerCollectionId defaultCollectionId = oim->defaultCollectionId();
4270 QOrganizerCollection defaultCollection = oim->collection(collectionId: defaultCollectionId);
4271 defaultCollection.setMetaData(key: QOrganizerCollection::KeyName, value: "NewName");
4272 QCOMPARE(defaultCollection.id(), defaultCollectionId);
4273 QVERIFY(oim->saveCollection(&defaultCollection));
4274 int finalCollectionCount = oim->collections().size();
4275 QCOMPARE(finalCollectionCount, initialCollectionCount);
4276 QCOMPARE(oim->collection(defaultCollectionId).metaData(QOrganizerCollection::KeyName).toString(), QString("NewName"));
4277 QCOMPARE(defaultCollection.id(), defaultCollectionId);
4278 }
4279
4280 // first test
4281 {
4282 // save a collection
4283 QVERIFY(c1.id().isNull()); // should have a null id to start with.
4284 QVERIFY(oim->saveCollection(&c1));
4285 QVERIFY(!c1.id().isNull()); // should have been set by the save operation
4286 QVERIFY(oim->collections().contains(c1));
4287 sc1 = oim->collection(collectionId: c1.id());
4288 QVERIFY(sc1.metaData(QOrganizerCollection::KeyName) == "Test One");
4289 QVERIFY(sc1.metaData(QOrganizerCollection::KeyDescription) == "This collection is for testing purposes.");
4290 QVERIFY(sc1.extendedMetaData("key") == "value");
4291
4292 // save an item in that collection
4293 QOrganizerItemCollectionFilter fil;
4294 fil.setCollectionId(c1.id());
4295 i1.setCollectionId(c1.id());
4296 QVERIFY(oim->saveItem(&i1));
4297 QVERIFY(i1.collectionId() == c1.id());
4298
4299 QList<QOrganizerItem> c1Items = oim->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: fil);
4300 int itemIndex = -1;
4301 for (int i = 0; i < c1Items.count(); i++) {
4302 if (c1Items.at(i).id() == i1.id()) {
4303 itemIndex = i;
4304 break;
4305 }
4306 }
4307 QVERIFY(itemIndex >= 0);
4308 QVERIFY(oim->items(QDateTime(), QDateTime(), fil).contains(i1) || isSuperset(c1Items.at(itemIndex), i1));
4309
4310 fil.setCollectionId(oim->defaultCollectionId());
4311 QVERIFY(!oim->items(QDateTime(), QDateTime(), fil).contains(i1)); // it should not be in the default collection.
4312 }
4313
4314 // second test
4315 {
4316 // save multiple collections. // XXX TODO: batch save for collections?
4317 int originalColCount = oim->collections().count();
4318 QVERIFY(oim->saveCollection(&c2));
4319 QVERIFY(oim->saveCollection(&c3));
4320 QVERIFY(oim->collections().count() == (originalColCount + 2));
4321
4322 // save i5 in c3 as a canary value.
4323 i5.setCollectionId(c3.id());
4324
4325 // save multiple items in collection c2
4326 QList<QOrganizerItem> saveList;
4327 i2.setCollectionId(c2.id());
4328 i3.setCollectionId(c2.id());
4329 i4.setCollectionId(c2.id());
4330 saveList << i2 << i3 << i4 << i5;
4331 int originalItemCount = oim->items().count();
4332 QVERIFY(oim->saveItems(&saveList));
4333 i2 = saveList.at(i: 0); // update from save list because manager might have added details / set ids etc.
4334 i3 = saveList.at(i: 1);
4335 i4 = saveList.at(i: 2);
4336 i5 = saveList.at(i: 3);
4337 QList<QOrganizerItem> fetchedItems = oim->items();
4338 QCOMPARE(fetchedItems.count(), originalItemCount + 4);
4339 //fails here
4340 QVERIFY(fetchedItems.contains(i2)); // these three should have been added
4341 QVERIFY(fetchedItems.contains(i3));
4342 QVERIFY(fetchedItems.contains(i4));
4343 QVERIFY(fetchedItems.contains(i5)); // i5 should not have been removed.
4344
4345 // update a collection shouldn't remove its items.
4346 c2.setMetaData(key: QOrganizerCollection::KeyName, value: "Test Two Updated");
4347 QVERIFY(oim->saveCollection(&c2));
4348 fetchedItems = oim->items();
4349 QVERIFY(fetchedItems.contains(i2)); // no items should have been removed
4350 QVERIFY(fetchedItems.contains(i3)); // nor should they have changed collection.
4351 QVERIFY(fetchedItems.contains(i4));
4352 QVERIFY(fetchedItems.contains(i5));
4353
4354 // exceptions must be saved in the same collection as their parent.
4355 QOrganizerEvent recurringEvent;
4356 recurringEvent.setDescription("A recurring test event parent.");
4357 // recurringEvent.setLocation("Some Location");
4358 recurringEvent.setStartDateTime(QDateTime(QDate(2010,10,5), QTime(10,30)));
4359 recurringEvent.setEndDateTime(QDateTime(QDate(2010,10,5), QTime(11,30)));
4360 QOrganizerRecurrenceRule rrule;
4361 rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
4362 rrule.setLimit(5); // count limited.
4363 recurringEvent.setRecurrenceRule(rrule);
4364 recurringEvent.setCollectionId(c2.id());
4365 QVERIFY(oim->saveItem(&recurringEvent));
4366 recurringEvent = oim->item(itemId: recurringEvent.id()); // reload it.
4367 QVERIFY(recurringEvent.collectionId() == c2.id());
4368 QList<QOrganizerItem> occ(oim->itemOccurrences(parentItem: recurringEvent, startDateTime: QDateTime(), endDateTime: QDateTime()));
4369 QVERIFY(occ.size() == 5);
4370 QOrganizerEventOccurrence someException = occ.at(i: 2); // there should be five, so this shouldn't segfault.
4371 // someException.setLocation("Other Location");
4372 someException.setCollectionId(c3.id()); // different to parent.
4373 QVERIFY(!oim->saveItem(&someException)); // shouldn't work.
4374 someException.setCollectionId(c2.id()); // same as parent.
4375 QVERIFY(oim->saveItem(&someException)); // should work.
4376
4377 // remove a collection, removes its items.
4378 QVERIFY(oim->removeCollection(c2.id()));
4379 fetchedItems = oim->items();
4380 QCOMPARE(fetchedItems.count(), originalItemCount + 1); // i5 should remain, i2->i4 should be removed.
4381 QVERIFY(!fetchedItems.contains(i2)); // these three should have been removed
4382 QVERIFY(!fetchedItems.contains(i3));
4383 QVERIFY(!fetchedItems.contains(i4));
4384 QVERIFY(!fetchedItems.contains(recurringEvent)); // the parent
4385 QVERIFY(!fetchedItems.contains(someException)); // and exceptions too.
4386 QVERIFY(fetchedItems.contains(i5)); // i5 should not have been removed.
4387
4388 // attempt to save an item in a non-existent collection should fail.
4389 i2.setId(QOrganizerItemId()); // reset Id so save can succeed...
4390 i2.setCollectionId(c2.id());
4391 QVERIFY(!oim->saveItem(&i2));
4392 fetchedItems = oim->items();
4393 QVERIFY(!fetchedItems.contains(i2)); // shouldn't have been added.
4394 QVERIFY(fetchedItems.contains(i5)); // i5 should not have been removed.
4395 }
4396}
4397
4398void tst_QOrganizerManager::testReminder()
4399{
4400 QFETCH(QString, uri);
4401 QScopedPointer<QOrganizerManager> oim(QOrganizerManager::fromUri(uri));
4402
4403 /*audible reminder test*/
4404 QOrganizerItemAudibleReminder audioReminder;
4405 QOrganizerEvent oi;
4406 oi.setDisplayLabel("test reminder");
4407 audioReminder.setRepetition(count: 3, delaySeconds: 100);
4408 QVERIFY(oi.saveDetail(&audioReminder));
4409 oi.setStartDateTime(QDateTime::currentDateTime());
4410 QVERIFY(oim->saveItem(&oi));
4411
4412 QList<QOrganizerItem> fetchedItems = oim->items();
4413 //After adding StartDateTime detail the item compare function does not work. Need fix later
4414 //QVERIFY(fetchedItems.contains(oi));
4415 foreach (QOrganizerItem item, fetchedItems) {
4416 if (oi.id() == item.id())
4417 QVERIFY(item.detail(QOrganizerItemDetail::TypeAudibleReminder) == audioReminder);
4418 }
4419
4420 //Test SecondsBeforeStart properties
4421 audioReminder.setSecondsBeforeStart(30); // reminder, 30 seconds before the item is due to start.
4422 QVERIFY(oi.saveDetail(&audioReminder));
4423 QVERIFY(oim->saveItem (&oi));
4424 fetchedItems = oim->items();
4425 //After adding StartDateTime detail the item compare function does not work. Need fix later
4426 //QVERIFY(fetchedItems.contains(oi));
4427 foreach (QOrganizerItem item, fetchedItems) {
4428 if (oi.id() == item.id())
4429 QVERIFY(item.detail(QOrganizerItemDetail::TypeAudibleReminder) == audioReminder);
4430 }
4431
4432 // update
4433 audioReminder.setSecondsBeforeStart(300);
4434 audioReminder.setDataUrl(QUrl("http://www.test.com"));
4435 QVERIFY(audioReminder.dataUrl() == QUrl("http://www.test.com"));
4436 QVERIFY(oi.detail(QOrganizerItemDetail::TypeAudibleReminder) != audioReminder);
4437 QVERIFY(oi.saveDetail(&audioReminder));
4438 QVERIFY(oi.details(QOrganizerItemDetail::TypeAudibleReminder).size() == 1); // should update, not add another
4439 QVERIFY(oi.detail(QOrganizerItemDetail::TypeAudibleReminder) == audioReminder);
4440 oim->saveItem (item: &oi);
4441 fetchedItems = oim->items();
4442 // After adding StartDateTime detail the item compare function does not work. Need fix later
4443 //QVERIFY(fetchedItems.contains(oi));
4444 foreach (QOrganizerItem item, fetchedItems) {
4445 if (oi.id() == item.id())
4446 QVERIFY(item.detail(QOrganizerItemDetail::TypeAudibleReminder) == audioReminder);
4447 }
4448
4449 // remove
4450 QVERIFY(oi.removeDetail(&audioReminder));
4451 QVERIFY(oi.details(QOrganizerItemDetail::TypeAudibleReminder).size() == 0);
4452 oim->saveItem (item: &oi);
4453 fetchedItems = oim->items();
4454 // After adding StartDateTime detail the item compare function does not work. Need fix later
4455 //QVERIFY(fetchedItems.contains(oi));
4456 foreach (QOrganizerItem item, fetchedItems) {
4457 if (oi.id() == item.id())
4458 QVERIFY(item.detail(QOrganizerItemDetail::TypeAudibleReminder) == oi.detail(QOrganizerItemDetail::TypeAudibleReminder));
4459 }
4460
4461 /*Email reminder test*/
4462 QOrganizerItemEmailReminder emailReminder;
4463 QOrganizerEvent emailEvent;
4464 QVERIFY(emailReminder.reminderType() == QOrganizerItemReminder::EmailReminder);
4465 emailReminder.setRepetition(count: 3, delaySeconds: 100);
4466
4467 QVERIFY(emailEvent.saveDetail(&emailReminder));
4468 QVERIFY(oim->saveItem (&emailEvent));
4469 fetchedItems = oim->items();
4470
4471 QVERIFY(fetchedItems.contains(emailEvent));
4472
4473 emailReminder.setSecondsBeforeStart(30); // reminder, 30 seconds before the item is due to start.
4474 QVERIFY(emailReminder.secondsBeforeStart() == 30);
4475 QVERIFY(emailEvent.saveDetail(&emailReminder));
4476 QVERIFY(oim->saveItem (&emailEvent));
4477 fetchedItems = oim->items();
4478 QVERIFY(fetchedItems.contains(emailEvent));
4479
4480 // update
4481 emailReminder.setSecondsBeforeStart(300);
4482 emailReminder.setContents(subject: "subject", body: "body", attachments: QVariantList());
4483 emailReminder.setRecipients(QStringList() << "recipient" << "other recipient");
4484 QVERIFY(emailReminder.subject() == QString("subject"));
4485 QVERIFY(emailReminder.body() == QString("body"));
4486 QVERIFY(emailReminder.attachments() == QVariantList());
4487 QVERIFY(emailReminder.recipients() == (QStringList() << "recipient" << "other recipient"));
4488 QVERIFY(emailEvent.detail(QOrganizerItemDetail::TypeEmailReminder) != emailReminder);
4489 QVERIFY(emailEvent.saveDetail(&emailReminder));
4490 oim->saveItem (item: &emailEvent);
4491 fetchedItems = oim->items();
4492
4493// dumpOrganizerItem (emailEvent);
4494// foreach (QOrganizerItem item, fetchedItems) {
4495// if (emailEvent.id() == item.id())
4496// dumpOrganizerItem (item);
4497// }
4498
4499 QVERIFY(fetchedItems.contains(emailEvent));
4500
4501 // remove
4502 QVERIFY(emailEvent.removeDetail(&emailReminder));
4503 QVERIFY(emailEvent.details(QOrganizerItemDetail::TypeEmailReminder).size() == 0);
4504 oim->saveItem (item: &emailEvent);
4505 fetchedItems = oim->items();
4506 QVERIFY(fetchedItems.contains(emailEvent));
4507
4508 /*Visual reminder test*/
4509 QOrganizerItemVisualReminder visualReminder;
4510 QOrganizerEvent visualEvent;
4511 QVERIFY(visualReminder.reminderType() == QOrganizerItemReminder::VisualReminder);
4512 visualReminder.setRepetition(count: 3, delaySeconds: 100);
4513
4514 QVERIFY(visualEvent.saveDetail(&visualReminder));
4515 QVERIFY(oim->saveItem (&visualEvent));
4516 fetchedItems = oim->items();
4517 QVERIFY(fetchedItems.contains(visualEvent));
4518
4519 visualReminder.setSecondsBeforeStart(30); // reminder, 30 seconds before the item is due to start.
4520 QVERIFY(visualReminder.secondsBeforeStart() == 30);
4521 QVERIFY(visualEvent.saveDetail(&visualReminder));
4522 QVERIFY(oim->saveItem (&visualEvent));
4523 fetchedItems = oim->items();
4524 QVERIFY(fetchedItems.contains(visualEvent));
4525
4526 // update
4527 visualReminder.setSecondsBeforeStart(300);
4528 visualReminder.setMessage("test");
4529 visualReminder.setDataUrl(QUrl("http://www.test.com"));
4530 QVERIFY(visualReminder.message() == QString("test"));
4531 QVERIFY(visualReminder.dataUrl() == QUrl("http://www.test.com"));
4532 QVERIFY(visualEvent.detail(QOrganizerItemDetail::TypeVisualReminder) != visualReminder);
4533 QVERIFY(visualEvent.saveDetail(&visualReminder));
4534 oim->saveItem (item: &visualEvent);
4535 fetchedItems = oim->items();
4536 QVERIFY(fetchedItems.contains(visualEvent));
4537
4538 // remove
4539 QVERIFY(visualEvent.removeDetail(&visualReminder));
4540 QVERIFY(visualEvent.details(QOrganizerItemDetail::TypeVisualReminder).size() == 0);
4541 oim->saveItem (item: &visualEvent);
4542 fetchedItems = oim->items();
4543 QVERIFY(fetchedItems.contains(visualEvent));
4544
4545 /*Event with more reminder*/
4546 QOrganizerEvent bigEvent;
4547 bigEvent.saveDetail(detail: &audioReminder);
4548 bigEvent.saveDetail(detail: &visualReminder);
4549 bigEvent.saveDetail(detail: &emailReminder);
4550 oim->saveItem (item: &bigEvent);
4551 fetchedItems = oim->items();
4552 QVERIFY(fetchedItems.contains(bigEvent));
4553
4554 // remove
4555 QVERIFY(bigEvent.removeDetail(&visualReminder));
4556 oim->saveItem (item: &bigEvent);
4557 fetchedItems = oim->items();
4558 QVERIFY(fetchedItems.contains(bigEvent));
4559}
4560
4561void tst_QOrganizerManager::testIntersectionFilter()
4562{
4563 QFETCH(QString, uri);
4564 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
4565
4566 // initialize db
4567 mgr->removeItems(itemIds: mgr->itemIds());
4568 QCOMPARE(mgr->items().count(), 0);
4569
4570 //prepare filter data
4571 QOrganizerCollection c1;
4572 QOrganizerCollection c2;
4573 mgr->saveCollection(collection: &c1);
4574 mgr->saveCollection(collection: &c2);
4575 QOrganizerItem event1;
4576 event1.setType(QOrganizerItemType::TypeEvent);
4577 QOrganizerItem event2;
4578 event2.setType(QOrganizerItemType::TypeEvent);
4579 event1.setCollectionId(c1.id());
4580 event2.setCollectionId(c2.id());
4581 mgr->saveItem(item: &event1);
4582 mgr->saveItem(item: &event2);
4583 //Test intersection filter with 2 different collection filter
4584 QOrganizerItemCollectionFilter cf1;
4585 cf1.setCollectionId(c1.id());
4586 QOrganizerItemCollectionFilter cf2;
4587 cf2.setCollectionId(c2.id());
4588 QOrganizerItemIntersectionFilter isf;
4589 isf.append(filter: cf1);
4590 isf.append(filter: cf2);
4591 QList<QOrganizerItem> itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: cf1);
4592 QCOMPARE(itemList.size(), 1);
4593 QCOMPARE(itemList.at(0), event1);
4594 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4595 QCOMPARE(itemList.size(), 0);
4596
4597 //Test intersection filter with 2 same collection filter
4598 isf.remove(filter: cf2);
4599 cf2.setCollectionId(c1.id());
4600 isf.append(filter: cf2);
4601 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4602 QCOMPARE(itemList.size(), 1);
4603
4604 //Test intersection filter with 2 collection filter and one of them is bigger than another
4605 isf.remove(filter: cf2);
4606 QSet<QOrganizerCollectionId> collectionList;
4607 collectionList << c1.id() << c2.id();
4608 cf2.setCollectionIds(collectionList);
4609 isf.append(filter: cf2);
4610 isf.append(filter: cf1);
4611 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4612 QCOMPARE(itemList.size(), 1);
4613
4614 //Bad case: one empty filter
4615 isf.remove(filter: cf2);
4616 cf2.setCollectionId(QOrganizerCollectionId());
4617 isf.append(filter: cf2);
4618 QCOMPARE(isf.filters().size(), 2);
4619 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4620 QCOMPARE(itemList.size(), 0);
4621
4622 //QOrganizerItemIdFilter test
4623 QOrganizerItemIdFilter idFilter;
4624 QList<QOrganizerItemId> ids;
4625 QOrganizerItem event3;
4626 event3.setType(QOrganizerItemType::TypeEvent);
4627 mgr->saveItem(item: &event3);
4628 ids << event1.id() << event3.id();
4629 idFilter.setIds(ids);
4630 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: idFilter);
4631 QCOMPARE(itemList.size(), 2);
4632 if (itemList.at(i: 0).id() == event1.id()){
4633 QCOMPARE(itemList.at(0), event1);
4634 QCOMPARE(itemList.at(1), event3);
4635 } else {
4636 QCOMPARE(itemList.at(1), event1);
4637 QCOMPARE(itemList.at(0), event3);
4638 }
4639 //a bad id inside the list
4640 // NOTE: empty id in id filter will match all generated occurrences
4641 QOrganizerItem badEvent;
4642 ids.prepend(t: badEvent.id());
4643 idFilter.setIds(ids);
4644 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: idFilter);
4645 QCOMPARE(itemList.size(), 2);
4646
4647 //intersection filter contains QOrganizerItemIdFilter and QOrganizerItemCollectionFilter
4648 cf2.setCollectionIds(collectionList);
4649 isf.clear();
4650 isf.append(filter: cf2);//event1 event2
4651 isf.append(filter: idFilter);//event1 event3
4652 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4653 QCOMPARE(itemList.size(), 1);
4654 QCOMPARE(itemList.at(0), event1);//expect event1
4655
4656 //3 filters intersection
4657 ids.clear();
4658 ids.append(t: event1.id());
4659 idFilter.setIds(ids);
4660 isf.append(filter: idFilter);//event1
4661 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4662 QCOMPARE(itemList.size(), 1);
4663
4664 //empty intersection
4665 ids.clear();
4666 ids.append(t: event3.id());
4667 idFilter.setIds(ids);
4668 isf.append(filter: idFilter);//event3
4669 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isf);
4670 QCOMPARE(itemList.size(), 0);
4671}
4672
4673void tst_QOrganizerManager::testNestCompoundFilter()
4674{
4675 QFETCH(QString, uri);
4676 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
4677 //simple case: nest intersection filter
4678 //prepare filter data
4679 QOrganizerCollection c1;
4680 QOrganizerCollection c2;
4681 mgr->saveCollection(collection: &c1);
4682 mgr->saveCollection(collection: &c2);
4683 QOrganizerItem event1;
4684 event1.setType(QOrganizerItemType::TypeEvent);
4685 QOrganizerItem event2;
4686 event2.setType(QOrganizerItemType::TypeEvent);
4687 event1.setCollectionId(c1.id());
4688 event2.setCollectionId(c2.id());
4689 mgr->saveItem(item: &event1);
4690 mgr->saveItem(item: &event2);
4691 //Test intersection filter with 2 different collection filter
4692 QOrganizerItemCollectionFilter cf1;
4693 cf1.setCollectionId(c1.id());
4694 QOrganizerItemCollectionFilter cf2;
4695 cf2.setCollectionId(c2.id());
4696 QOrganizerItemIntersectionFilter isf;
4697 isf.append(filter: cf1);
4698
4699 QOrganizerItemIntersectionFilter isfLevel1;
4700 isfLevel1.append(filter: isf);
4701 QList<QOrganizerItem> itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel1);
4702 QCOMPARE(itemList.size(), 1);
4703
4704 QOrganizerItemIntersectionFilter isfLevel2;
4705 isfLevel2.append(filter: isfLevel1);
4706
4707 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel2);
4708 QCOMPARE(itemList.size(), 1);
4709
4710 QOrganizerItemIntersectionFilter isfLevel3;
4711 isfLevel3.append(filter: isfLevel2);
4712
4713 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel3);
4714 QCOMPARE(itemList.size(), 1);
4715
4716 // union filter nest in interseion filter
4717 QOrganizerItemUnionFilter unf;
4718 unf.append(filter: cf2);
4719 unf.append(filter: cf1);
4720
4721 isfLevel1.append(filter: unf);
4722 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel1);
4723 QCOMPARE(itemList.size(), 1);
4724
4725 isfLevel2.append(filter: unf);
4726 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel2);
4727 QCOMPARE(itemList.size(), 1);
4728
4729 QList<QOrganizerItemId> idList;
4730 idList << event1.id() << event2.id();
4731
4732 QOrganizerItemIdFilter idf;
4733 idf.setIds(idList);
4734 isfLevel3.append(filter: idf);
4735
4736 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel3);
4737 QCOMPARE(itemList.size(), 1);
4738
4739 QOrganizerItemUnionFilter unfLevel4;
4740 unfLevel4.append(filter: isfLevel3);
4741 unfLevel4.append(filter: idf);
4742
4743 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unfLevel4);
4744 QCOMPARE(itemList.size(), 2);
4745
4746 //attach each other
4747 isfLevel3.append(filter: unfLevel4);
4748 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: isfLevel3);
4749 QCOMPARE(itemList.size(), 1);
4750
4751 //actual use case test
4752 int count = mgr->items().size();
4753
4754 QOrganizerTodo todo;
4755 todo.setDisplayLabel("myTodo");
4756 todo.setCollectionId(c1.id());
4757 mgr->saveItem(item: &todo);
4758 itemList = mgr->items();
4759 QCOMPARE(itemList.size(), ++count);
4760 //collection
4761 QOrganizerItemCollectionFilter collectionFilter;
4762 collectionFilter.setCollectionId(c1.id());
4763 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: collectionFilter);
4764 QCOMPARE(itemList.size(), 2);
4765 //event
4766 QOrganizerItemDetailFieldFilter detailFieldFilter;
4767 detailFieldFilter.setDetail(detailType: QOrganizerItemDetail::TypeItemType, field: QOrganizerItemType::FieldType);
4768 detailFieldFilter.setValue(QOrganizerItemType::TypeEvent);
4769 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: detailFieldFilter);
4770 QVERIFY(itemList.size() >= 2);
4771 //event + collection
4772 QOrganizerItemIntersectionFilter intersFilter;
4773 intersFilter.append(filter: detailFieldFilter);
4774 intersFilter.append(filter: collectionFilter);
4775 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: intersFilter);
4776 QCOMPARE(itemList.size(), 1);
4777 //filter event + collection + id
4778 idList << event1.id() << event2.id() << todo.id();
4779 QOrganizerItemIdFilter idf1;
4780 idf1.setIds(idList);
4781 QOrganizerItemIntersectionFilter intersFilter2;
4782 intersFilter2.append(filter: idf1);
4783 intersFilter2.append(filter: intersFilter);
4784 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: intersFilter);
4785 QCOMPARE(itemList.size(), 1);
4786 QCOMPARE(itemList[0].id(), event1.id());
4787
4788 //case 2: myTodo or event + collection + id
4789 QOrganizerItemDetailFieldFilter detailFieldFilter2;
4790 detailFieldFilter2.setDetail(detailType: QOrganizerItemDetail::TypeDisplayLabel, field: QOrganizerItemDisplayLabel::FieldLabel);
4791 detailFieldFilter2.setValue("myTodo");
4792 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: detailFieldFilter2);
4793 QCOMPARE(itemList.size(), 1);
4794
4795 QOrganizerItemUnionFilter unf2;
4796 unf2.append(filter: detailFieldFilter2);
4797 unf2.append(filter: detailFieldFilter);
4798 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf2);
4799 QVERIFY(itemList.size() >= 3);
4800
4801 //event or myTodo + collection
4802 QOrganizerItemIntersectionFilter intersFilter3;
4803 intersFilter3.append(filter: unf2);
4804 intersFilter3.append(filter: collectionFilter);
4805 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: intersFilter3);
4806 QCOMPARE(itemList.size(), 2);
4807 // ... + id
4808 QOrganizerItemIntersectionFilter intersFilter4;
4809 intersFilter4.append(filter: idf1);
4810 intersFilter4.append(filter: intersFilter3);
4811 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: intersFilter4);
4812 QCOMPARE(itemList.size(), 2);
4813 QVERIFY(itemList.contains(event1));
4814 QVERIFY(itemList.contains(todo));
4815}
4816
4817void tst_QOrganizerManager::testUnionFilter()
4818{
4819 QFETCH(QString, uri);
4820 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
4821
4822 //prepare filter data
4823 QOrganizerCollection c1;
4824 QOrganizerCollection c2;
4825 mgr->saveCollection(collection: &c1);
4826 mgr->saveCollection(collection: &c2);
4827 QOrganizerItem event1;
4828 event1.setType(QOrganizerItemType::TypeEvent);
4829 QOrganizerItem event2;
4830 event2.setType(QOrganizerItemType::TypeEvent);
4831 event1.setCollectionId(c1.id());
4832 event2.setCollectionId(c2.id());
4833 mgr->saveItem(item: &event1);
4834 mgr->saveItem(item: &event2);
4835 //Test union filter with 2 different collection filter
4836 QOrganizerItemCollectionFilter cf1;
4837 cf1.setCollectionId(c1.id());
4838 QOrganizerItemCollectionFilter cf2;
4839 cf2.setCollectionId(c2.id());
4840 QOrganizerItemUnionFilter unf;
4841 unf.append(filter: cf1);
4842 unf.append(filter: cf2);
4843 QList<QOrganizerItem> itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: cf1);
4844 QCOMPARE(itemList.size(), 1);
4845 QCOMPARE(itemList.at(0), event1);
4846 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf);
4847 QCOMPARE(itemList.size(), 2);
4848
4849 //Test union filter with 2 same collection filter
4850 unf.remove(filter: cf2);
4851 cf2.setCollectionId(c1.id());
4852 unf.append(filter: cf2);
4853 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf);
4854 QCOMPARE(itemList.size(), 1);
4855
4856 //Test union filter with 2 collection filter and one of them is biger than another
4857 unf.remove(filter: cf2);
4858 QSet<QOrganizerCollectionId> collectionList;
4859 collectionList << c1.id() << c2.id();
4860 cf2.setCollectionIds(collectionList);
4861 unf.append(filter: cf2);
4862 unf.append(filter: cf1);
4863 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf);
4864 QCOMPARE(itemList.size(), 2);
4865
4866 //Bad case: one empty filter
4867 unf.remove(filter: cf2);
4868 cf2.setCollectionId(QOrganizerCollectionId());
4869 unf.append(filter: cf2);
4870 QCOMPARE(unf.filters().size(), 2);
4871 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf);
4872 QCOMPARE(itemList.size(), 1);
4873
4874 //union filter contains QOrganizerItemIdFilter and QOrganizerItemCollectionFilter
4875 QList<QOrganizerItemId> ids;
4876 QOrganizerItemIdFilter idFilter;
4877 QOrganizerItem event3;
4878 event3.setType(QOrganizerItemType::TypeEvent);
4879 mgr->saveItem(item: &event3);
4880 ids << event3.id();
4881 idFilter.setIds(ids);
4882
4883 cf2.setCollectionIds(collectionList);
4884 unf.clear();
4885 unf.append(filter: cf2);//event1 event2
4886 unf.append(filter: idFilter);// event3
4887 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf);
4888 QCOMPARE(itemList.size(), 3);//expect event1 event2 event3
4889
4890 //3 filters union
4891 QOrganizerItem event4;
4892 event4.setType(QOrganizerItemType::TypeEvent);
4893 mgr->saveItem(item: &event4);
4894 ids.clear();
4895 ids.append(t: event4.id());
4896 idFilter.setIds(ids);
4897 unf.append(filter: idFilter);//event4
4898 itemList = mgr->items(startDateTime: QDateTime(), endDateTime: QDateTime(), filter: unf);
4899 QCOMPARE(itemList.size(), 4);//expect event1 event2 event3 event4
4900}
4901
4902void tst_QOrganizerManager::testTags()
4903{
4904 QFETCH(QString, uri);
4905 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
4906
4907 // save & load
4908 QOrganizerEvent event;
4909 event.setTags(QStringList() << QString::fromLatin1(str: "Tag1") << QString::fromLatin1(str: "Tag2"));
4910 event.addTag(tag: QString::fromLatin1(str: "Tag3"));
4911 QVERIFY(mgr->saveItem(&event));
4912 QOrganizerItemId id = event.id();
4913 QOrganizerItem item = mgr->item(itemId: id);
4914 QVERIFY(item.tags().size() == 3);
4915 QVERIFY(item.tags().contains(QString::fromLatin1("Tag1")));
4916 QVERIFY(item.tags().contains(QString::fromLatin1("Tag2")));
4917 QVERIFY(item.tags().contains(QString::fromLatin1("Tag3")));
4918
4919 // update
4920 item.addTag(tag: QString::fromLatin1(str: "Tag4"));QVERIFY(mgr->saveItem(&event));
4921 QList<QOrganizerItemDetail> details = item.details(detailType: QOrganizerItemDetail::TypeTag);
4922 QOrganizerItemTag tag = details.at(i: 1);
4923 tag.setTag(QString::fromLatin1(str: "Tag222"));
4924 item.saveDetail(detail: &tag);
4925 item.removeDetail(detail: &details[2]);
4926 QVERIFY(mgr->saveItem(&item));
4927 QOrganizerItemId id2 = item.id();
4928 QOrganizerItem item2 = mgr->item(itemId: id2);
4929 QVERIFY(item2.tags().size() == 3);
4930 QVERIFY(item2.tags().contains(QString::fromLatin1("Tag1")));
4931 QVERIFY(item2.tags().contains(QString::fromLatin1("Tag222")));
4932 QVERIFY(item2.tags().contains(QString::fromLatin1("Tag4")));
4933}
4934
4935void tst_QOrganizerManager::testExtendedDetail()
4936{
4937 QFETCH(QString, uri);
4938 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
4939 QOrganizerEvent event;
4940
4941 // simple string
4942 QOrganizerItemExtendedDetail basicString;
4943 basicString.setName(QStringLiteral("basic-string"));
4944 basicString.setData(QString(QStringLiteral("Qt Everywhere")));
4945 event.saveDetail(detail: &basicString);
4946 QVERIFY(mgr->saveItem(&event));
4947
4948 event = mgr->item(itemId: event.id());
4949 basicString = event.detail(detailType: QOrganizerItemDetail::TypeExtendedDetail);
4950 QCOMPARE(basicString.name(), QStringLiteral("basic-string"));
4951 QCOMPARE(basicString.data().toString(), QStringLiteral("Qt Everywhere"));
4952
4953 // simple list
4954 QOrganizerItemExtendedDetail basicList;
4955 basicList.setName(QStringLiteral("basic-list"));
4956 QVariantList basicListData;
4957 basicListData << QString(QStringLiteral("data 1"))
4958 << QString(QStringLiteral("data 2"))
4959 << QVariant(3);
4960 basicList.setData(basicListData);
4961 event.saveDetail(detail: &basicList);
4962 QVERIFY(mgr->saveItem(&event));
4963
4964 event = mgr->item(itemId: event.id());
4965 QList<QOrganizerItemDetail> extendedDetails = event.details(detailType: QOrganizerItemDetail::TypeExtendedDetail);
4966 QCOMPARE(extendedDetails.size(), 2);
4967 foreach (const QOrganizerItemExtendedDetail &extendedDetail, extendedDetails) {
4968 if (extendedDetail.name() == QStringLiteral("basic-list")) {
4969 QVariantList data = extendedDetail.data().toList();
4970 QCOMPARE(data.size(), 3);
4971 QCOMPARE(data.at(0).toString(), QStringLiteral("data 1"));
4972 QCOMPARE(data.at(1).toString(), QStringLiteral("data 2"));
4973 QCOMPARE(data.at(2).toInt(), 3);
4974 break;
4975 }
4976 }
4977
4978 // simple map
4979 QOrganizerItemExtendedDetail basicMap;
4980 basicMap.setName(QStringLiteral("basic map"));
4981 QVariantMap basicMapData;
4982 basicMapData.insert(akey: QString(QStringLiteral("key1")), avalue: QString(QStringLiteral("data-1")));
4983 basicMapData.insert(akey: QString(QStringLiteral("key-2")), avalue: QString(QStringLiteral("data2")));
4984 basicMapData.insert(akey: QString(QStringLiteral("key_3")), avalue: QVariant(1989));
4985 basicMap.setData(basicMapData);
4986 event.saveDetail(detail: &basicMap);
4987 QVERIFY(mgr->saveItem(&event));
4988
4989 event = mgr->item(itemId: event.id());
4990 extendedDetails = event.details(detailType: QOrganizerItemDetail::TypeExtendedDetail);
4991 QCOMPARE(extendedDetails.size(), 3);
4992 foreach (const QOrganizerItemExtendedDetail &extendedDetail, extendedDetails) {
4993 if (extendedDetail.name() == QStringLiteral("basic map")) {
4994 QVariantMap data = extendedDetail.data().toMap();
4995 QCOMPARE(data.size(), 3);
4996 QCOMPARE(data.value(QStringLiteral("key1")).toString(), QStringLiteral("data-1"));
4997 QCOMPARE(data.value(QStringLiteral("key-2")).toString(), QStringLiteral("data2"));
4998 QCOMPARE(data.value(QStringLiteral("key_3")).toInt(), 1989);
4999 break;
5000 }
5001 }
5002
5003 // map inside a list
5004 QOrganizerItemExtendedDetail mapInList;
5005 mapInList.setName(QStringLiteral("map in list"));
5006 mapInList.setData(QVariantList() << QString(QStringLiteral("Qt is cute")) << basicMapData);
5007 event.saveDetail(detail: &mapInList);
5008 QVERIFY(mgr->saveItem(&event));
5009
5010 event = mgr->item(itemId: event.id());
5011 extendedDetails = event.details(detailType: QOrganizerItemDetail::TypeExtendedDetail);
5012 QCOMPARE(extendedDetails.size(), 4);
5013 foreach (const QOrganizerItemExtendedDetail &extendedDetail, extendedDetails) {
5014 if (extendedDetail.name() == QStringLiteral("map in list")) {
5015 QVariantList data = extendedDetail.data().toList();
5016 QCOMPARE(data.size(), 2);
5017 QCOMPARE(data.at(0).toString(), QStringLiteral("Qt is cute"));
5018
5019 QVariantMap map = data.at(i: 1).toMap();
5020 QCOMPARE(map.value(QStringLiteral("key1")).toString(), QStringLiteral("data-1"));
5021 QCOMPARE(map.value(QStringLiteral("key-2")).toString(), QStringLiteral("data2"));
5022 QCOMPARE(map.value(QStringLiteral("key_3")).toInt(), 1989);
5023 break;
5024 }
5025 }
5026
5027 QVERIFY(mgr->removeItem(event.id()));
5028}
5029
5030void tst_QOrganizerManager::testAttendee()
5031{
5032 QFETCH(QString, uri);
5033 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
5034 QOrganizerEvent event;
5035
5036 // Save item and verify
5037 QOrganizerEventAttendee attendee;
5038 attendee.setName("people");
5039 attendee.setAttendeeId("123456");
5040 attendee.setEmailAddress("people@nokia.com");
5041 attendee.setParticipationRole(QOrganizerEventAttendee::RoleRequiredParticipant);
5042 attendee.setParticipationStatus(QOrganizerEventAttendee::StatusAccepted);
5043 event.saveDetail(detail: &attendee);
5044 QVERIFY(mgr->saveItem(&event));
5045 QOrganizerItemId id = event.id();
5046 QOrganizerItem item = mgr->item(itemId: id);
5047 QVERIFY(item.details(QOrganizerItemDetail::TypeEventAttendee).count() == 1);
5048 QVERIFY(item == event);//This will compare all details and their values
5049
5050 // Update
5051 attendee.setName("newpeople");
5052 attendee.setAttendeeId("54321");
5053 attendee.setEmailAddress("newpeople@nokia.com");
5054 event.saveDetail(detail: &attendee);
5055 QVERIFY(item != event);
5056 QVERIFY(mgr->saveItem(&event));
5057 item = mgr->item(itemId: id);
5058 QVERIFY(item.details(QOrganizerItemDetail::TypeEventAttendee).count() == 1);
5059 QVERIFY(item == event);//This will compare all details and their values
5060
5061 // Add one more attendee
5062 QOrganizerEventAttendee a1;
5063 a1.setAttendeeId("777777");
5064 a1.setName("people1");
5065 a1.setEmailAddress("people1@nokia.com");
5066 event.saveDetail(detail: &a1);
5067 QVERIFY(item != event);
5068 QVERIFY(mgr->saveItem(&event));
5069 item = mgr->item(itemId: id);
5070 QVERIFY(item.details(QOrganizerItemDetail::TypeEventAttendee).count() == 2);
5071
5072 // Remove
5073 QVERIFY(event.removeDetail(&attendee));
5074 QVERIFY(event.details(QOrganizerItemDetail::TypeEventAttendee).size() == 1);
5075 QVERIFY(event.removeDetail(&a1));
5076 QVERIFY(event.details(QOrganizerItemDetail::TypeEventAttendee).size() == 0);
5077 QVERIFY(mgr->saveItem(&event));
5078 item = mgr->item(itemId: id);
5079 QVERIFY(item.details(QOrganizerItemDetail::TypeEventAttendee).count() == 0);
5080}
5081
5082void tst_QOrganizerManager::testRsvp()
5083{
5084 QFETCH(QString, uri);
5085 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
5086 QOrganizerEvent event;
5087
5088 // Save item and verify
5089 QOrganizerEventRsvp rsvp;
5090 rsvp.setOrganizerName("Donald Duck");
5091 rsvp.setOrganizerEmail("don@duck.com");
5092 rsvp.setResponseDate(QDate(2010, 10, 10));
5093 rsvp.setResponseDeadline(QDate(2010, 11, 11));
5094 rsvp.setParticipationRole(QOrganizerEventAttendee::RoleOrganizer);
5095 rsvp.setParticipationStatus(QOrganizerEventAttendee::StatusAccepted);
5096 rsvp.setResponseRequirement(QOrganizerEventRsvp::ResponseRequired);
5097 QVERIFY(event.saveDetail(&rsvp));
5098 QVERIFY(mgr->saveItem(&event));
5099 QOrganizerItemId id = event.id();
5100 QOrganizerItem item = mgr->item(itemId: id);
5101 QCOMPARE(1, item.details(QOrganizerItemDetail::TypeEventRsvp).count());
5102 QVERIFY(item == event);//This will compare all details and their values
5103
5104 // Update
5105 rsvp.setOrganizerName("Mickey Mouse");
5106 rsvp.setOrganizerEmail("mick@mouse.com");
5107 rsvp.setResponseDate(QDate(2011, 11, 11));
5108 rsvp.setResponseDeadline(QDate(2011, 12, 12));
5109 rsvp.setParticipationRole(QOrganizerEventAttendee::RoleChairperson);
5110 rsvp.setParticipationStatus(QOrganizerEventAttendee::StatusDelegated);
5111 rsvp.setResponseRequirement(QOrganizerEventRsvp::ResponseNotRequired);
5112 QVERIFY(event.saveDetail(&rsvp));
5113 QVERIFY(mgr->saveItem(&event));
5114 item = mgr->item(itemId: id);
5115 QCOMPARE(1, event.details(QOrganizerItemDetail::TypeEventRsvp).size());
5116 QVERIFY(item == event);//This will compare all details and their values
5117
5118 // Remove
5119 QVERIFY(event.removeDetail(&rsvp));
5120 QCOMPARE(0, event.details(QOrganizerItemDetail::TypeEventRsvp).size());
5121 QVERIFY(mgr->saveItem(&event));
5122 item = mgr->item(itemId: id);
5123 QVERIFY(item.details(QOrganizerItemDetail::TypeEventRsvp).count() == 0);
5124}
5125
5126void tst_QOrganizerManager::testClassification()
5127{
5128 QFETCH(QString, uri);
5129 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
5130 if (!mgr->supportedItemDetails(itemType: QOrganizerItemType::TypeEvent).contains(t: QOrganizerItemDetail::TypeClassification))
5131 QSKIP("Classification -detail not supported by this backend.");
5132
5133 // Save item and verify
5134 QOrganizerEvent event;
5135 QOrganizerItemClassification classification;
5136 classification.setClassification(QOrganizerItemClassification::AccessPrivate);
5137 QVERIFY(event.saveDetail(&classification));
5138 QVERIFY(mgr->saveItem(&event));
5139 QOrganizerItemId id = event.id();
5140 QOrganizerItem item = mgr->item(itemId: id);
5141 QCOMPARE(1, item.details(QOrganizerItemDetail::TypeClassification).count());
5142 QVERIFY(item == event);//This will compare all details and their values
5143
5144 // Update
5145 classification.setClassification(QOrganizerItemClassification::AccessConfidential);
5146 QVERIFY(event.saveDetail(&classification));
5147 QVERIFY(mgr->saveItem(&event));
5148 item = mgr->item(itemId: id);
5149 QCOMPARE(1, event.details(QOrganizerItemDetail::TypeClassification).size());
5150 QVERIFY(item == event);//This will compare all details and their values
5151
5152 // Remove
5153 QVERIFY(event.removeDetail(&classification));
5154 QCOMPARE(0, event.details(QOrganizerItemDetail::TypeClassification).size());
5155 QVERIFY(mgr->saveItem(&event));
5156 item = mgr->item(itemId: id);
5157 QVERIFY(item.details(QOrganizerItemDetail::TypeClassification).count() == 0);
5158}
5159
5160void tst_QOrganizerManager::testVersion()
5161{
5162 QFETCH(QString, uri);
5163 QScopedPointer<QOrganizerManager> mgr(QOrganizerManager::fromUri(uri));
5164 if (!mgr->supportedItemDetails(itemType: QOrganizerItemType::TypeEvent).contains(t: QOrganizerItemDetail::TypeVersion))
5165 QSKIP("Version detail not supported by this backend.");
5166
5167 QOrganizerEvent event;
5168 QVERIFY(event.detail(QOrganizerItemDetail::TypeVersion).isEmpty());
5169 QVERIFY(mgr->saveItem(&event));
5170
5171 QOrganizerItemVersion version = event.detail(detailType: QOrganizerItemDetail::TypeVersion);
5172 QVERIFY(!version.isEmpty());
5173
5174 event.setDisplayLabel("Qt rules!");
5175 QVERIFY(mgr->saveItem(&event));
5176
5177 QOrganizerItemVersion version2 = event.detail(detailType: QOrganizerItemDetail::TypeVersion);
5178 QVERIFY(!version2.isEmpty());
5179 QVERIFY((version2.version() > version.version()) || (version2.extendedVersion() != version.extendedVersion()));
5180}
5181
5182#if 0 // This test is currently excluded; can it be reinstated?
5183class errorSemanticsTester : public QObject {
5184 Q_OBJECT;
5185public:
5186 bool initialErrorWasDoesNotExist;
5187 bool slotErrorWasBadArgument;
5188 QOrganizerManager* mManager;
5189
5190 errorSemanticsTester(QOrganizerManager* manager)
5191 : initialErrorWasDoesNotExist(false),
5192 slotErrorWasBadArgument(false),
5193 mManager(manager)
5194 {
5195 connect(manager, SIGNAL(itemsAdded(QList<QOrganizerItemId>)), this, SLOT(handleAdded()));
5196 }
5197
5198public slots:
5199 void handleAdded()
5200 {
5201 // Make sure the initial error state is correct
5202 initialErrorWasDoesNotExist = mManager->error() == QOrganizerManager::DoesNotExistError;
5203 // Now force a different error
5204 mManager->removeItems(QList<QOrganizerItemId>());
5205 slotErrorWasBadArgument = mManager->error() == QOrganizerManager::BadArgumentError;
5206 // and return
5207 }
5208};
5209#endif
5210
5211QTEST_MAIN(tst_QOrganizerManager)
5212#include "tst_qorganizermanager.moc"
5213

source code of qtpim/tests/auto/organizer/qorganizermanager/tst_qorganizermanager.cpp