File indexing completed on 2025-01-05 04:59:58

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
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 <KLocalizedString>
0014 
0015 #include "utils/mockobject.h"
0016 #include "utils/datetime.h"
0017 
0018 #include "presentation/alltaskspagemodel.h"
0019 #include "presentation/availablepagesmodel.h"
0020 #include "presentation/contextpagemodel.h"
0021 #include "presentation/errorhandler.h"
0022 #include "presentation/inboxpagemodel.h"
0023 #include "presentation/projectpagemodel.h"
0024 #include "presentation/querytreemodelbase.h"
0025 #include "presentation/workdaypagemodel.h"
0026 
0027 #include "testlib/fakejob.h"
0028 
0029 using namespace mockitopp;
0030 using namespace mockitopp::matcher;
0031 
0032 class FakeErrorHandler : public Presentation::ErrorHandler
0033 {
0034 public:
0035     void doDisplayMessage(const QString &message) override
0036     {
0037         m_message = message;
0038     }
0039 
0040     QString m_message;
0041 };
0042 
0043 static const int s_projectsRow = 2;
0044 static const int s_contextRow = 3;
0045 static const int s_allTasksRow = 4;
0046 
0047 class AvailablePagesModelTest : public QObject
0048 {
0049     Q_OBJECT
0050 private slots:
0051     void shouldListAvailablePages()
0052     {
0053         // GIVEN
0054 
0055         // Two selected data sources
0056         auto source1 = Domain::DataSource::Ptr::create();
0057         source1->setName("source1");
0058         auto source2 = Domain::DataSource::Ptr::create();
0059         source2->setName("source2");
0060         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0061         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0062         sourceProvider->append(source1);
0063         sourceProvider->append(source2);
0064 
0065         // Two projects under source 1
0066         auto project11 = Domain::Project::Ptr::create();
0067         project11->setName(QStringLiteral("Project 11"));
0068         auto project12 = Domain::Project::Ptr::create();
0069         project12->setName(QStringLiteral("Project 12"));
0070         auto project1Provider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0071         auto project1Result = Domain::QueryResult<Domain::Project::Ptr>::create(project1Provider);
0072         project1Provider->append(project12);
0073         project1Provider->append(project11); // note: reversed order, to test sorting
0074 
0075         // Two projects under source 2
0076         auto project21 = Domain::Project::Ptr::create();
0077         project21->setName(QStringLiteral("Project 21"));
0078         auto project22 = Domain::Project::Ptr::create();
0079         project22->setName(QStringLiteral("Project 22"));
0080         auto project2Provider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0081         auto project2Result = Domain::QueryResult<Domain::Project::Ptr>::create(project2Provider);
0082         project2Provider->append(project22);
0083         project2Provider->append(project21); // note: reversed order, to test sorting
0084 
0085         // Two contexts
0086         auto context1 = Domain::Context::Ptr::create();
0087         context1->setName(QStringLiteral("context 1"));
0088         auto context2 = Domain::Context::Ptr::create();
0089         context2->setName(QStringLiteral("context 2"));
0090         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0091         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0092         contextProvider->append(context1);
0093         contextProvider->append(context2);
0094 
0095         // One task (used for dropping later on)
0096         Domain::Task::Ptr taskToDrop(new Domain::Task);
0097 
0098         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0099         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0100         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source1).thenReturn(project1Result);
0101         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source2).thenReturn(project2Result);
0102 
0103         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0104         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
0105 
0106         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0107         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0108 
0109         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0110 
0111         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0112                                                     Domain::ProjectQueries::Ptr(),
0113                                                     projectRepositoryMock.getInstance(),
0114                                                     contextQueriesMock.getInstance(),
0115                                                     contextRepositoryMock.getInstance(),
0116                                                     Domain::TaskQueries::Ptr(),
0117                                                     taskRepositoryMock.getInstance());
0118 
0119         // WHEN
0120         QAbstractItemModel *model = pages.pageListModel();
0121 
0122         // THEN
0123         const QModelIndex inboxIndex = model->index(0, 0);
0124         const QModelIndex workdayIndex = model->index(1, 0);
0125         const QModelIndex projectsIndex = model->index(s_projectsRow, 0);
0126         const QModelIndex source1Index = model->index(0, 0, projectsIndex);
0127         const QModelIndex project11Index = model->index(0, 0, source1Index);
0128         const QModelIndex project12Index = model->index(1, 0, source1Index);
0129         const QModelIndex source2Index = model->index(1, 0, projectsIndex);
0130         const QModelIndex project21Index = model->index(0, 0, source2Index);
0131         const QModelIndex project22Index = model->index(1, 0, source2Index);
0132         const QModelIndex contextsIndex = model->index(s_contextRow, 0);
0133         const QModelIndex context1Index = model->index(0, 0, contextsIndex);
0134         const QModelIndex context2Index = model->index(1, 0, contextsIndex);
0135         const QModelIndex allTasksIndex = model->index(s_allTasksRow, 0);
0136 
0137         QCOMPARE(model->rowCount(), 5);
0138         QCOMPARE(model->rowCount(inboxIndex), 0);
0139         QCOMPARE(model->rowCount(workdayIndex), 0);
0140         QCOMPARE(model->rowCount(projectsIndex), 2);
0141         QCOMPARE(model->rowCount(source1Index), 2);
0142         QCOMPARE(model->rowCount(project11Index), 0);
0143         QCOMPARE(model->rowCount(project12Index), 0);
0144         QCOMPARE(model->rowCount(source2Index), 2);
0145         QCOMPARE(model->rowCount(project21Index), 0);
0146         QCOMPARE(model->rowCount(project22Index), 0);
0147         QCOMPARE(model->rowCount(contextsIndex), 2);
0148         QCOMPARE(model->rowCount(context1Index), 0);
0149         QCOMPARE(model->rowCount(context2Index), 0);
0150         QCOMPARE(model->rowCount(allTasksIndex), 0);
0151 
0152         const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable
0153                                          | Qt::ItemIsEnabled
0154                                          | Qt::ItemIsEditable;
0155         QCOMPARE(model->flags(inboxIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled);
0156         QCOMPARE(model->flags(workdayIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled);
0157         QCOMPARE(model->flags(projectsIndex), Qt::NoItemFlags);
0158         QCOMPARE(model->flags(source1Index), Qt::NoItemFlags);
0159         QCOMPARE(model->flags(project11Index), defaultFlags | Qt::ItemIsDropEnabled);
0160         QCOMPARE(model->flags(project12Index), defaultFlags | Qt::ItemIsDropEnabled);
0161         QCOMPARE(model->flags(source2Index), Qt::NoItemFlags);
0162         QCOMPARE(model->flags(project21Index), defaultFlags | Qt::ItemIsDropEnabled);
0163         QCOMPARE(model->flags(project22Index), defaultFlags | Qt::ItemIsDropEnabled);
0164         QCOMPARE(model->flags(contextsIndex), Qt::NoItemFlags);
0165         QCOMPARE(model->flags(context1Index), defaultFlags | Qt::ItemIsDropEnabled);
0166         QCOMPARE(model->flags(context2Index), defaultFlags | Qt::ItemIsDropEnabled);
0167         QCOMPARE(model->flags(allTasksIndex), (defaultFlags & ~(Qt::ItemIsEditable)));
0168 
0169         QCOMPARE(model->data(inboxIndex).toString(), i18n("Inbox"));
0170         QCOMPARE(model->data(workdayIndex).toString(), i18n("Workday"));
0171         QCOMPARE(model->data(projectsIndex).toString(), i18n("Projects"));
0172         QCOMPARE(model->data(source1Index).toString(), source1->name());
0173         QCOMPARE(model->data(project11Index).toString(), project11->name());
0174         QCOMPARE(model->data(project12Index).toString(), project12->name());
0175         QCOMPARE(model->data(source2Index).toString(), source2->name());
0176         QCOMPARE(model->data(project21Index).toString(), project21->name());
0177         QCOMPARE(model->data(project22Index).toString(), project22->name());
0178         QCOMPARE(model->data(contextsIndex).toString(), i18n("Contexts"));
0179         QCOMPARE(model->data(context1Index).toString(), context1->name());
0180         QCOMPARE(model->data(context2Index).toString(), context2->name());
0181         QCOMPARE(model->data(allTasksIndex).toString(), i18n("All Tasks"));
0182 
0183         QVERIFY(!model->data(inboxIndex, Qt::EditRole).isValid());
0184         QVERIFY(!model->data(workdayIndex, Qt::EditRole).isValid());
0185         QVERIFY(!model->data(projectsIndex, Qt::EditRole).isValid());
0186         QVERIFY(!model->data(source1Index, Qt::EditRole).isValid());
0187         QCOMPARE(model->data(project11Index, Qt::EditRole).toString(), project11->name());
0188         QCOMPARE(model->data(project12Index, Qt::EditRole).toString(), project12->name());
0189         QVERIFY(!model->data(source2Index, Qt::EditRole).isValid());
0190         QCOMPARE(model->data(project21Index, Qt::EditRole).toString(), project21->name());
0191         QCOMPARE(model->data(project22Index, Qt::EditRole).toString(), project22->name());
0192         QVERIFY(!model->data(contextsIndex, Qt::EditRole).isValid());
0193         QCOMPARE(model->data(context1Index, Qt::EditRole).toString(), context1->name());
0194         QCOMPARE(model->data(context2Index, Qt::EditRole).toString(), context2->name());
0195         QVERIFY(!model->data(allTasksIndex, Qt::EditRole).isValid());
0196 
0197         QCOMPARE(model->data(inboxIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("mail-folder-inbox"));
0198         QCOMPARE(model->data(workdayIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("go-jump-today"));
0199         QCOMPARE(model->data(projectsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder"));
0200         QCOMPARE(model->data(source1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder"));
0201         QCOMPARE(model->data(project11Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks"));
0202         QCOMPARE(model->data(project12Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks"));
0203         QCOMPARE(model->data(source2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder"));
0204         QCOMPARE(model->data(project21Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks"));
0205         QCOMPARE(model->data(project22Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks"));
0206         QCOMPARE(model->data(contextsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder"));
0207         QCOMPARE(model->data(context1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-notes"));
0208         QCOMPARE(model->data(context2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-notes"));
0209         QCOMPARE(model->data(allTasksIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks"));
0210 
0211         QVERIFY(!model->data(inboxIndex, Qt::CheckStateRole).isValid());
0212         QVERIFY(!model->data(workdayIndex, Qt::CheckStateRole).isValid());
0213         QVERIFY(!model->data(projectsIndex, Qt::CheckStateRole).isValid());
0214         QVERIFY(!model->data(source1Index, Qt::CheckStateRole).isValid());
0215         QVERIFY(!model->data(project11Index, Qt::CheckStateRole).isValid());
0216         QVERIFY(!model->data(project12Index, Qt::CheckStateRole).isValid());
0217         QVERIFY(!model->data(source2Index, Qt::CheckStateRole).isValid());
0218         QVERIFY(!model->data(project21Index, Qt::CheckStateRole).isValid());
0219         QVERIFY(!model->data(project22Index, Qt::CheckStateRole).isValid());
0220         QVERIFY(!model->data(contextsIndex, Qt::CheckStateRole).isValid());
0221         QVERIFY(!model->data(context1Index, Qt::CheckStateRole).isValid());
0222         QVERIFY(!model->data(context2Index, Qt::CheckStateRole).isValid());
0223         QVERIFY(!model->data(allTasksIndex, Qt::CheckStateRole).isValid());
0224 
0225         // WHEN
0226         projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).thenReturn(new FakeJob(this));
0227         projectRepositoryMock(&Domain::ProjectRepository::update).when(project12).thenReturn(new FakeJob(this));
0228         projectRepositoryMock(&Domain::ProjectRepository::update).when(project21).thenReturn(new FakeJob(this));
0229         projectRepositoryMock(&Domain::ProjectRepository::update).when(project22).thenReturn(new FakeJob(this));
0230         contextRepositoryMock(&Domain::ContextRepository::update).when(context1).thenReturn(new FakeJob(this));
0231         contextRepositoryMock(&Domain::ContextRepository::update).when(context2).thenReturn(new FakeJob(this));
0232 
0233         QVERIFY(!model->setData(inboxIndex, "Foo"));
0234         QVERIFY(!model->setData(projectsIndex, "Foo"));
0235         QVERIFY(!model->setData(source1Index, "Foo"));
0236         QVERIFY(model->setData(project11Index, "New Project 11"));
0237         QVERIFY(model->setData(project12Index, "New Project 12"));
0238         QVERIFY(!model->setData(source2Index, "Foo"));
0239         QVERIFY(model->setData(project21Index, "New Project 21"));
0240         QVERIFY(model->setData(project22Index, "New Project 22"));
0241         QVERIFY(!model->setData(contextsIndex, "Foo"));
0242         QVERIFY(model->setData(context1Index, "New Context 1"));
0243         QVERIFY(model->setData(context2Index, "New Context 2"));
0244 
0245         // THEN
0246         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).exactly(1));
0247         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project12).exactly(1));
0248         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project21).exactly(1));
0249         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project22).exactly(1));
0250         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::update).when(context1).exactly(1));
0251         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::update).when(context2).exactly(1));
0252 
0253         QCOMPARE(project11->name(), QStringLiteral("New Project 11"));
0254         QCOMPARE(project12->name(), QStringLiteral("New Project 12"));
0255         QCOMPARE(project21->name(), QStringLiteral("New Project 21"));
0256         QCOMPARE(project22->name(), QStringLiteral("New Project 22"));
0257         QCOMPARE(context1->name(), QStringLiteral("New Context 1"));
0258         QCOMPARE(context2->name(), QStringLiteral("New Context 2"));
0259 
0260         // WHEN
0261         projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop).thenReturn(new FakeJob(this));
0262         auto data = std::make_unique<QMimeData>();
0263         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0264         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop));
0265         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project11Index);
0266 
0267         // THEN
0268         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop).exactly(1));
0269 
0270         // WHEN a task is dropped on a context
0271         contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop).thenReturn(new FakeJob(this));
0272         data.reset(new QMimeData);
0273         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0274         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop));
0275         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index);
0276 
0277         // THEN
0278         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop).exactly(1));
0279 
0280         // WHEN
0281         projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).thenReturn(new FakeJob(this));
0282         taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop).thenReturn(new FakeJob(this));
0283         data.reset(new QMimeData);
0284         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0285         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop));
0286         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex);
0287         QTest::qWait(150);
0288 
0289         // THEN
0290         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).exactly(1));
0291         QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop).exactly(1));
0292 
0293         // WHEN
0294         Domain::Task::Ptr taskToDrop2(new Domain::Task);
0295         projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop2).thenReturn(new FakeJob(this));
0296         data.reset(new QMimeData);
0297         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0298         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop2));
0299         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project11Index);
0300 
0301         // THEN
0302         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop2).exactly(1));
0303 
0304         // WHEN two tasks are dropped on a context
0305         Domain::Task::Ptr taskToDrop3(new Domain::Task);
0306         Domain::Task::Ptr taskToDrop4(new Domain::Task);
0307         contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop3).thenReturn(new FakeJob(this));
0308         contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop4).thenReturn(new FakeJob(this));
0309         data.reset(new QMimeData);
0310         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0311         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop3 << taskToDrop4));
0312         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index);
0313 
0314         // THEN
0315         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop3).exactly(1));
0316         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop4).exactly(1));
0317 
0318         // WHEN a task is drop on the workday
0319         Domain::Task::Ptr taskToDrop5(new Domain::Task);
0320         taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop5).thenReturn(new FakeJob(this));
0321         data.reset(new QMimeData);
0322         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0323         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop5));
0324         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, workdayIndex);
0325 
0326         // THEN
0327         QCOMPARE(taskToDrop5->startDate(), Utils::DateTime::currentDate());
0328 
0329         // WHEN two task are drop on the workday
0330         Domain::Task::Ptr taskToDrop6(new Domain::Task);
0331         Domain::Task::Ptr taskToDrop7(new Domain::Task);
0332         taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop6).thenReturn(new FakeJob(this));
0333         taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop7).thenReturn(new FakeJob(this));
0334         data.reset(new QMimeData);
0335         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
0336         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop6 << taskToDrop7));
0337         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, workdayIndex);
0338 
0339         // THEN
0340         QCOMPARE(taskToDrop6->startDate(), Utils::DateTime::currentDate());
0341         QCOMPARE(taskToDrop7->startDate(), Utils::DateTime::currentDate());
0342     }
0343 
0344 
0345 
0346     void shouldCreateInboxPage()
0347     {
0348         // GIVEN
0349 
0350         // Empty sources provider
0351         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0352         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0353         // Empty context provider
0354         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0355         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0356 
0357         // context mocking
0358         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0359         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0360 
0361         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0362 
0363         // sources mocking
0364         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0365         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0366 
0367         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0368 
0369         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0370                                                     Domain::ProjectQueries::Ptr(),
0371                                                     projectRepositoryMock.getInstance(),
0372                                                     contextQueriesMock.getInstance(),
0373                                                     contextRepositoryMock.getInstance(),
0374                                                     Domain::TaskQueries::Ptr(),
0375                                                     Domain::TaskRepository::Ptr());
0376 
0377         // WHEN
0378         QAbstractItemModel *model = pages.pageListModel();
0379 
0380         // THEN
0381         const QModelIndex inboxIndex = model->index(0, 0);
0382 
0383         QObject *inboxPage = pages.createPageForIndex(inboxIndex);
0384         QVERIFY(qobject_cast<Presentation::InboxPageModel*>(inboxPage));
0385     }
0386 
0387     void shouldCreateWorkdayPage()
0388     {
0389         // GIVEN
0390 
0391         // Empty sources provider
0392         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0393         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0394         // Empty context provider
0395         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0396         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0397 
0398         // context mocking
0399         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0400         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0401 
0402         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0403 
0404         // sources mocking
0405         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0406         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0407 
0408         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0409 
0410         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0411                                                     Domain::ProjectQueries::Ptr(),
0412                                                     projectRepositoryMock.getInstance(),
0413                                                     contextQueriesMock.getInstance(),
0414                                                     contextRepositoryMock.getInstance(),
0415                                                     Domain::TaskQueries::Ptr(),
0416                                                     Domain::TaskRepository::Ptr());
0417 
0418         // WHEN
0419         QAbstractItemModel *model = pages.pageListModel();
0420 
0421         // THEN
0422         const QModelIndex workdayIndex = model->index(1, 0);
0423 
0424         QObject *workdayPage = pages.createPageForIndex(workdayIndex);
0425         QVERIFY(qobject_cast<Presentation::WorkdayPageModel*>(workdayPage));
0426     }
0427 
0428     void shouldCreateAllTasksPage()
0429     {
0430         // GIVEN
0431 
0432         // Empty sources provider
0433         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0434         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0435         // Empty context provider
0436         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0437         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0438 
0439         // context mocking
0440         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0441         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0442 
0443         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0444 
0445         // sources mocking
0446         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0447         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0448 
0449         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0450 
0451         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0452                                                     Domain::ProjectQueries::Ptr(),
0453                                                     projectRepositoryMock.getInstance(),
0454                                                     contextQueriesMock.getInstance(),
0455                                                     contextRepositoryMock.getInstance(),
0456                                                     Domain::TaskQueries::Ptr(),
0457                                                     Domain::TaskRepository::Ptr());
0458 
0459         // WHEN
0460         QAbstractItemModel *model = pages.pageListModel();
0461 
0462         // THEN
0463         const QModelIndex allTasksIndex = model->index(s_allTasksRow, 0);
0464 
0465         QObject *workdayPage = pages.createPageForIndex(allTasksIndex);
0466         QVERIFY(qobject_cast<Presentation::AllTasksPageModel*>(workdayPage));
0467     }
0468 
0469     void shouldCreateProjectsPage()
0470     {
0471         // GIVEN
0472 
0473         // One selected data source
0474         auto source = Domain::DataSource::Ptr::create();
0475         source->setName("source");
0476         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0477         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0478         sourceProvider->append(source);
0479 
0480         // Two projects
0481         auto project1 = Domain::Project::Ptr::create();
0482         project1->setName(QStringLiteral("Project 11"));
0483         auto project2 = Domain::Project::Ptr::create();
0484         project2->setName(QStringLiteral("Project 12"));
0485         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0486         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
0487         projectProvider->append(project1);
0488         projectProvider->append(project2);
0489 
0490         // No contexts
0491         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0492         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0493 
0494         // data source mocking
0495         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0496         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0497         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
0498 
0499         // projects mocking
0500         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0501 
0502         // contexts mocking
0503         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0504         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0505 
0506         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0507                                                     Domain::ProjectQueries::Ptr(),
0508                                                     projectRepositoryMock.getInstance(),
0509                                                     contextQueriesMock.getInstance(),
0510                                                     Domain::ContextRepository::Ptr(),
0511                                                     Domain::TaskQueries::Ptr(),
0512                                                     Domain::TaskRepository::Ptr());
0513 
0514         // WHEN
0515         QAbstractItemModel *model = pages.pageListModel();
0516 
0517         // THEN
0518         const QModelIndex projectsIndex = model->index(s_projectsRow, 0);
0519         const QModelIndex sourceIndex = model->index(0, 0, projectsIndex);
0520         const QModelIndex project1Index = model->index(0, 0, sourceIndex);
0521         const QModelIndex project2Index = model->index(1, 0, sourceIndex);
0522 
0523         QObject *projectsPage = pages.createPageForIndex(projectsIndex);
0524         QObject *sourcesPage = pages.createPageForIndex(sourceIndex);
0525         QObject *project1Page = pages.createPageForIndex(project1Index);
0526         QObject *project2Page = pages.createPageForIndex(project2Index);
0527 
0528         QVERIFY(!projectsPage);
0529         QVERIFY(!sourcesPage);
0530         QVERIFY(qobject_cast<Presentation::ProjectPageModel*>(project1Page));
0531         QCOMPARE(qobject_cast<Presentation::ProjectPageModel*>(project1Page)->project(), project1);
0532         QVERIFY(qobject_cast<Presentation::ProjectPageModel*>(project2Page));
0533         QCOMPARE(qobject_cast<Presentation::ProjectPageModel*>(project2Page)->project(), project2);
0534     }
0535 
0536     void shouldCreateContextsPage()
0537     {
0538         // GIVEN
0539 
0540         // Two contexts
0541         auto context1 = Domain::Context::Ptr::create();
0542         context1->setName(QStringLiteral("context 1"));
0543         auto context2 = Domain::Context::Ptr::create();
0544         context2->setName(QStringLiteral("context 2"));
0545         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0546         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0547         contextProvider->append(context1);
0548         contextProvider->append(context2);
0549 
0550         // Empty sources provider
0551         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0552         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0553 
0554         // contexts mocking
0555         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0556         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0557 
0558         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0559 
0560         // sources mocking
0561         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0562         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0563 
0564         // projects mocking
0565         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0566 
0567 
0568         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0569                                                     Domain::ProjectQueries::Ptr(),
0570                                                     projectRepositoryMock.getInstance(),
0571                                                     contextQueriesMock.getInstance(),
0572                                                     contextRepositoryMock.getInstance(),
0573                                                     Domain::TaskQueries::Ptr(),
0574                                                     Domain::TaskRepository::Ptr());
0575 
0576         // WHEN
0577         QAbstractItemModel *model = pages.pageListModel();
0578 
0579         // THEN
0580         const QModelIndex contextsIndex = model->index(s_contextRow, 0);
0581         const QModelIndex context1Index = model->index(0, 0, contextsIndex);
0582         const QModelIndex context2Index = model->index(1, 0, contextsIndex);
0583 
0584         QObject *contextsPage = pages.createPageForIndex(contextsIndex);
0585         QObject *context1Page = pages.createPageForIndex(context1Index);
0586         QObject *context2Page = pages.createPageForIndex(context2Index);
0587 
0588         QVERIFY(!contextsPage);
0589         QVERIFY(qobject_cast<Presentation::ContextPageModel*>(context1Page));
0590         QCOMPARE(qobject_cast<Presentation::ContextPageModel*>(context1Page)->context(), context1);
0591         QVERIFY(qobject_cast<Presentation::ContextPageModel*>(context2Page));
0592         QCOMPARE(qobject_cast<Presentation::ContextPageModel*>(context2Page)->context(), context2);
0593     }
0594 
0595     void shouldAddProjects()
0596     {
0597         // GIVEN
0598 
0599         auto source = Domain::DataSource::Ptr::create();
0600 
0601         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0602         projectRepositoryMock(&Domain::ProjectRepository::create).when(any<Domain::Project::Ptr>(),
0603                                                                        any<Domain::DataSource::Ptr>())
0604                                                                  .thenReturn(new FakeJob(this));
0605 
0606         Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(),
0607                                                     Domain::ProjectQueries::Ptr(),
0608                                                     projectRepositoryMock.getInstance(),
0609                                                     Domain::ContextQueries::Ptr(),
0610                                                     Domain::ContextRepository::Ptr(),
0611                                                     Domain::TaskQueries::Ptr(),
0612                                                     Domain::TaskRepository::Ptr());
0613 
0614         // WHEN
0615         pages.addProject(QStringLiteral("Foo"), source);
0616 
0617         // THEN
0618         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::create).when(any<Domain::Project::Ptr>(),
0619                                                                                any<Domain::DataSource::Ptr>())
0620                                                                          .exactly(1));
0621     }
0622 
0623     void shouldGetAnErrorMessageWhenAddProjectFailed()
0624     {
0625         // GIVEN
0626 
0627         auto source = Domain::DataSource::Ptr::create();
0628         source->setName(QStringLiteral("Source1"));
0629 
0630         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0631         auto job = new FakeJob(this);
0632         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
0633         projectRepositoryMock(&Domain::ProjectRepository::create).when(any<Domain::Project::Ptr>(),
0634                                                                        any<Domain::DataSource::Ptr>())
0635                                                                  .thenReturn(job);
0636 
0637         Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(),
0638                                                     Domain::ProjectQueries::Ptr(),
0639                                                     projectRepositoryMock.getInstance(),
0640                                                     Domain::ContextQueries::Ptr(),
0641                                                     Domain::ContextRepository::Ptr(),
0642                                                     Domain::TaskQueries::Ptr(),
0643                                                     Domain::TaskRepository::Ptr());
0644         FakeErrorHandler errorHandler;
0645         pages.setErrorHandler(&errorHandler);
0646 
0647         // WHEN
0648         pages.addProject(QStringLiteral("Foo"), source);
0649 
0650         // THEN
0651         QTest::qWait(150);
0652         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add project Foo in dataSource Source1: Foo"));
0653     }
0654 
0655     void shouldAddContexts()
0656     {
0657         // GIVEN
0658         auto source = Domain::DataSource::Ptr::create();
0659         source->setName(QStringLiteral("Source1"));
0660 
0661         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0662         contextRepositoryMock(&Domain::ContextRepository::create).when(any<Domain::Context::Ptr>(), any<Domain::DataSource::Ptr>())
0663                                                                  .thenReturn(new FakeJob(this));
0664 
0665         Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(),
0666                                                     Domain::ProjectQueries::Ptr(),
0667                                                     Domain::ProjectRepository::Ptr(),
0668                                                     Domain::ContextQueries::Ptr(),
0669                                                     contextRepositoryMock.getInstance(),
0670                                                     Domain::TaskQueries::Ptr(),
0671                                                     Domain::TaskRepository::Ptr());
0672 
0673         // WHEN
0674         pages.addContext(QStringLiteral("Foo"), source);
0675 
0676         // THEN
0677         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::create).when(any<Domain::Context::Ptr>(), any<Domain::DataSource::Ptr>())
0678                                                                        .exactly(1));
0679     }
0680 
0681     void shouldGetAnErrorMessageWhenAddContextFailed()
0682     {
0683         // GIVEN
0684         auto source = Domain::DataSource::Ptr::create();
0685         source->setName(QStringLiteral("Source1"));
0686 
0687         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0688         auto job = new FakeJob(this);
0689         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
0690         contextRepositoryMock(&Domain::ContextRepository::create).when(any<Domain::Context::Ptr>(), any<Domain::DataSource::Ptr>())
0691                                                                  .thenReturn(job);
0692 
0693         Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(),
0694                                                     Domain::ProjectQueries::Ptr(),
0695                                                     Domain::ProjectRepository::Ptr(),
0696                                                     Domain::ContextQueries::Ptr(),
0697                                                     contextRepositoryMock.getInstance(),
0698                                                     Domain::TaskQueries::Ptr(),
0699                                                     Domain::TaskRepository::Ptr());
0700         FakeErrorHandler errorHandler;
0701         pages.setErrorHandler(&errorHandler);
0702 
0703         // WHEN
0704         pages.addContext(QStringLiteral("Foo"), source);
0705 
0706         // THEN
0707         QTest::qWait(150);
0708         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add context Foo: Foo"));
0709     }
0710 
0711     void shouldRemoveProject()
0712     {
0713         // GIVEN
0714 
0715         // One selected data source
0716         auto source = Domain::DataSource::Ptr::create();
0717         source->setName("source");
0718         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0719         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0720         sourceProvider->append(source);
0721 
0722         // Two projects
0723         auto project1 = Domain::Project::Ptr::create();
0724         project1->setName(QStringLiteral("Project 1"));
0725         auto project2 = Domain::Project::Ptr::create();
0726         project2->setName(QStringLiteral("Project 2"));
0727         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0728         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
0729         projectProvider->append(project1);
0730         projectProvider->append(project2);
0731 
0732         // No contexts
0733         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0734         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0735 
0736         // data source mocking
0737         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0738         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0739         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
0740 
0741         // projects mocking
0742         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0743 
0744         // contexts mocking
0745         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0746         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0747 
0748         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0749                                                     Domain::ProjectQueries::Ptr(),
0750                                                     projectRepositoryMock.getInstance(),
0751                                                     contextQueriesMock.getInstance(),
0752                                                     Domain::ContextRepository::Ptr(),
0753                                                     Domain::TaskQueries::Ptr(),
0754                                                     Domain::TaskRepository::Ptr());
0755 
0756         QAbstractItemModel *model = pages.pageListModel();
0757 
0758         const QModelIndex projectsIndex = model->index(s_projectsRow, 0);
0759         const QModelIndex sourceIndex = model->index(0, 0, projectsIndex);
0760         const QModelIndex project1Index = model->index(0, 0, sourceIndex);
0761 
0762         projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).thenReturn(new FakeJob(this));
0763 
0764         // WHEN
0765         pages.removeItem(project1Index);
0766 
0767         // THEN
0768         QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).exactly(1));
0769     }
0770 
0771     void shouldGetAnErrorMessageWhenRemoveProjectFailed()
0772     {
0773         // GIVEN
0774 
0775         // One selected data source
0776         auto source = Domain::DataSource::Ptr::create();
0777         source->setName("source");
0778         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0779         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0780         sourceProvider->append(source);
0781 
0782         // Two projects
0783         auto project1 = Domain::Project::Ptr::create();
0784         project1->setName(QStringLiteral("Project 1"));
0785         auto project2 = Domain::Project::Ptr::create();
0786         project2->setName(QStringLiteral("Project 2"));
0787         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0788         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
0789         projectProvider->append(project1);
0790         projectProvider->append(project2);
0791 
0792         // No contexts
0793         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0794         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0795 
0796         // data source mocking
0797         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0798         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0799         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
0800 
0801         // projects mocking
0802         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0803 
0804         // contexts mocking
0805         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0806         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0807 
0808         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0809                                                     Domain::ProjectQueries::Ptr(),
0810                                                     projectRepositoryMock.getInstance(),
0811                                                     contextQueriesMock.getInstance(),
0812                                                     Domain::ContextRepository::Ptr(),
0813                                                     Domain::TaskQueries::Ptr(),
0814                                                     Domain::TaskRepository::Ptr());
0815         FakeErrorHandler errorHandler;
0816         pages.setErrorHandler(&errorHandler);
0817 
0818         QAbstractItemModel *model = pages.pageListModel();
0819 
0820         const QModelIndex projectsIndex = model->index(s_projectsRow, 0);
0821         const QModelIndex sourceIndex = model->index(0, 0, projectsIndex);
0822         const QModelIndex project1Index = model->index(0, 0, sourceIndex);
0823 
0824         auto job = new FakeJob(this);
0825         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
0826         projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).thenReturn(job);
0827 
0828         // WHEN
0829         pages.removeItem(project1Index);
0830 
0831         // THEN
0832         QTest::qWait(150);
0833         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove project Project 1: Foo"));
0834     }
0835 
0836     void shouldRemoveContext()
0837     {
0838         // GIVEN
0839 
0840         // Two contexts
0841         auto context1 = Domain::Context::Ptr::create();
0842         context1->setName(QStringLiteral("context 1"));
0843         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0844         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0845         contextProvider->append(context1);
0846 
0847         // Empty sources provider
0848         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0849         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0850 
0851         // contexts mocking
0852         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0853         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0854 
0855         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0856 
0857         // sources mocking
0858         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0859         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0860 
0861 
0862         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0863                                                     Domain::ProjectQueries::Ptr(),
0864                                                     Domain::ProjectRepository::Ptr(),
0865                                                     contextQueriesMock.getInstance(),
0866                                                     contextRepositoryMock.getInstance(),
0867                                                     Domain::TaskQueries::Ptr(),
0868                                                     Domain::TaskRepository::Ptr());
0869 
0870         QAbstractItemModel *model = pages.pageListModel();
0871 
0872         const QModelIndex contextsIndex = model->index(s_contextRow, 0);
0873         const QModelIndex context1Index = model->index(0, 0, contextsIndex);
0874 
0875         contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(new FakeJob(this));
0876 
0877         // WHEN
0878         pages.removeItem(context1Index);
0879 
0880         // THEN
0881         QVERIFY(contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).exactly(1));
0882     }
0883 
0884     void shouldGetAnErrorMessageWhenRemoveContextFailed()
0885     {
0886         // GIVEN
0887 
0888         // Two contexts
0889         auto context1 = Domain::Context::Ptr::create();
0890         context1->setName(QStringLiteral("context 1"));
0891         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0892         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0893         contextProvider->append(context1);
0894 
0895         // Empty sources provider
0896         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0897         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0898 
0899         // contexts mocking
0900         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0901         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0902 
0903         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0904 
0905         // sources mocking
0906         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0907         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0908 
0909 
0910         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0911                                                     Domain::ProjectQueries::Ptr(),
0912                                                     Domain::ProjectRepository::Ptr(),
0913                                                     contextQueriesMock.getInstance(),
0914                                                     contextRepositoryMock.getInstance(),
0915                                                     Domain::TaskQueries::Ptr(),
0916                                                     Domain::TaskRepository::Ptr());
0917         FakeErrorHandler errorHandler;
0918         pages.setErrorHandler(&errorHandler);
0919 
0920         QAbstractItemModel *model = pages.pageListModel();
0921 
0922         const QModelIndex contextsIndex = model->index(s_contextRow, 0);
0923         const QModelIndex context1Index = model->index(0, 0, contextsIndex);
0924 
0925         auto job = new FakeJob(this);
0926         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
0927         contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(job);
0928 
0929         // WHEN
0930         pages.removeItem(context1Index);
0931 
0932         // THEN
0933         QTest::qWait(150);
0934         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove context context 1: Foo"));
0935     }
0936 
0937     void shouldGetAnErrorMessageWhenUpdateProjectFailed()
0938     {
0939         // GIVEN
0940 
0941         // One selected data source
0942         auto source = Domain::DataSource::Ptr::create();
0943         source->setName("source1");
0944         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
0945         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
0946         sourceProvider->append(source);
0947 
0948         // Two projects under the source
0949         auto project1 = Domain::Project::Ptr::create();
0950         project1->setName(QStringLiteral("Project 1"));
0951         auto project2 = Domain::Project::Ptr::create();
0952         project2->setName(QStringLiteral("Project 2"));
0953         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
0954         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
0955         projectProvider->append(project1);
0956         projectProvider->append(project2);
0957 
0958         // Two contexts
0959         auto context1 = Domain::Context::Ptr::create();
0960         context1->setName(QStringLiteral("context 1"));
0961         auto context2 = Domain::Context::Ptr::create();
0962         context2->setName(QStringLiteral("context 2"));
0963         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
0964         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
0965         contextProvider->append(context1);
0966         contextProvider->append(context2);
0967 
0968         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
0969         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
0970         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
0971 
0972         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
0973 
0974         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
0975         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
0976 
0977         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
0978 
0979         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
0980                                                     Domain::ProjectQueries::Ptr(),
0981                                                     projectRepositoryMock.getInstance(),
0982                                                     contextQueriesMock.getInstance(),
0983                                                     contextRepositoryMock.getInstance(),
0984                                                     Domain::TaskQueries::Ptr(),
0985                                                     Domain::TaskRepository::Ptr());
0986 
0987         FakeErrorHandler errorHandler;
0988         pages.setErrorHandler(&errorHandler);
0989         QAbstractItemModel *model = pages.pageListModel();
0990         const QModelIndex projectsIndex = model->index(s_projectsRow, 0);
0991         const QModelIndex sourceIndex = model->index(0, 0, projectsIndex);
0992         const QModelIndex project1Index = model->index(0, 0, sourceIndex);
0993 
0994         // WHEN
0995         auto job = new FakeJob(this);
0996         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
0997         projectRepositoryMock(&Domain::ProjectRepository::update).when(project1).thenReturn(job);
0998 
0999         QVERIFY(model->setData(project1Index, "New Project 1"));
1000 
1001         // THEN
1002         QTest::qWait(150);
1003         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify project Project 1: Foo"));
1004     }
1005 
1006     void shouldGetAnErrorMessageWhenUpdateContextFailed()
1007     {
1008         // GIVEN
1009 
1010         // One selected data source
1011         auto source = Domain::DataSource::Ptr::create();
1012         source->setName("source1");
1013         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
1014         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
1015         sourceProvider->append(source);
1016 
1017         // Two projects under the source
1018         auto project1 = Domain::Project::Ptr::create();
1019         project1->setName(QStringLiteral("Project 1"));
1020         auto project2 = Domain::Project::Ptr::create();
1021         project2->setName(QStringLiteral("Project 2"));
1022         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
1023         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
1024         projectProvider->append(project1);
1025         projectProvider->append(project2);
1026 
1027         // Two contexts
1028         auto context1 = Domain::Context::Ptr::create();
1029         context1->setName(QStringLiteral("context 1"));
1030         auto context2 = Domain::Context::Ptr::create();
1031         context2->setName(QStringLiteral("context 2"));
1032         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
1033         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
1034         contextProvider->append(context1);
1035         contextProvider->append(context2);
1036 
1037         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
1038         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
1039         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
1040 
1041         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
1042 
1043         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
1044         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
1045 
1046         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
1047 
1048         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
1049                                                     Domain::ProjectQueries::Ptr(),
1050                                                     projectRepositoryMock.getInstance(),
1051                                                     contextQueriesMock.getInstance(),
1052                                                     contextRepositoryMock.getInstance(),
1053                                                     Domain::TaskQueries::Ptr(),
1054                                                     Domain::TaskRepository::Ptr());
1055 
1056         FakeErrorHandler errorHandler;
1057         pages.setErrorHandler(&errorHandler);
1058         QAbstractItemModel *model = pages.pageListModel();
1059         const QModelIndex contextsIndex = model->index(s_contextRow, 0);
1060         const QModelIndex context1Index = model->index(0, 0, contextsIndex);
1061 
1062         // WHEN
1063         auto job = new FakeJob(this);
1064         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
1065         contextRepositoryMock(&Domain::ContextRepository::update).when(context1).thenReturn(job);
1066 
1067         QVERIFY(model->setData(context1Index, "New Context 1"));
1068 
1069         // THEN
1070         QTest::qWait(150);
1071         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify context context 1: Foo"));
1072     }
1073 
1074     void shouldGetAnErrorMessageWhenAssociateProjectFailed()
1075     {
1076         // GIVEN
1077 
1078         // One selected data source
1079         auto source = Domain::DataSource::Ptr::create();
1080         source->setName("source1");
1081         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
1082         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
1083         sourceProvider->append(source);
1084 
1085         // Two projects under the source
1086         auto project1 = Domain::Project::Ptr::create();
1087         project1->setName(QStringLiteral("Project 1"));
1088         auto project2 = Domain::Project::Ptr::create();
1089         project2->setName(QStringLiteral("Project 2"));
1090         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
1091         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
1092         projectProvider->append(project1);
1093         projectProvider->append(project2);
1094 
1095         // Two contexts
1096         auto context1 = Domain::Context::Ptr::create();
1097         context1->setName(QStringLiteral("context 1"));
1098         auto context2 = Domain::Context::Ptr::create();
1099         context2->setName(QStringLiteral("context 2"));
1100         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
1101         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
1102         contextProvider->append(context1);
1103         contextProvider->append(context2);
1104 
1105         // One task (used for dropping later on)
1106         Domain::Task::Ptr taskToDrop(new Domain::Task);
1107         taskToDrop->setTitle(QStringLiteral("taskDropped"));
1108 
1109         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
1110         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
1111         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
1112 
1113         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
1114 
1115         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
1116         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
1117 
1118         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
1119 
1120         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
1121 
1122         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
1123                                                     Domain::ProjectQueries::Ptr(),
1124                                                     projectRepositoryMock.getInstance(),
1125                                                     contextQueriesMock.getInstance(),
1126                                                     contextRepositoryMock.getInstance(),
1127                                                     Domain::TaskQueries::Ptr(),
1128                                                     taskRepositoryMock.getInstance());
1129 
1130         FakeErrorHandler errorHandler;
1131         pages.setErrorHandler(&errorHandler);
1132         QAbstractItemModel *model = pages.pageListModel();
1133         const QModelIndex projectsIndex = model->index(s_projectsRow, 0);
1134         const QModelIndex sourceIndex = model->index(0, 0, projectsIndex);
1135         const QModelIndex project1Index = model->index(0, 0, sourceIndex);
1136 
1137         // WHEN
1138         auto job = new FakeJob(this);
1139         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
1140         projectRepositoryMock(&Domain::ProjectRepository::associate).when(project1, taskToDrop).thenReturn(job);
1141         auto data = std::make_unique<QMimeData>();
1142         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
1143         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop));
1144         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project1Index);
1145 
1146         // THEN
1147         QTest::qWait(150);
1148         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add taskDropped to project Project 1: Foo"));
1149     }
1150 
1151     void shouldGetAnErrorMessageWhenAssociateContextFailed()
1152     {
1153         // GIVEN
1154 
1155         // One selected data source
1156         auto source = Domain::DataSource::Ptr::create();
1157         source->setName("source1");
1158         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
1159         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
1160         sourceProvider->append(source);
1161 
1162         // Two projects under the source
1163         auto project1 = Domain::Project::Ptr::create();
1164         project1->setName(QStringLiteral("Project 1"));
1165         auto project2 = Domain::Project::Ptr::create();
1166         project2->setName(QStringLiteral("Project 2"));
1167         auto projectProvider = Domain::QueryResultProvider<Domain::Project::Ptr>::Ptr::create();
1168         auto projectResult = Domain::QueryResult<Domain::Project::Ptr>::create(projectProvider);
1169         projectProvider->append(project1);
1170         projectProvider->append(project2);
1171 
1172         // Two contexts
1173         auto context1 = Domain::Context::Ptr::create();
1174         context1->setName(QStringLiteral("context 1"));
1175         auto context2 = Domain::Context::Ptr::create();
1176         context2->setName(QStringLiteral("context 2"));
1177         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
1178         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
1179         contextProvider->append(context1);
1180         contextProvider->append(context2);
1181 
1182         // One task (used for dropping later on)
1183         Domain::Task::Ptr taskToDrop(new Domain::Task);
1184         taskToDrop->setTitle(QStringLiteral("taskDropped"));
1185 
1186         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
1187         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
1188         dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult);
1189 
1190         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
1191 
1192         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
1193         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
1194 
1195         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
1196 
1197         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
1198 
1199         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
1200                                                     Domain::ProjectQueries::Ptr(),
1201                                                     projectRepositoryMock.getInstance(),
1202                                                     contextQueriesMock.getInstance(),
1203                                                     contextRepositoryMock.getInstance(),
1204                                                     Domain::TaskQueries::Ptr(),
1205                                                     taskRepositoryMock.getInstance());
1206 
1207         FakeErrorHandler errorHandler;
1208         pages.setErrorHandler(&errorHandler);
1209         QAbstractItemModel *model = pages.pageListModel();
1210         const QModelIndex contextsIndex = model->index(s_contextRow, 0);
1211         const QModelIndex context1Index = model->index(0, 0, contextsIndex);
1212 
1213         // WHEN
1214         auto job = new FakeJob(this);
1215         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
1216         contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop).thenReturn(job);
1217         auto data = std::make_unique<QMimeData>();
1218         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
1219         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop));
1220         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index);
1221 
1222         // THEN
1223         QTest::qWait(150);
1224         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add taskDropped to context context 1: Foo"));
1225     }
1226 
1227     void shouldGetAnErrorMessageWhenDissociateFailed()
1228     {
1229         // GIVEN
1230 
1231         // Empty source provider
1232         auto sourceProvider = Domain::QueryResultProvider<Domain::DataSource::Ptr>::Ptr::create();
1233         auto sourceResult = Domain::QueryResult<Domain::DataSource::Ptr>::create(sourceProvider);
1234 
1235         // Empty context provider
1236         auto contextProvider = Domain::QueryResultProvider<Domain::Context::Ptr>::Ptr::create();
1237         auto contextResult = Domain::QueryResult<Domain::Context::Ptr>::create(contextProvider);
1238 
1239         // One task (used for dropping later on)
1240         Domain::Task::Ptr taskToDrop(new Domain::Task);
1241         taskToDrop->setTitle(QStringLiteral("taskDropped"));
1242 
1243         // context mocking
1244         Utils::MockObject<Domain::ContextQueries> contextQueriesMock;
1245         contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult);
1246 
1247         Utils::MockObject<Domain::ContextRepository> contextRepositoryMock;
1248 
1249         // sources mocking
1250         Utils::MockObject<Domain::DataSourceQueries> dataSourceQueriesMock;
1251         dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult);
1252 
1253         Utils::MockObject<Domain::ProjectRepository> projectRepositoryMock;
1254         Utils::MockObject<Domain::TaskRepository> taskRepositoryMock;
1255 
1256         Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(),
1257                                                     Domain::ProjectQueries::Ptr(),
1258                                                     projectRepositoryMock.getInstance(),
1259                                                     contextQueriesMock.getInstance(),
1260                                                     contextRepositoryMock.getInstance(),
1261                                                     Domain::TaskQueries::Ptr(),
1262                                                     taskRepositoryMock.getInstance());
1263 
1264         FakeErrorHandler errorHandler;
1265         pages.setErrorHandler(&errorHandler);
1266         QAbstractItemModel *model = pages.pageListModel();
1267         const QModelIndex inboxIndex = model->index(0, 0);
1268 
1269         // WHEN
1270         auto job = new FakeJob(this);
1271         job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo"));
1272         projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).thenReturn(job);
1273         taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop).thenReturn(new FakeJob(this));
1274         auto data = std::make_unique<QMimeData>();
1275         data->setData(QStringLiteral("application/x-zanshin-object"), "object");
1276         data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop));
1277         model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex);
1278 
1279         // THEN
1280         QTest::qWait(150);
1281         QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move taskDropped to Inbox: Foo"));
1282     }
1283 };
1284 
1285 ZANSHIN_TEST_MAIN(AvailablePagesModelTest)
1286 
1287 #include "availablepagesmodeltest.moc"