File indexing completed on 2025-01-05 05:00:01

0001 /*
0002  * SPDX-FileCopyrightText: 2015 Theo Vaucher <theo.vaucher@gmail.com>
0003  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 
0007 #include <testlib/qtest_zanshin.h>
0008 
0009 #include <memory>
0010 
0011 #include <QMimeData>
0012 
0013 #include <testlib/fakejob.h>
0014 
0015 #include "utils/datetime.h"
0016 #include "utils/mockobject.h"
0017 
0018 #include "domain/taskqueries.h"
0019 #include "domain/taskrepository.h"
0020 #include "presentation/workdaypagemodel.h"
0021 #include "presentation/querytreemodelbase.h"
0022 
0023 using namespace mockitopp;
0024 using namespace mockitopp::matcher;
0025 
0026 class WorkdayPageModelTest : public QObject
0027 {
0028     Q_OBJECT
0029 private slots:
0030     void shouldListWorkdayInCentralListModel()
0031     {
0032         // GIVEN
0033 
0034         const auto today = Utils::DateTime::currentDate();
0035 
0036         // Three tasks
0037         auto task1 = Domain::Task::Ptr::create();
0038         task1->setTitle(QStringLiteral("task1"));
0039         task1->setStartDate(today.addDays(-10));
0040         task1->setDueDate(today);
0041         auto task2 = Domain::Task::Ptr::create();
0042         task2->setTitle(QStringLiteral("task2"));
0043         task2->setStartDate(today);
0044         task2->setDueDate(today.addDays(10));
0045         auto task3 = Domain::Task::Ptr::create();
0046         task3->setTitle(QStringLiteral("task3"));
0047         task3->setStartDate(today.addYears(-4));
0048         task3->setDueDate(today.addYears(-3));
0049         auto taskProvider = Domain::QueryResultProvider<Domain::Task::Ptr>::Ptr::create();
0050         auto taskResult = Domain::QueryResult<Domain::Task::Ptr>::create(taskProvider);
0051         taskProvider->append(task1);
0052         taskProvider->append(task2);
0053         taskProvider->append(task3);
0054 
0055         // Two tasks under the task1
0056         auto childTask11 = Domain::Task::Ptr::create();
0057         childTask11->setTitle(QStringLiteral("childTask11"));
0058         auto childTask12 = Domain::Task::Ptr::create();
0059         childTask12->setTitle(QStringLiteral("childTask12"));
0060         childTask12->setStartDate(today);
0061         childTask12->setDueDate(today);
0062         auto childTaskProvider = Domain::QueryResultProvider<Domain::Task::Ptr>::Ptr::create();
0063         auto childTaskResult = Domain::QueryResult<Domain::Task::Ptr>::create(childTaskProvider);
0064         taskProvider->append(childTask12);
0065         childTaskProvider->append(childTask11);
0066         childTaskProvider->append(childTask12);
0067 
0068         // One project
0069         auto project = Domain::Project::Ptr::create();
0070         project->setName("KDE");
0071         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0072         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
0073         projectProvider->append(project);
0074 
0075         auto inboxProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0076         auto inboxResult = Domain::QueryResult<Domain::Project::Ptr>::create(inboxProvider);
0077 
0078         Utils::MockObject<Domain::TaskQueries> taskQueriesMock;
0079         taskQueriesMock(&Domain::TaskQueries::findWorkdayTopLevel).when().thenReturn(taskResult);
0080         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(childTaskResult);
0081         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0082         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task3).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0083         taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask11).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0084         taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask12).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0085 
0086         taskQueriesMock(&Domain::TaskQueries::findProject).when(task1).thenReturn(inboxResult);
0087         taskQueriesMock(&Domain::TaskQueries::findProject).when(task2).thenReturn(projectResult);
0088         taskQueriesMock(&Domain::TaskQueries::findProject).when(task3).thenReturn(inboxResult);
0089         taskQueriesMock(&Domain::TaskQueries::findProject).when(childTask11).thenReturn(inboxResult);
0090         taskQueriesMock(&Domain::TaskQueries::findProject).when(childTask12).thenReturn(inboxResult);
0091 
0092         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
0093 
0094         Presentation::WorkdayPageModel workday(taskQueriesMock.getInstance(),
0095                                                taskRepositoryMock.getInstance());
0096 
0097         // WHEN
0098         QAbstractItemModel *model = workday.centralListModel();
0099 
0100         // THEN
0101         const QModelIndex task1Index = model->index(0, 0);
0102         const QModelIndex task2Index = model->index(1, 0);
0103         const QModelIndex task3Index = model->index(2, 0);
0104         const QModelIndex taskChildTask12Index = model->index(3, 0);
0105 
0106         const QModelIndex childTask11Index = model->index(0, 0, task1Index);
0107         const QModelIndex childTask12Index = model->index(1, 0, task1Index);
0108 
0109         QCOMPARE(model->rowCount(), 4);
0110         QCOMPARE(model->rowCount(task1Index), 2);
0111         QCOMPARE(model->rowCount(task2Index), 0);
0112         QCOMPARE(model->rowCount(task3Index), 0);
0113         QCOMPARE(model->rowCount(taskChildTask12Index), 0);
0114 
0115         QVERIFY(childTask11Index.isValid());
0116         QVERIFY(childTask12Index.isValid());
0117         QCOMPARE(model->rowCount(childTask11Index), 0);
0118         QCOMPARE(model->rowCount(childTask12Index), 0);
0119 
0120         const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable
0121                                          | Qt::ItemIsEnabled
0122                                          | Qt::ItemIsEditable
0123                                          | Qt::ItemIsDragEnabled;
0124         QCOMPARE(model->flags(task1Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled);
0125         QCOMPARE(model->flags(childTask11Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled);
0126         QCOMPARE(model->flags(childTask12Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled);
0127         QCOMPARE(model->flags(task2Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled);
0128         QCOMPARE(model->flags(task3Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled);
0129         QCOMPARE(model->flags(taskChildTask12Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled);
0130 
0131         QCOMPARE(model->data(task1Index).toString(), task1->title());
0132         QCOMPARE(model->data(childTask11Index).toString(), childTask11->title());
0133         QCOMPARE(model->data(childTask12Index).toString(), childTask12->title());
0134         QCOMPARE(model->data(task2Index).toString(), task2->title());
0135         QCOMPARE(model->data(task3Index).toString(), task3->title());
0136         QCOMPARE(model->data(taskChildTask12Index).toString(), childTask12->title());
0137 
0138         QCOMPARE(model->data(task1Index, Qt::EditRole).toString(), task1->title());
0139         QCOMPARE(model->data(childTask11Index, Qt::EditRole).toString(), childTask11->title());
0140         QCOMPARE(model->data(childTask12Index, Qt::EditRole).toString(), childTask12->title());
0141         QCOMPARE(model->data(task2Index, Qt::EditRole).toString(), task2->title());
0142         QCOMPARE(model->data(task3Index, Qt::EditRole).toString(), task3->title());
0143         QCOMPARE(model->data(taskChildTask12Index, Qt::EditRole).toString(), childTask12->title());
0144 
0145         QVERIFY(model->data(task1Index, Qt::CheckStateRole).isValid());
0146         QVERIFY(model->data(childTask11Index, Qt::CheckStateRole).isValid());
0147         QVERIFY(model->data(childTask12Index, Qt::CheckStateRole).isValid());
0148         QVERIFY(model->data(task2Index, Qt::CheckStateRole).isValid());
0149         QVERIFY(model->data(task3Index, Qt::CheckStateRole).isValid());
0150         QVERIFY(model->data(taskChildTask12Index, Qt::CheckStateRole).isValid());
0151 
0152         QCOMPARE(model->data(task1Index, Qt::CheckStateRole).toBool(), task1->isDone());
0153         QCOMPARE(model->data(childTask11Index, Qt::CheckStateRole).toBool(), childTask11->isDone());
0154         QCOMPARE(model->data(childTask12Index, Qt::CheckStateRole).toBool(), childTask12->isDone());
0155         QCOMPARE(model->data(task2Index, Qt::CheckStateRole).toBool(), task2->isDone());
0156         QCOMPARE(model->data(task3Index, Qt::CheckStateRole).toBool(), task3->isDone());
0157         QCOMPARE(model->data(taskChildTask12Index, Qt::CheckStateRole).toBool(), childTask12->isDone());
0158 
0159         QVERIFY(model->data(task1Index, Presentation::QueryTreeModelBase::ProjectRole).isValid());
0160         QVERIFY(model->data(task2Index, Presentation::QueryTreeModelBase::ProjectRole).isValid());
0161         QCOMPARE(model->data(task1Index, Presentation::QueryTreeModelBase::ProjectRole).toString(), QString());
0162         QCOMPARE(model->data(task2Index, Presentation::QueryTreeModelBase::ProjectRole).toString(), QString("KDE"));
0163         QCOMPARE(model->data(task1Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), false);
0164         QCOMPARE(model->data(task2Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), false);
0165         QVERIFY(!model->data(childTask11Index, Presentation::QueryTreeModelBase::ProjectRole).isValid());
0166         QVERIFY(!model->data(childTask12Index, Presentation::QueryTreeModelBase::ProjectRole).isValid());
0167         QCOMPARE(model->data(childTask11Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), true);
0168         QCOMPARE(model->data(childTask12Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), true);
0169 
0170         // WHEN
0171         taskRepositoryMock(&Domain::TaskRepository::update).when(task1).thenReturn(new FakeJob(this));
0172         taskRepositoryMock(&Domain::TaskRepository::update).when(childTask11).thenReturn(new FakeJob(this));
0173         taskRepositoryMock(&Domain::TaskRepository::update).when(childTask12).thenReturn(new FakeJob(this));
0174         taskRepositoryMock(&Domain::TaskRepository::update).when(task2).thenReturn(new FakeJob(this));
0175         taskRepositoryMock(&Domain::TaskRepository::update).when(task3).thenReturn(new FakeJob(this));
0176 
0177         QVERIFY(model->setData(task1Index, "newTask1"));
0178         QVERIFY(model->setData(childTask11Index, "newChildTask11"));
0179         QVERIFY(model->setData(task2Index, "newTask2"));
0180         QVERIFY(model->setData(task3Index, "newTask3"));
0181         QVERIFY(model->setData(taskChildTask12Index, "newChildTask12"));
0182 
0183         QVERIFY(model->setData(task1Index, Qt::Unchecked, Qt::CheckStateRole));
0184         QVERIFY(model->setData(childTask11Index, Qt::Unchecked, Qt::CheckStateRole));
0185         QVERIFY(model->setData(task2Index, Qt::Checked, Qt::CheckStateRole));
0186         QVERIFY(model->setData(task3Index, Qt::Unchecked, Qt::CheckStateRole));
0187         QVERIFY(model->setData(taskChildTask12Index, Qt::Checked, Qt::CheckStateRole));
0188 
0189         // THEN
0190         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task1).exactly(2));
0191         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask11).exactly(2));
0192         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask12).exactly(2));
0193         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task2).exactly(2));
0194         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task3).exactly(2));
0195 
0196         QCOMPARE(task1->title(), QStringLiteral("newTask1"));
0197         QCOMPARE(childTask11->title(), QStringLiteral("newChildTask11"));
0198         QCOMPARE(childTask12->title(), QStringLiteral("newChildTask12"));
0199         QCOMPARE(task2->title(), QStringLiteral("newTask2"));
0200         QCOMPARE(task3->title(), QStringLiteral("newTask3"));
0201 
0202         QCOMPARE(task1->isDone(), false);
0203         QCOMPARE(childTask11->isDone(), false);
0204         QCOMPARE(childTask12->isDone(), true);
0205         QCOMPARE(task2->isDone(), true);
0206         QCOMPARE(task3->isDone(), false);
0207 
0208         // WHEN
0209         auto data = std::unique_ptr<QMimeData>(model->mimeData(QModelIndexList() << childTask12Index));
0210 
0211         // THEN
0212         QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object")));
0213         QCOMPARE(data->property("objects").value<Domain::Task::List>(),
0214                  Domain::Task::List() << childTask12);
0215 
0216         // WHEN
0217         auto childTask2 = Domain::Task::Ptr::create();
0218         taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask11, childTask2).thenReturn(new FakeJob(this));
0219         data.reset(new QMimeData);
0220         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0221         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask2));
0222         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, childTask11Index);
0223 
0224         // THEN
0225         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask11, childTask2).exactly(1));
0226 
0227 
0228         // WHEN
0229         auto childTask3 = Domain::Task::Ptr::create();
0230         auto childTask4 = Domain::Task::Ptr::create();
0231         taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask3).thenReturn(new FakeJob(this));
0232         taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask4).thenReturn(new FakeJob(this));
0233         data.reset(new QMimeData);
0234         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0235         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask3 << childTask4));
0236         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, childTask12Index);
0237 
0238         // THEN
0239         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask3).exactly(1));
0240         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask4).exactly(1));
0241 
0242         // WHEN
0243         auto childTask5 = Domain::Task::Ptr::create();
0244         QVERIFY(!childTask5->startDate().isValid());
0245         taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask5).thenReturn(new FakeJob(this));
0246         data.reset(new QMimeData);
0247         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0248         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask5));
0249         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, QModelIndex());
0250 
0251         // THEN
0252         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask5).exactly(1));
0253         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask5).exactly(0));
0254         QCOMPARE(childTask5->startDate(), today);
0255     }
0256 
0257     void shouldAddTasksInWorkdayPage()
0258     {
0259         // GIVEN
0260 
0261         // ... in fact we won't list any model
0262         Utils::MockObject<Domain::TaskQueries> taskQueriesMock;
0263 
0264         // We'll gladly create a task though
0265         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
0266         taskRepositoryMock(&Domain::TaskRepository::create).when(any<Domain::Task::Ptr>()).thenReturn(new FakeJob(this));
0267 
0268         Presentation::WorkdayPageModel workday(taskQueriesMock.getInstance(),
0269                                                taskRepositoryMock.getInstance());
0270 
0271         // WHEN
0272         auto title = QStringLiteral("New task");
0273         auto today = Utils::DateTime::currentDate();
0274         auto task = workday.addItem(title);
0275 
0276         // THEN
0277         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::create).when(any<Domain::Task::Ptr>()).exactly(1));
0278 
0279         QVERIFY(task);
0280         QCOMPARE(task->title(), title);
0281         QCOMPARE(task->startDate(), today);
0282     }
0283 
0284     void shouldAddChildTask()
0285     {
0286         // GIVEN
0287 
0288         // Two tasks
0289         auto task1 = Domain::Task::Ptr::create();
0290         auto task2 = Domain::Task::Ptr::create();
0291         auto taskProvider = Domain::QueryResultProvider<Domain::Task::Ptr>::Ptr::create();
0292         auto taskResult = Domain::QueryResult<Domain::Task::Ptr>::create(taskProvider);
0293         taskProvider->append(task1);
0294         taskProvider->append(task2);
0295 
0296         Utils::MockObject<Domain::TaskQueries> taskQueriesMock;
0297         taskQueriesMock(&Domain::TaskQueries::findWorkdayTopLevel).when().thenReturn(taskResult);
0298         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0299         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0300         taskQueriesMock(&Domain::TaskQueries::findProject).when(any<Domain::Task::Ptr>()).thenReturn(Domain::QueryResult<Domain::Project::Ptr>::Ptr());
0301 
0302         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
0303         taskRepositoryMock(&Domain::TaskRepository::createChild).when(any<Domain::Task::Ptr>(),
0304                                                                       any<Domain::Task::Ptr>())
0305                                                                 .thenReturn(new FakeJob(this));
0306 
0307         Presentation::WorkdayPageModel workday(taskQueriesMock.getInstance(),
0308                                                taskRepositoryMock.getInstance());
0309 
0310         // WHEN
0311         const auto title = QStringLiteral("New task");
0312         const auto parentIndex = workday.centralListModel()->index(0, 0);
0313         const auto createdTask = workday.addItem(title, parentIndex);
0314 
0315         // THEN
0316         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createChild).when(any<Domain::Task::Ptr>(),
0317                                                                               any<Domain::Task::Ptr>())
0318                                                                         .exactly(1));
0319 
0320         QVERIFY(createdTask);
0321         QCOMPARE(createdTask->title(), title);
0322         QVERIFY(!createdTask->startDate().isValid());
0323     }
0324 
0325     void shouldDeleteItems()
0326     {
0327         // GIVEN
0328 
0329         // Two tasks
0330         auto task1 = Domain::Task::Ptr::create();
0331         auto task2 = Domain::Task::Ptr::create();
0332         auto taskProvider = Domain::QueryResultProvider<Domain::Task::Ptr>::Ptr::create();
0333         auto taskResult = Domain::QueryResult<Domain::Task::Ptr>::create(taskProvider);
0334         taskProvider->append(task1);
0335         taskProvider->append(task2);
0336 
0337         Utils::MockObject<Domain::TaskQueries> taskQueriesMock;
0338         taskQueriesMock(&Domain::TaskQueries::findWorkdayTopLevel).when().thenReturn(taskResult);
0339         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0340         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0341         taskQueriesMock(&Domain::TaskQueries::findProject).when(any<Domain::Task::Ptr>()).thenReturn(Domain::QueryResult<Domain::Project::Ptr>::Ptr());
0342 
0343         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
0344         taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).thenReturn(new FakeJob(this));
0345 
0346         Presentation::WorkdayPageModel workday(taskQueriesMock.getInstance(),
0347                                                taskRepositoryMock.getInstance());
0348 
0349         // WHEN
0350         const QModelIndex index = workday.centralListModel()->index(1, 0);
0351         workday.removeItem(index);
0352 
0353         // THEN
0354         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).exactly(1));
0355     }
0356 
0357     void shouldPromoteItem()
0358     {
0359         // GIVEN
0360 
0361         // Two tasks
0362         auto task1 = Domain::Task::Ptr::create();
0363         auto task2 = Domain::Task::Ptr::create();
0364         auto taskProvider = Domain::QueryResultProvider<Domain::Task::Ptr>::Ptr::create();
0365         auto taskResult = Domain::QueryResult<Domain::Task::Ptr>::create(taskProvider);
0366         taskProvider->append(task1);
0367         taskProvider->append(task2);
0368 
0369         Utils::MockObject<Domain::TaskQueries> taskQueriesMock;
0370         taskQueriesMock(&Domain::TaskQueries::findWorkdayTopLevel).when().thenReturn(taskResult);
0371         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0372         taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult<Domain::Task::Ptr>::Ptr());
0373         taskQueriesMock(&Domain::TaskQueries::findProject).when(any<Domain::Task::Ptr>()).thenReturn(Domain::QueryResult<Domain::Project::Ptr>::Ptr());
0374 
0375         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
0376         taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this));
0377 
0378         Presentation::WorkdayPageModel workday(taskQueriesMock.getInstance(),
0379                                                taskRepositoryMock.getInstance());
0380 
0381         // WHEN
0382         const QModelIndex index = workday.centralListModel()->index(1, 0);
0383         workday.promoteItem(index);
0384 
0385         // THEN
0386         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1));
0387     }
0388 };
0389 
0390 ZANSHIN_TEST_MAIN(WorkdayPageModelTest)
0391 
0392 #include "workdaypagemodeltest.moc"