1 /*
2 This file is part of the kcalcore library.
3
4 SPDX-FileCopyrightText: 2006, 2008 Allen Winter <winter@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 #include "testtodo.h"
9 #include "attachment.h"
10 #include "event.h"
11 #include "sorting.h"
12 #include "todo.h"
13
14 #include <QTest>
15 QTEST_MAIN(TodoTest)
16
17 using namespace KCalendarCore;
18
initTestCase()19 void TodoTest::initTestCase()
20 {
21 qputenv("TZ", "UTC");
22 }
23
testValidity()24 void TodoTest::testValidity()
25 {
26 QDate dt = QDate::currentDate();
27 Todo todo;
28 todo.setDtStart(QDateTime(dt, {}));
29 todo.setDtDue(QDateTime(dt, {}).addDays(1));
30 todo.setSummary(QStringLiteral("To-do1 Summary"));
31 todo.setDescription(QStringLiteral("This is a description of the first to-do"));
32 todo.setLocation(QStringLiteral("the place"));
33 todo.setPercentComplete(5);
34
35 QCOMPARE(todo.summary(), QStringLiteral("To-do1 Summary"));
36 QCOMPARE(todo.location(), QStringLiteral("the place"));
37 QCOMPARE(todo.percentComplete(), 5);
38 }
39
testCompare()40 void TodoTest::testCompare()
41 {
42 QDate dt = QDate::currentDate();
43 Todo todo1;
44 todo1.setDtStart(QDateTime(dt, {}));
45 todo1.setDtDue(QDateTime(dt, {}).addDays(1));
46 todo1.setSummary(QStringLiteral("To-do1 Summary"));
47 todo1.setDescription(QStringLiteral("This is a description of the first to-do"));
48 todo1.setLocation(QStringLiteral("the place"));
49 todo1.setCompleted(true);
50
51 Todo todo2;
52 todo2.setDtStart(QDateTime(dt, {}).addDays(1));
53 todo2.setDtDue(QDateTime(dt, {}).addDays(2));
54 todo2.setSummary(QStringLiteral("To-do2 Summary"));
55 todo2.setDescription(QStringLiteral("This is a description of the second to-do"));
56 todo2.setLocation(QStringLiteral("the other place"));
57 todo2.setCompleted(false);
58
59 QVERIFY(!(todo1 == todo2));
60 QCOMPARE(todo1.dtDue(), todo2.dtStart());
61 QCOMPARE(todo2.summary(), QStringLiteral("To-do2 Summary"));
62 QVERIFY(!(todo1.isCompleted() == todo2.isCompleted()));
63 }
64
testClone()65 void TodoTest::testClone()
66 {
67 QDate dt = QDate::currentDate();
68 Todo todo1;
69 todo1.setDtStart(QDateTime(dt, {}));
70 todo1.setDtDue(QDateTime(dt, {}).addDays(1));
71 todo1.setSummary(QStringLiteral("Todo1 Summary"));
72 todo1.setDescription(QStringLiteral("This is a description of the first todo"));
73 todo1.setLocation(QStringLiteral("the place"));
74
75 Todo *todo2 = todo1.clone();
76 QCOMPARE(todo1.summary(), todo2->summary());
77 QCOMPARE(todo1.dtStart(), todo2->dtStart());
78 QCOMPARE(todo1.dtDue(), todo2->dtDue());
79 QCOMPARE(todo1.description(), todo2->description());
80 QCOMPARE(todo1.location(), todo2->location());
81 QCOMPARE(todo1.isCompleted(), todo2->isCompleted());
82 delete todo2;
83 }
84
testCopyIncidence()85 void TodoTest::testCopyIncidence()
86 {
87 QDate dt = QDate::currentDate();
88 Event event;
89 event.setDtStart(QDateTime(dt, {}));
90 event.setSummary(QStringLiteral("Event1 Summary"));
91 event.setDescription(QStringLiteral("This is a description of the first event"));
92 event.setLocation(QStringLiteral("the place"));
93
94 Todo todo(event);
95 QCOMPARE(todo.uid(), event.uid());
96 QCOMPARE(todo.dtStart(), event.dtStart());
97 QCOMPARE(todo.summary(), event.summary());
98 QCOMPARE(todo.description(), event.description());
99 QCOMPARE(todo.location(), event.location());
100 }
101
testCopyConstructor()102 void TodoTest::testCopyConstructor()
103 {
104 QDate dt = QDate::currentDate();
105 Todo todo1;
106 todo1.setDtStart(QDateTime(dt, {}));
107 todo1.setDtDue(QDateTime(dt, {}).addDays(1));
108 todo1.setSummary(QStringLiteral("Todo1 Summary"));
109 todo1.setDescription(QStringLiteral("This is a description of the first todo"));
110 todo1.setLocation(QStringLiteral("the place"));
111
112 Todo todo2 {todo1};
113 QVERIFY(todo1 == todo2);
114 }
115
testAssign()116 void TodoTest::testAssign()
117 {
118 QDate dt = QDate::currentDate();
119 Todo todo1;
120 todo1.setDtStart(QDateTime(dt, {}));
121 todo1.setDtDue(QDateTime(dt, {}).addDays(1));
122 todo1.setSummary(QStringLiteral("Todo1 Summary"));
123 todo1.setDescription(QStringLiteral("This is a description of the first todo"));
124 todo1.setLocation(QStringLiteral("the place"));
125
126 IncidenceBase *todo2 = new Todo;
127 *todo2 = todo1; // Use IncidenceBase's virtual assignment.
128 QVERIFY(todo1 == *todo2);
129 }
130
testSetCompletedWithDate()131 void TodoTest::testSetCompletedWithDate()
132 {
133 Todo t;
134 t.setStatus(Incidence::StatusNone);
135 QVERIFY(!t.isCompleted());
136 QVERIFY(!t.hasCompletedDate());
137 QVERIFY(t.status() != Incidence::StatusCompleted);
138 QVERIFY(t.percentComplete() != 100);
139
140 const auto now = QDateTime::currentDateTimeUtc();
141 t.setCompleted(now);
142 QVERIFY(t.isCompleted());
143 QVERIFY(t.completed() == now);
144 QVERIFY(t.hasCompletedDate());
145 QVERIFY(t.status() == Incidence::StatusNone);
146 QVERIFY(t.percentComplete() == 100);
147 }
148
testSetCompletedWithoutDate()149 void TodoTest::testSetCompletedWithoutDate()
150 {
151 Todo t;
152 t.setStatus(Incidence::StatusNeedsAction);
153 QVERIFY(!t.isCompleted());
154 QVERIFY(!t.hasCompletedDate());
155 QVERIFY(t.status() != Incidence::StatusCompleted);
156 QVERIFY(t.percentComplete() != 100);
157
158 t.setCompleted(QDateTime());
159 QVERIFY(t.isCompleted());
160 QVERIFY(!t.hasCompletedDate());
161 QVERIFY(t.status() == Incidence::StatusCompleted);
162 QVERIFY(t.percentComplete() == 100);
163 }
164
testSetCompleted()165 void TodoTest::testSetCompleted()
166 {
167 Todo todo1;
168 todo1.setSummary(QStringLiteral("Todo Summary"));
169 QDateTime today = QDateTime::currentDateTimeUtc();
170
171 // due yesterday
172 QDateTime originalDueDate = today.addDays(-1);
173
174 todo1.setDtStart(originalDueDate);
175 todo1.setDtDue(originalDueDate);
176 todo1.recurrence()->setDaily(1);
177 todo1.setCompleted(today);
178 QVERIFY(originalDueDate != todo1.dtDue());
179 QVERIFY(!todo1.isCompleted());
180 }
181
testSetCompletedBool()182 void TodoTest::testSetCompletedBool()
183 {
184 Todo t;
185 QVERIFY(!t.isCompleted());
186 QVERIFY(!t.hasCompletedDate());
187 QVERIFY(t.status() != Incidence::StatusCompleted);
188 QVERIFY(t.percentComplete() != 100);
189
190 t.setCompleted(true);
191 QVERIFY(t.isCompleted());
192 QVERIFY(!t.hasCompletedDate());
193 QVERIFY(t.status() == Incidence::StatusCompleted);
194 QVERIFY(t.percentComplete() == 100);
195
196 const auto yesterday = QDateTime::currentDateTimeUtc().addDays(-1);
197 t.setCompleted(yesterday);
198 t.setCompleted(true);
199 QVERIFY(t.isCompleted());
200 QVERIFY(t.completed() == yesterday);
201 QVERIFY(t.status() == Incidence::StatusCompleted);
202 QVERIFY(t.percentComplete() == 100);
203
204 t.setCompleted(false);
205 QVERIFY(!t.isCompleted());
206 QVERIFY(!t.hasCompletedDate());
207 QVERIFY(t.status() == Incidence::StatusNone);
208 QVERIFY(t.percentComplete() == 0);
209 }
210
testSetPercent()211 void TodoTest::testSetPercent()
212 {
213 Todo t;
214 t.setStatus(Incidence::StatusCompleted);
215 t.setCompleted(QDateTime::currentDateTimeUtc());
216 t.setPercentComplete(100);
217 QVERIFY(t.percentComplete() == 100);
218 QVERIFY(t.isCompleted());
219
220 // Completion reset if necessary.
221 QVERIFY(t.hasCompletedDate());
222 t.setPercentComplete(99);
223 QVERIFY(t.percentComplete() == 99);
224 QVERIFY(!t.isCompleted());
225 QVERIFY(!t.hasCompletedDate());
226 QVERIFY(t.status() != Incidence::StatusCompleted);
227
228 t.setPercentComplete(0);
229 QVERIFY(t.percentComplete() == 0);
230 QVERIFY(!t.isCompleted());
231 QVERIFY(!t.hasCompletedDate());
232 QVERIFY(t.status() != Incidence::StatusCompleted);
233 }
234
testStatus()235 void TodoTest::testStatus()
236 {
237 QDateTime today = QDateTime::currentDateTimeUtc();
238 QDateTime yesterday = today.addDays(-1);
239
240 Todo todo1;
241 todo1.setAllDay(true);
242 todo1.setDtStart(yesterday);
243 todo1.setDtDue(today);
244 todo1.setPercentComplete(50);
245 QVERIFY(todo1.isInProgress(false));
246 QVERIFY(!todo1.isNotStarted(false));
247 QVERIFY(!todo1.isOverdue());
248 todo1.setPercentComplete(100);
249 QVERIFY(todo1.isCompleted());
250
251 Todo todo2 = todo1;
252 todo2.setPercentComplete(33);
253 todo2.setDtDue(QDateTime());
254 QVERIFY(todo2.isOpenEnded());
255 }
256
testSerializer_data()257 void TodoTest::testSerializer_data()
258 {
259 QTest::addColumn<KCalendarCore::Todo::Ptr>("todo");
260
261 QDateTime today = QDateTime::currentDateTimeUtc();
262 QDateTime yesterday = today.addDays(-1);
263
264 Todo::Ptr todo1 = Todo::Ptr(new Todo());
265 Todo::Ptr todo2 = Todo::Ptr(new Todo());
266 Todo::Ptr todo3 = Todo::Ptr(new Todo());
267 Todo::Ptr todo4 = Todo::Ptr(new Todo());
268 Todo::Ptr todo5 = Todo::Ptr(new Todo());
269 Todo::Ptr todo6 = Todo::Ptr(new Todo());
270
271 todo1->setSummary(QStringLiteral("Summary"), false);
272 todo1->setDescription(QStringLiteral("description"), false);
273 todo1->setCreated(yesterday);
274 todo1->setRevision(50);
275 todo1->setDtDue(yesterday);
276 todo1->setDtStart(today);
277 todo1->setPercentComplete(50);
278 todo1->setLocation(QStringLiteral("<b>location</b>"), false);
279
280 todo2->setDescription(QStringLiteral("<b>description</b>"), true);
281 todo2->setSummary(QStringLiteral("<b>Summary2</b>"), true);
282 todo2->setLocation(QStringLiteral("<b>location</b>"), true);
283 todo2->setDtDue(yesterday);
284 todo2->setPercentComplete(100);
285
286 todo3->setDtStart(today);
287 todo3->setPercentComplete(100);
288 todo3->setCategories(QStringList() << QStringLiteral("a") << QStringLiteral("b") << QStringLiteral("c") << QStringLiteral("d"));
289 todo3->setResources(QStringList() << QStringLiteral("a") << QStringLiteral("b") << QStringLiteral("c") << QStringLiteral("d"));
290 todo3->setPriority(5);
291
292 QVERIFY(!todo4->dirtyFields().contains(IncidenceBase::FieldRecurrence));
293 todo4->recurrence()->setDaily(1);
294 QVERIFY(todo4->dirtyFields().contains(IncidenceBase::FieldRecurrence));
295
296 Attachment attachment(QStringLiteral("http://www.kde.org"));
297 todo4->addAttachment(attachment);
298
299 todo5->recurrence()->setDaily(1);
300 todo5->setCompleted(today);
301 todo5->setStatus(Incidence::StatusDraft);
302 todo5->setSecrecy(Incidence::SecrecyPrivate);
303 todo5->setRelatedTo(QStringLiteral("uid1"), Incidence::RelTypeParent);
304 todo5->setHasGeo(true);
305 todo5->setGeoLatitude(40);
306 todo5->setGeoLongitude(40);
307 todo5->setOrganizer(QStringLiteral("organizer@mail.com"));
308
309 todo6->recurrence()->setDaily(1);
310 todo6->setCompleted(today);
311 todo6->setRecurrenceId(yesterday);
312 todo6->setStatus(Incidence::StatusDraft);
313 todo6->setSecrecy(Incidence::SecrecyPrivate);
314 todo6->setRelatedTo(QStringLiteral("uid1"), Incidence::RelTypeParent);
315 todo6->setHasGeo(true);
316 todo6->setGeoLatitude(40);
317 todo6->setGeoLongitude(40);
318 todo6->setUid(QStringLiteral("uid22"));
319 todo6->setLastModified(today);
320 todo6->addContact(QStringLiteral("addContact"));
321
322 // Remaining properties tested in testevent.cpp
323
324 QTest::newRow("todo1") << todo1;
325 QTest::newRow("todo2") << todo2;
326 QTest::newRow("todo3") << todo3;
327 QTest::newRow("todo4") << todo4;
328 QTest::newRow("todo5") << todo5;
329 QTest::newRow("todo6") << todo6;
330 }
331
testSerializer()332 void TodoTest::testSerializer()
333 {
334 QFETCH(KCalendarCore::Todo::Ptr, todo);
335 IncidenceBase::Ptr incidenceBase = todo.staticCast<KCalendarCore::IncidenceBase>();
336
337 QByteArray array;
338 QDataStream stream(&array, QIODevice::WriteOnly);
339 stream << incidenceBase;
340
341 Todo::Ptr todo2 = Todo::Ptr(new Todo());
342 IncidenceBase::Ptr incidenceBase2 = todo2.staticCast<KCalendarCore::IncidenceBase>();
343 QVERIFY(*todo != *todo2);
344 QDataStream stream2(&array, QIODevice::ReadOnly);
345 stream2 >> incidenceBase2;
346 QVERIFY(*todo == *todo2);
347 }
348
testRoles()349 void TodoTest::testRoles()
350 {
351 const QDateTime today = QDateTime::currentDateTimeUtc();
352 const QDateTime yesterday = today.addDays(-1);
353 Todo todo;
354 todo.setDtStart(today.addDays(-1));
355 todo.setDtDue(today);
356 QCOMPARE(todo.dateTime(Incidence::RoleDisplayStart), today);
357 QCOMPARE(todo.dateTime(Incidence::RoleDisplayEnd), today);
358 todo.setDtDue(QDateTime());
359 QCOMPARE(todo.dateTime(Incidence::RoleDisplayStart), yesterday);
360 QCOMPARE(todo.dateTime(Incidence::RoleDisplayEnd), yesterday);
361 }
362
testIconNameOneoff()363 void TodoTest::testIconNameOneoff()
364 {
365 const QDateTime now = QDateTime::currentDateTime();
366 Todo todo;
367 todo.setDtStart(now);
368
369 QCOMPARE(todo.iconName(), QLatin1String("view-calendar-tasks"));
370 todo.setCompleted(now);
371 QCOMPARE(todo.iconName(), QLatin1String("task-complete"));
372 }
373
testIconNameRecurringNeverDue()374 void TodoTest::testIconNameRecurringNeverDue()
375 {
376 const QDateTime now = QDateTime::currentDateTime();
377 Todo todo;
378 todo.setDtStart(now);
379 todo.recurrence()->setDaily(1);
380
381 QCOMPARE(todo.iconName(now), QLatin1String("view-calendar-tasks"));
382
383 todo.setCompleted(now);
384 QCOMPARE(todo.iconName(now), QLatin1String("task-complete"));
385 QCOMPARE(todo.iconName(now.addDays(1)), QLatin1String("view-calendar-tasks"));
386 }
387
testIconNameRecurringDue()388 void TodoTest::testIconNameRecurringDue()
389 {
390 const QDateTime now = QDateTime::currentDateTime();
391 const QDateTime later = now.addSecs(3600);
392 Todo todo;
393 todo.setDtStart(now);
394 todo.setDtDue(later, /*first=*/true);
395 todo.recurrence()->setDaily(1);
396
397 QCOMPARE(todo.iconName(now), QLatin1String("view-calendar-tasks"));
398 QCOMPARE(todo.iconName(later), QLatin1String("view-calendar-tasks")); // Legacy case
399
400 todo.setCompleted(now);
401 QCOMPARE(todo.iconName(now), QLatin1String("task-complete"));
402 QCOMPARE(todo.iconName(later), QLatin1String("task-complete")); // Legacy case
403 QCOMPARE(todo.iconName(now.addDays(1)), QLatin1String("view-calendar-tasks"));
404 }
405
testCategoriesComparison()406 void TodoTest::testCategoriesComparison()
407 {
408 QSharedPointer<Todo> small(new Todo);
409 small->setCategories({QStringLiteral("alpha")});
410 small->setSummary(QStringLiteral("alpha"));
411
412 QSharedPointer<Todo> medium(new Todo);
413 medium->setCategories({QStringLiteral("beta")});
414 medium->setSummary(QStringLiteral("beta 1"));
415
416 QSharedPointer<Todo> large(new Todo);
417 large->setCategories({QStringLiteral("beta")});
418 large->setSummary(QStringLiteral("beta 2"));
419
420 QVERIFY(Incidences::categoriesLessThan(small, medium));
421 QVERIFY(!Incidences::categoriesLessThan(medium, small));
422 QVERIFY(Incidences::categoriesLessThan(medium, large));
423 QVERIFY(!Incidences::categoriesLessThan(large, medium));
424 QVERIFY(!Incidences::categoriesLessThan(small, small));
425
426 QVERIFY(!Incidences::categoriesMoreThan(small, medium));
427 QVERIFY(Incidences::categoriesMoreThan(medium, small));
428 QVERIFY(!Incidences::categoriesMoreThan(medium, large));
429 QVERIFY(Incidences::categoriesMoreThan(large, medium));
430 QVERIFY(!Incidences::categoriesMoreThan(small, small));
431 }
432
testDtDueComparison()433 void TodoTest::testDtDueComparison()
434 {
435 auto now = QDateTime::currentDateTime();
436 auto later = now.addSecs(1);
437
438 QSharedPointer<Todo> small(new Todo);
439 small->setDtDue(now);
440 small->setAllDay(false);
441 small->setSummary(QStringLiteral("now"));
442
443 QSharedPointer<Todo> medium(new Todo);
444 medium->setDtDue(later);
445 medium->setAllDay(false);
446 medium->setSummary(QStringLiteral("later 1"));
447
448 QSharedPointer<Todo> large(new Todo);
449 large->setDtDue(later);
450 large->setAllDay(false);
451 large->setSummary(QStringLiteral("later 2"));
452
453 QSharedPointer<Todo> never(new Todo);
454 never->setDtDue(QDateTime());
455 never->setAllDay(false);
456 never->setSummary(QStringLiteral("never"));
457
458 QVERIFY(Todos::dueDateLessThan(small, medium));
459 QVERIFY(!Todos::dueDateLessThan(medium, small));
460 QVERIFY(Todos::dueDateLessThan(medium, large));
461 QVERIFY(!Todos::dueDateLessThan(large, medium));
462 QVERIFY(Todos::dueDateLessThan(large, never));
463 QVERIFY(!Todos::dueDateLessThan(never, large));
464 QVERIFY(!Todos::dueDateLessThan(small, small));
465 QVERIFY(!Todos::dueDateLessThan(never, never));
466
467 QVERIFY(!Todos::dueDateMoreThan(small, medium));
468 QVERIFY(Todos::dueDateMoreThan(medium, small));
469 QVERIFY(!Todos::dueDateMoreThan(medium, large));
470 QVERIFY(Todos::dueDateMoreThan(large, medium));
471 QVERIFY(!Todos::dueDateMoreThan(large, never));
472 QVERIFY(Todos::dueDateMoreThan(never, large));
473 QVERIFY(!Todos::dueDateMoreThan(small, small));
474 QVERIFY(!Todos::dueDateLessThan(never, never));
475 }
476
477