diff --git a/3rdparty/kdepim/libkdepim/kdateedit.h b/3rdparty/kdepim/libkdepim/kdateedit.h index 4b7eead9..499a20c0 100644 --- a/3rdparty/kdepim/libkdepim/kdateedit.h +++ b/3rdparty/kdepim/libkdepim/kdateedit.h @@ -1,157 +1,157 @@ /* This file is part of libkdepim. Copyright (c) 2002 Cornelius Schumacher Copyright (c) 2002 David Jarvie Copyright (c) 2004 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEPIM_KDATEEDIT_H #define KDEPIM_KDATEEDIT_H #include "kdatepickerpopup.h" #include "kdepim_export.h" #include #include #include #include #include class QEvent; namespace KPIM { /** A date editing widget that consists of an editable combo box. The combo box contains the date in text form, and clicking the combo box arrow will display a 'popup' style date picker. This widget also supports advanced features like allowing the user to type in the day name to get the date. The following keywords are supported (in the native language): tomorrow, yesterday, today, monday, tuesday, wednesday, thursday, friday, saturday, sunday. @image html kdateedit.png "This is how it looks" @author Cornelius Schumacher @author Mike Pilone @author David Jarvie @author Tobias Koenig */ class KDEPIM_EXPORT KDateEdit : public QComboBox { Q_OBJECT Q_PROPERTY( QDate date READ date WRITE setDate ) public: explicit KDateEdit( QWidget *parent = 0 ); virtual ~KDateEdit(); /** @return The date entered. This date could be invalid, you have to check validity yourself. */ QDate date() const; /** Sets whether the widget is read-only for the user. If read-only, the date pop-up is inactive, and the displayed date cannot be edited. @param readOnly True to set the widget read-only, false to set it read-write. */ void setReadOnly( bool readOnly ); /** @return True if the widget is read-only, false if read-write. */ bool isReadOnly() const; - virtual void showPopup(); + void showPopup() override; Q_SIGNALS: /** This signal is emitted whenever the user has entered a new date. When the user changes the date by editing the line edit field, the signal is not emitted until focus leaves the line edit field. The passed date can be invalid. */ void dateEntered( const QDate &date ); /** This signal is emitted whenever the user modifies the date. The passed date can be invalid. */ void dateChanged( const QDate &date ); public Q_SLOTS: /** Sets the date. @param date The new date to display. This date must be valid or it will not be set */ void setDate( const QDate &date ); protected Q_SLOTS: void lineEnterPressed(); void slotTextChanged( const QString & ); void dateSelected( const QDate & ); protected: - virtual bool eventFilter( QObject *, QEvent * ); - virtual void mousePressEvent( QMouseEvent * ); - virtual void focusOutEvent( QFocusEvent * ); - virtual void wheelEvent( QWheelEvent * ); - virtual void keyPressEvent( QKeyEvent * ); + bool eventFilter( QObject *, QEvent * ) override; + void mousePressEvent( QMouseEvent * ) override; + void focusOutEvent( QFocusEvent * ) override; + void wheelEvent( QWheelEvent * ) override; + void keyPressEvent( QKeyEvent * ) override; /** Sets the date, without altering the display. This method is used internally to set the widget's date value. As a virtual method, it allows derived classes to perform additional validation on the date value before it is set. Derived classes should return true if QDate::isValid(@p date) returns false. @param date The new date to set. @return True if the date was set, false if it was considered invalid and remains unchanged. */ virtual bool assignDate( const QDate &date ); /** Fills the keyword map. Reimplement it if you want additional keywords. */ void setupKeywords(); private: QDate parseDate( bool *replaced = 0 ) const; void updateView(); KDatePickerPopup *mPopup; QDate mDate; bool mReadOnly; bool mTextChanged; bool mDiscardNextMousePress; QMap mKeywordMap; }; } #endif diff --git a/3rdparty/mockitopp/detail/stubbing/action.hpp b/3rdparty/mockitopp/detail/stubbing/action.hpp index c8d0a3f5..b035e73e 100644 --- a/3rdparty/mockitopp/detail/stubbing/action.hpp +++ b/3rdparty/mockitopp/detail/stubbing/action.hpp @@ -1,48 +1,48 @@ #ifndef __MOCKITOPP_ACTION_HPP__ #define __MOCKITOPP_ACTION_HPP__ namespace mockitopp { namespace detail { template struct action { virtual R invoke() = 0; virtual ~action() {} }; template struct returnable_action : public action { R _returnable; returnable_action(const R& returnable) : _returnable(returnable) {} - R invoke() { return _returnable; } + R invoke() override { return _returnable; } }; template <> struct returnable_action : public action { - void invoke() {} + void invoke() override {} }; template struct throwable_action : public action { T _throwable; throwable_action(const T& throwable) : _throwable(throwable) {} - R invoke() { throw _throwable; } + R invoke() override { throw _throwable; } }; } // namespace detail } // namespace mockitopp #endif //__MOCKITOPP_ACTION_HPP__ diff --git a/3rdparty/mockitopp/matchers/base/any.hpp b/3rdparty/mockitopp/matchers/base/any.hpp index 946f4571..b395c282 100644 --- a/3rdparty/mockitopp/matchers/base/any.hpp +++ b/3rdparty/mockitopp/matchers/base/any.hpp @@ -1,35 +1,35 @@ #ifndef __MOCKITOPP_MATCHER_ANY_HPP__ #define __MOCKITOPP_MATCHER_ANY_HPP__ #include namespace mockitopp { namespace matcher { namespace detail { template struct AnyT : public Matcher { AnyT() {} - virtual Matcher* clone() const + Matcher* clone() const override { return new AnyT(); } - virtual bool operator== (typename mockitopp::detail::tr1::add_reference::type>::type rhs) const + bool operator== (typename mockitopp::detail::tr1::add_reference::type>::type rhs) const override { (void)rhs; return true; } }; } // namespace detail template detail::AnyT any() { return detail::AnyT(); } } // namespace matcher } // namespace mockitopp #endif //__MOCKITOPP_MATCHER_ANY_HPP__ diff --git a/3rdparty/mockitopp/matchers/base/equal.hpp b/3rdparty/mockitopp/matchers/base/equal.hpp index 2e9d3c6f..de805fb8 100644 --- a/3rdparty/mockitopp/matchers/base/equal.hpp +++ b/3rdparty/mockitopp/matchers/base/equal.hpp @@ -1,44 +1,44 @@ #ifndef __MOCKITOPP_MATCHER_EQ_HPP__ #define __MOCKITOPP_MATCHER_EQ_HPP__ #include #include namespace mockitopp { namespace matcher { namespace detail { template struct EqualT : public Matcher { EqualT(typename mockitopp::detail::tr1::add_reference< typename mockitopp::detail::tr1::add_const::type>::type element) : element_(element) {} - virtual Matcher* clone() const + Matcher* clone() const override { return new EqualT(element_); } - virtual bool operator== (typename mockitopp::detail::tr1::add_reference< - typename mockitopp::detail::tr1::add_const::type>::type rhs) const + bool operator== (typename mockitopp::detail::tr1::add_reference< + typename mockitopp::detail::tr1::add_const::type>::type rhs) const override { return element_ == rhs; } private: T element_; }; } // namespace detail template detail::EqualT equal(typename mockitopp::detail::tr1::add_reference< typename mockitopp::detail::tr1::add_const::type>::type element) { return detail::EqualT(element); } inline detail::EqualT equal(const char* element) { return detail::EqualT(element); } } // namespace matcher } // namespace mockitopp #endif //__MOCKITOPP_MATCHER_EQ_HPP__ diff --git a/src/domain/queryresult.h b/src/domain/queryresult.h index 8b74ad3e..ac6156f4 100644 --- a/src/domain/queryresult.h +++ b/src/domain/queryresult.h @@ -1,125 +1,125 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DOMAIN_QUERYRESULT_H #define DOMAIN_QUERYRESULT_H #include #include "queryresultinterface.h" #include "queryresultprovider.h" namespace Domain { template class QueryResult : public QueryResultInputImpl, public QueryResultInterface { public: typedef QSharedPointer> Ptr; typedef QWeakPointer> WeakPtr; typedef std::function ChangeHandler; static Ptr create(const typename QueryResultProvider::Ptr &provider) { Ptr result(new QueryResult(provider)); QueryResultInputImpl::registerResult(provider, result); return result; } static Ptr copy(const typename QueryResultInputImpl::Ptr &other) { if (!other) return Ptr(); auto provider = QueryResultInputImpl::retrieveProvider(other); return create(provider); } - QList data() const + QList data() const override { return dataImpl(); } - void addPreInsertHandler(const ChangeHandler &handler) + void addPreInsertHandler(const ChangeHandler &handler) override { QueryResultInputImpl::m_preInsertHandlers << handler; } - void addPostInsertHandler(const ChangeHandler &handler) + void addPostInsertHandler(const ChangeHandler &handler) override { QueryResultInputImpl::m_postInsertHandlers << handler; } - void addPreRemoveHandler(const ChangeHandler &handler) + void addPreRemoveHandler(const ChangeHandler &handler) override { QueryResultInputImpl::m_preRemoveHandlers << handler; } - void addPostRemoveHandler(const ChangeHandler &handler) + void addPostRemoveHandler(const ChangeHandler &handler) override { QueryResultInputImpl::m_postRemoveHandlers << handler; } - void addPreReplaceHandler(const ChangeHandler &handler) + void addPreReplaceHandler(const ChangeHandler &handler) override { QueryResultInputImpl::m_preReplaceHandlers << handler; } - void addPostReplaceHandler(const ChangeHandler &handler) + void addPostReplaceHandler(const ChangeHandler &handler) override { QueryResultInputImpl::m_postReplaceHandlers << handler; } private: explicit QueryResult(const typename QueryResultProvider::Ptr &provider) : QueryResultInputImpl(provider) { } template typename std::enable_if::value, QList>::type dataImpl() const { auto provider = QueryResultInputImpl::m_provider; return provider->data(); } template typename std::enable_if::value, QList>::type dataImpl() const { auto provider = QueryResultInputImpl::m_provider; QList inputData = provider->data(); QList outputData; std::transform(inputData.constBegin(), inputData.constEnd(), std::back_inserter(outputData), [] (const InputType &input) { return OutputType(input); }); return outputData; } }; } #endif // DOMAIN_QUERYRESULT_H diff --git a/src/presentation/availablepagessortfilterproxymodel.h b/src/presentation/availablepagessortfilterproxymodel.h index 0d83a2dd..d9dd1ae6 100644 --- a/src/presentation/availablepagessortfilterproxymodel.h +++ b/src/presentation/availablepagessortfilterproxymodel.h @@ -1,45 +1,45 @@ /* This file is part of Zanshin Copyright 2014 David Faure This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PRESENTATION_AVAILABLEPAGESSORTFILTERPROXYMODEL_H #define PRESENTATION_AVAILABLEPAGESSORTFILTERPROXYMODEL_H #include namespace Presentation { class AvailablePagesSortFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT Q_ENUMS(SortType) public: explicit AvailablePagesSortFilterProxyModel(QObject *parent = 0); protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; }; } #endif // PRESENTATION_AVAILABLEPAGESSORTFILTERPROXYMODEL_H diff --git a/src/zanshin/runner/zanshinrunner.h b/src/zanshin/runner/zanshinrunner.h index 8c6b8371..ba997892 100644 --- a/src/zanshin/runner/zanshinrunner.h +++ b/src/zanshin/runner/zanshinrunner.h @@ -1,47 +1,47 @@ /* This file is part of Zanshin Copyright 2011 Kevin Ottens Copyright 2014 Mario Bensi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef ZANSHINRUNNER_H #define ZANSHINRUNNER_H #include #include "domain/taskrepository.h" class ZanshinRunner : public Plasma::AbstractRunner { Q_OBJECT public: ZanshinRunner(QObject *parent, const QVariantList &args); ~ZanshinRunner(); - void match(Plasma::RunnerContext &context); - void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + void match(Plasma::RunnerContext &context) override; + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action) override; private: Domain::TaskRepository::Ptr m_taskRepository; }; #endif diff --git a/tests/testlib/fakejob.h b/tests/testlib/fakejob.h index d332c7c7..83f6c75b 100644 --- a/tests/testlib/fakejob.h +++ b/tests/testlib/fakejob.h @@ -1,55 +1,55 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef ZANSHIN_TESTLIB_FAKEJOB_H #define ZANSHIN_TESTLIB_FAKEJOB_H #include class FakeJob : public KJob { Q_OBJECT public: static const int DURATION = 50; explicit FakeJob(QObject *parent = Q_NULLPTR); void setExpectedError(int errorCode, const QString &errorText = QString()); - void start(); + void start() override; private slots: virtual void onTimeout(); public: bool isDone() const; int expectedError() const; QString expectedErrorText() const; private: bool m_done; bool m_launched; int m_errorCode; QString m_errorText; }; #endif diff --git a/tests/units/domain/queryresulttest.cpp b/tests/units/domain/queryresulttest.cpp index 65d168f8..7d126847 100644 --- a/tests/units/domain/queryresulttest.cpp +++ b/tests/units/domain/queryresulttest.cpp @@ -1,346 +1,346 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "domain/queryresult.h" using namespace Domain; class Base { public: typedef QSharedPointer Ptr; virtual ~Base() {} virtual QString whoAmI() { return QStringLiteral("I'm Base"); } }; class Derived : public Base { public: typedef QSharedPointer Ptr; - QString whoAmI() { return QStringLiteral("I'm Derived"); } + QString whoAmI() override { return QStringLiteral("I'm Derived"); } }; class QueryResultTest : public QObject { Q_OBJECT private slots: void shouldBeCreatedEmpty() { QueryResultProvider::Ptr provider(new QueryResultProvider); QVERIFY(provider->data().isEmpty()); QueryResult::Ptr result = QueryResult::create(provider); QVERIFY(result->data().isEmpty()); } void shouldHaveSameContent() { QueryResultProvider::Ptr provider(new QueryResultProvider); QueryResult::Ptr result = QueryResult::create(provider); provider->append(QStringLiteral("Bar")); QVERIFY(!provider->data().isEmpty()); QVERIFY(!result->data().isEmpty()); QCOMPARE(provider->data().size(), 1); QCOMPARE(result->data().size(), 1); QCOMPARE(provider->data().first(), QStringLiteral("Bar")); QCOMPARE(result->data().first(), QStringLiteral("Bar")); provider->prepend(QStringLiteral("Foo")); *provider << QStringLiteral("Baz"); QCOMPARE(provider->data().size(), 3); QCOMPARE(result->data().size(), 3); QCOMPARE(provider->data().first(), QStringLiteral("Foo")); QCOMPARE(result->data().first(), QStringLiteral("Foo")); QCOMPARE(provider->data().at(1), QStringLiteral("Bar")); QCOMPARE(result->data().at(1), QStringLiteral("Bar")); QCOMPARE(provider->data().last(), QStringLiteral("Baz")); QCOMPARE(result->data().last(), QStringLiteral("Baz")); } void shouldCreateResultFromAnotherResultOfSameType() { auto provider = QueryResultProvider::Ptr::create(); auto result = QueryResult::create(provider); provider->append(QStringLiteral("Foo")); provider->append(QStringLiteral("Bar")); provider->append(QStringLiteral("Baz")); QVERIFY(!provider->data().isEmpty()); QVERIFY(!result->data().isEmpty()); QCOMPARE(result->data(), provider->data()); auto otherResult = QueryResult::copy(result); QCOMPARE(otherResult->data(), result->data()); } void shouldCreateResultFromAnotherResultOfCompatibleType() { auto provider = QueryResultProvider::Ptr::create(); auto result = QueryResult::create(provider); provider->append(Derived::Ptr::create()); QList baseList; baseList << provider->data().first(); QVERIFY(!provider->data().isEmpty()); QVERIFY(!result->data().isEmpty()); QCOMPARE(result->data(), provider->data()); auto otherResult = QueryResult::copy(result); QCOMPARE(otherResult->data(), baseList); } void shouldProperlyCopyNullPointers() { QueryResult::Ptr result; QVERIFY(QueryResult::copy(result).isNull()); } void shouldResultsKeepProviderAlive() { QueryResultProvider::WeakPtr provider; QVERIFY(provider.isNull()); { QueryResult::Ptr result1; { QueryResultProvider::Ptr strongProvider(new QueryResultProvider); provider = strongProvider; QVERIFY(!provider.isNull()); result1 = QueryResult::create(provider.toStrongRef()); } QVERIFY(!provider.isNull()); { QueryResult::Ptr result2 = QueryResult::create(provider.toStrongRef()); Q_UNUSED(result2); QVERIFY(!provider.isNull()); } QVERIFY(!provider.isNull()); } QVERIFY(provider.isNull()); } void shouldNotifyInserts() { QList preInserts, postInserts; QList preInsertsPos, postInsertsPos; QueryResultProvider::Ptr provider(new QueryResultProvider); QueryResult::Ptr result = QueryResult::create(provider); result->addPreInsertHandler( [&](const QString &value, int pos) { preInserts << value; preInsertsPos << pos; } ); result->addPostInsertHandler( [&](const QString &value, int pos) { postInserts << value; postInsertsPos << pos; } ); provider->append(QStringLiteral("Bar")); provider->prepend(QStringLiteral("Foo")); *provider << QStringLiteral("Baz"); provider->insert(1, QStringLiteral("Bazz")); const QList expectedInserts = {"Bar", "Foo", "Baz", "Bazz"}; const QList expectedInsertsPos = {0, 0, 2, 1}; QCOMPARE(preInserts, expectedInserts); QCOMPARE(preInsertsPos, expectedInsertsPos); QCOMPARE(postInserts, expectedInserts); QCOMPARE(postInsertsPos, expectedInsertsPos); } void shouldNotifyInsertsForCompatibleTypes() { QList preInserts, postInserts; QList preInsertsPos, postInsertsPos; auto provider = QueryResultProvider::Ptr::create(); auto derivedResult = QueryResult::create(provider); auto baseResult = QueryResult::copy(derivedResult); baseResult->addPreInsertHandler( [&](const Base::Ptr &value, int pos) { preInserts << value; preInsertsPos << pos; } ); baseResult->addPostInsertHandler( [&](const Base::Ptr &value, int pos) { postInserts << value; postInsertsPos << pos; } ); provider->append(Derived::Ptr::create()); provider->append(Derived::Ptr::create()); const QList expectedInserts = { provider->data().first(), provider->data().last() }; const QList expectedInsertsPos = {0, 1}; QCOMPARE(preInserts, expectedInserts); QCOMPARE(preInsertsPos, expectedInsertsPos); QCOMPARE(postInserts, expectedInserts); QCOMPARE(postInsertsPos, expectedInsertsPos); } void shouldNotifyRemoves() { QList preRemoves, postRemoves; QList preRemovesPos, postRemovesPos; QueryResultProvider::Ptr provider(new QueryResultProvider); *provider << QStringLiteral("Foo") << QStringLiteral("Bar") << QStringLiteral("Baz") << QStringLiteral("Bazz"); QueryResult::Ptr result = QueryResult::create(provider); result->addPreRemoveHandler( [&](const QString &value, int pos) { preRemoves << value; preRemovesPos << pos; } ); result->addPostRemoveHandler( [&](const QString &value, int pos) { postRemoves << value; postRemovesPos << pos; } ); provider->removeAt(1); provider->removeFirst(); provider->removeLast(); const QList expectedRemoves = {"Bar", "Foo", "Bazz"}; const QList expectedRemovesPos = {1, 0, 1}; QCOMPARE(preRemoves, expectedRemoves); QCOMPARE(preRemovesPos, expectedRemovesPos); QCOMPARE(postRemoves, expectedRemoves); QCOMPARE(postRemovesPos, expectedRemovesPos); } void shouldNotifyTakes() { QList preRemoves, postRemoves, taken; QList preRemovesPos, postRemovesPos; QueryResultProvider::Ptr provider(new QueryResultProvider); *provider << QStringLiteral("Foo") << QStringLiteral("Bar") << QStringLiteral("Baz") << QStringLiteral("Bazz"); QueryResult::Ptr result = QueryResult::create(provider); result->addPreRemoveHandler( [&](const QString &value, int pos) { preRemoves << value; preRemovesPos << pos; } ); result->addPostRemoveHandler( [&](const QString &value, int pos) { postRemoves << value; postRemovesPos << pos; } ); taken << provider->takeAt(1); taken << provider->takeFirst(); taken << provider->takeLast(); const QList expectedRemoves = {"Bar", "Foo", "Bazz"}; const QList expectedRemovesPos = {1, 0, 1}; QCOMPARE(preRemoves, expectedRemoves); QCOMPARE(preRemovesPos, expectedRemovesPos); QCOMPARE(postRemoves, expectedRemoves); QCOMPARE(postRemovesPos, expectedRemovesPos); QCOMPARE(taken, expectedRemoves); } void shouldNotifyReplaces() { QList preReplaces, postReplaces; QList preReplacesPos, postReplacesPos; QueryResultProvider::Ptr provider(new QueryResultProvider); *provider << QStringLiteral("Foo") << QStringLiteral("Foo") << QStringLiteral("Foo") << QStringLiteral("Foo"); QueryResult::Ptr result = QueryResult::create(provider); result->addPreReplaceHandler( [&](const QString &value, int pos) { preReplaces << value; preReplacesPos << pos; } ); result->addPostReplaceHandler( [&](const QString &value, int pos) { postReplaces << value; postReplacesPos << pos; } ); provider->replace(1, QStringLiteral("Bar")); provider->replace(2, QStringLiteral("Baz")); const QList expectedPreReplaces = {"Foo", "Foo"}; const QList expectedPostReplaces = {"Bar", "Baz"}; const QList expectedReplacesPos = {1, 2}; QCOMPARE(preReplaces, expectedPreReplaces); QCOMPARE(preReplacesPos, expectedReplacesPos); QCOMPARE(postReplaces, expectedPostReplaces); QCOMPARE(postReplacesPos, expectedReplacesPos); } }; ZANSHIN_TEST_MAIN(QueryResultTest) #include "queryresulttest.moc" diff --git a/tests/units/presentation/applicationmodeltest.cpp b/tests/units/presentation/applicationmodeltest.cpp index 8faf4cde..2059bd7d 100644 --- a/tests/units/presentation/applicationmodeltest.cpp +++ b/tests/units/presentation/applicationmodeltest.cpp @@ -1,252 +1,252 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "utils/dependencymanager.h" #include "utils/jobhandler.h" #include "utils/mockobject.h" #include "presentation/applicationmodel.h" #include "presentation/artifacteditormodel.h" #include "presentation/availablepagesmodelinterface.h" #include "presentation/availablesourcesmodel.h" #include "presentation/pagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class FakeAvailablePagesModel : public Presentation::AvailablePagesModelInterface { Q_OBJECT public: explicit FakeAvailablePagesModel(QObject *parent = Q_NULLPTR) : Presentation::AvailablePagesModelInterface(parent) {} QAbstractItemModel *pageListModel() Q_DECL_OVERRIDE { return Q_NULLPTR; } bool hasProjectPages() const Q_DECL_OVERRIDE { return false; } bool hasContextPages() const Q_DECL_OVERRIDE { return false; } bool hasTagPages() const Q_DECL_OVERRIDE { return false; } QObject *createPageForIndex(const QModelIndex &) Q_DECL_OVERRIDE { return Q_NULLPTR; } void addProject(const QString &, const Domain::DataSource::Ptr &) Q_DECL_OVERRIDE {} void addContext(const QString &) Q_DECL_OVERRIDE {} void addTag(const QString &) Q_DECL_OVERRIDE {} void removeItem(const QModelIndex &) Q_DECL_OVERRIDE {} }; class FakePageModel : public Presentation::PageModel { Q_OBJECT public: explicit FakePageModel(QObject *parent = Q_NULLPTR) : Presentation::PageModel(parent) {} Domain::Artifact::Ptr addItem(const QString &, const QModelIndex &) Q_DECL_OVERRIDE { return {}; } void removeItem(const QModelIndex &) Q_DECL_OVERRIDE {} void promoteItem(const QModelIndex &) Q_DECL_OVERRIDE {} private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE { return {}; } }; class ApplicationModelTest : public QObject { Q_OBJECT public: explicit ApplicationModelTest(QObject *parent = Q_NULLPTR) : QObject(parent) { Utils::DependencyManager::globalInstance().add(); Utils::DependencyManager::globalInstance().add( [] (Utils::DependencyManager *) { return new Presentation::ArtifactEditorModel; }); Utils::DependencyManager::globalInstance().add( [] (Utils::DependencyManager *) { return new Presentation::AvailableSourcesModel(Domain::DataSourceQueries::Ptr(), Domain::DataSourceRepository::Ptr()); }); } private slots: void shouldProvideAvailableSourcesModel() { // GIVEN Presentation::ApplicationModel app; // WHEN QObject *available = app.availableSources(); // THEN QVERIFY(qobject_cast(available)); } void shouldProvideAvailablePagesModel() { // GIVEN Presentation::ApplicationModel app; // WHEN QObject *available = app.availablePages(); // THEN QVERIFY(qobject_cast(available)); } void shouldProvideCurrentPage() { // GIVEN Presentation::ApplicationModel app; QVERIFY(!app.currentPage()); QSignalSpy spy(&app, &Presentation::ApplicationModel::currentPageChanged); // WHEN auto page = new FakePageModel(this); app.setCurrentPage(page); // THEN QCOMPARE(app.currentPage(), page); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).value(), page); } void shouldSupportNullPage() { // GIVEN Presentation::ApplicationModel app; auto page = new FakePageModel(this); app.setCurrentPage(page); QCOMPARE(app.currentPage(), page); QSignalSpy spy(&app, &Presentation::ApplicationModel::currentPageChanged); // WHEN app.setCurrentPage(Q_NULLPTR); // THEN QVERIFY(!app.currentPage()); QCOMPARE(spy.count(), 1); QVERIFY(!spy.takeFirst().at(0).value()); } void shouldTakeOwnershipOfCurrentPage() { // GIVEN auto page = QPointer(new FakePageModel(this)); { Presentation::ApplicationModel app; // WHEN app.setCurrentPage(page.data()); // THEN QVERIFY(!page->parent()); QCOMPARE(app.currentPage(), page.data()); } // We don't crash and page is deleted QVERIFY(!page); } void shouldProvideArtifactEditorModel() { // GIVEN Presentation::ApplicationModel app; // WHEN QObject *page = app.editor(); // THEN QVERIFY(qobject_cast(page)); } void shouldSetErrorHandlerToAllModels() { // GIVEN // An ErrorHandler FakeErrorHandler errorHandler; Presentation::ApplicationModel app; app.setCurrentPage(new FakePageModel); // WHEN app.setErrorHandler(&errorHandler); // THEN auto availableSource = static_cast(app.availableSources()); auto availablePages = static_cast(app.availablePages()); auto editor = static_cast(app.editor()); auto page = static_cast(app.currentPage()); QCOMPARE(availableSource->errorHandler(), &errorHandler); QCOMPARE(availablePages->errorHandler(), &errorHandler); QCOMPARE(editor->errorHandler(), &errorHandler); QCOMPARE(page->errorHandler(), &errorHandler); // WHEN FakeErrorHandler errorHandler2; app.setErrorHandler(&errorHandler2); // THEN QCOMPARE(availableSource->errorHandler(), &errorHandler2); QCOMPARE(availablePages->errorHandler(), &errorHandler2); QCOMPARE(editor->errorHandler(), &errorHandler2); QCOMPARE(page->errorHandler(), &errorHandler2); } void shouldClearJobHandlersOnExit() { // GIVEN auto app = new Presentation::ApplicationModel; Utils::JobHandler::install(new FakeJob, [] { qFatal("Shouldn't happen"); }); QCOMPARE(Utils::JobHandler::jobCount(), 1); // WHEN delete app; // THEN QCOMPARE(Utils::JobHandler::jobCount(), 0); QTest::qWait(FakeJob::DURATION * 2); } }; ZANSHIN_TEST_MAIN(ApplicationModelTest) #include "applicationmodeltest.moc" diff --git a/tests/units/presentation/artifacteditormodeltest.cpp b/tests/units/presentation/artifacteditormodeltest.cpp index f7fd7ed4..c01678c5 100644 --- a/tests/units/presentation/artifacteditormodeltest.cpp +++ b/tests/units/presentation/artifacteditormodeltest.cpp @@ -1,645 +1,645 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "utils/mockobject.h" #include #include #include "testlib/fakejob.h" #include "domain/task.h" #include "domain/note.h" #include "presentation/artifacteditormodel.h" #include "presentation/errorhandler.h" using namespace mockitopp; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class ArtifactEditorModelTest : public QObject { Q_OBJECT public: explicit ArtifactEditorModelTest(QObject *parent = Q_NULLPTR) : QObject(parent) { qRegisterMetaType(); Presentation::ArtifactEditorModel::setAutoSaveDelay(50); } private slots: void shouldHaveEmptyDefaultState() { // GIVEN Presentation::ArtifactEditorModel model; // WHEN // Nothing // THEN QVERIFY(model.artifact().isNull()); QVERIFY(!model.hasTaskProperties()); QVERIFY(model.text().isEmpty()); QVERIFY(model.title().isEmpty()); QVERIFY(!model.isDone()); QVERIFY(model.startDate().isNull()); QVERIFY(model.dueDate().isNull()); QCOMPARE(model.recurrence(), Domain::Task::NoRecurrence); QVERIFY(model.attachmentModel() != nullptr); QVERIFY(model.delegateText().isNull()); QVERIFY(!model.hasSaveFunction()); QVERIFY(!model.hasDelegateFunction()); auto am = model.attachmentModel(); QCOMPARE(am->rowCount(), 0); } void shouldHaveTaskProperties() { // GIVEN Presentation::ArtifactEditorModel model; QSignalSpy textSpy(&model, &Presentation::ArtifactEditorModel::textChanged); QSignalSpy titleSpy(&model, &Presentation::ArtifactEditorModel::titleChanged); QSignalSpy doneSpy(&model, &Presentation::ArtifactEditorModel::doneChanged); QSignalSpy startSpy(&model, &Presentation::ArtifactEditorModel::startDateChanged); QSignalSpy dueSpy(&model, &Presentation::ArtifactEditorModel::dueDateChanged); QSignalSpy recurrenceSpy(&model, &Presentation::ArtifactEditorModel::recurrenceChanged); QSignalSpy attachmentSpy(model.attachmentModel(), &QAbstractItemModel::modelReset); QSignalSpy delegateSpy(&model, &Presentation::ArtifactEditorModel::delegateTextChanged); Domain::Task::Attachments attachments; Domain::Task::Attachment dataAttachment; dataAttachment.setData("foo"); dataAttachment.setLabel("dataAttachment"); dataAttachment.setMimeType("text/plain"); dataAttachment.setIconName("text-plain"); attachments.append(dataAttachment); Domain::Task::Attachment uriAttachment; uriAttachment.setUri(QUrl("https://www.kde.org")); uriAttachment.setLabel("uriAttachment"); uriAttachment.setMimeType("text/html"); uriAttachment.setIconName("text-html"); attachments.append(uriAttachment); auto task = Domain::Task::Ptr::create(); task->setText(QStringLiteral("description")); task->setTitle(QStringLiteral("title")); task->setDone(true); task->setStartDate(QDateTime::currentDateTime()); task->setDueDate(QDateTime::currentDateTime().addDays(2)); task->setRecurrence(Domain::Task::RecursDaily); task->setAttachments(attachments); task->setDelegate(Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("john@doe.com"))); // WHEN model.setArtifact(task); // To make sure we don't signal too much model.setText(task->text()); model.setTitle(task->title()); model.setDone(task->isDone()); model.setStartDate(task->startDate()); model.setDueDate(task->dueDate()); model.setRecurrence(task->recurrence()); // THEN QVERIFY(model.hasTaskProperties()); QCOMPARE(textSpy.size(), 1); QCOMPARE(textSpy.takeFirst().at(0).toString(), task->text()); QCOMPARE(model.property("text").toString(), task->text()); QCOMPARE(titleSpy.size(), 1); QCOMPARE(titleSpy.takeFirst().at(0).toString(), task->title()); QCOMPARE(model.property("title").toString(), task->title()); QCOMPARE(doneSpy.size(), 1); QCOMPARE(doneSpy.takeFirst().at(0).toBool(), task->isDone()); QCOMPARE(model.property("done").toBool(), task->isDone()); QCOMPARE(startSpy.size(), 1); QCOMPARE(startSpy.takeFirst().at(0).toDateTime(), task->startDate()); QCOMPARE(model.property("startDate").toDateTime(), task->startDate()); QCOMPARE(dueSpy.size(), 1); QCOMPARE(dueSpy.takeFirst().at(0).toDateTime(), task->dueDate()); QCOMPARE(model.property("dueDate").toDateTime(), task->dueDate()); QCOMPARE(recurrenceSpy.size(), 1); QCOMPARE(recurrenceSpy.takeFirst().at(0).value(), task->recurrence()); QCOMPARE(model.property("recurrence").value(), task->recurrence()); QCOMPARE(delegateSpy.size(), 1); QCOMPARE(delegateSpy.takeFirst().at(0).toString(), task->delegate().display()); QCOMPARE(model.property("delegateText").toString(), task->delegate().display()); QCOMPARE(attachmentSpy.size(), 1); auto am = model.attachmentModel(); QCOMPARE(am->rowCount(), 2); QCOMPARE(am->data(am->index(0, 0), Qt::DisplayRole).toString(), QStringLiteral("dataAttachment")); QCOMPARE(am->data(am->index(0, 0), Qt::DecorationRole).value(), QIcon::fromTheme("text-plain")); QCOMPARE(am->data(am->index(1, 0), Qt::DisplayRole).toString(), QStringLiteral("uriAttachment")); QCOMPARE(am->data(am->index(1, 0), Qt::DecorationRole).value(), QIcon::fromTheme("text-html")); } void shouldHaveNoteProperties() { // GIVEN Presentation::ArtifactEditorModel model; QSignalSpy textSpy(&model, &Presentation::ArtifactEditorModel::textChanged); QSignalSpy titleSpy(&model, &Presentation::ArtifactEditorModel::titleChanged); QSignalSpy doneSpy(&model, &Presentation::ArtifactEditorModel::doneChanged); QSignalSpy startSpy(&model, &Presentation::ArtifactEditorModel::startDateChanged); QSignalSpy dueSpy(&model, &Presentation::ArtifactEditorModel::dueDateChanged); QSignalSpy delegateSpy(&model, &Presentation::ArtifactEditorModel::delegateTextChanged); auto note = Domain::Note::Ptr::create(); note->setText(QStringLiteral("description")); note->setTitle(QStringLiteral("title")); // WHEN model.setArtifact(note); // To make sure we don't signal too much model.setText(note->text()); model.setTitle(note->title()); // THEN QVERIFY(!model.hasTaskProperties()); QCOMPARE(textSpy.size(), 1); QCOMPARE(textSpy.takeFirst().at(0).toString(), note->text()); QCOMPARE(model.property("text").toString(), note->text()); QCOMPARE(titleSpy.size(), 1); QCOMPARE(titleSpy.takeFirst().at(0).toString(), note->title()); QCOMPARE(model.property("title").toString(), note->title()); QCOMPARE(doneSpy.size(), 1); QCOMPARE(doneSpy.takeFirst().at(0).toBool(), false); QCOMPARE(model.property("done").toBool(), false); QCOMPARE(startSpy.size(), 1); QVERIFY(startSpy.takeFirst().at(0).toDateTime().isNull()); QVERIFY(model.property("startDate").toDateTime().isNull()); QCOMPARE(dueSpy.size(), 1); QVERIFY(dueSpy.takeFirst().at(0).toDateTime().isNull()); QVERIFY(model.property("dueDate").toDateTime().isNull()); QCOMPARE(delegateSpy.size(), 1); QVERIFY(delegateSpy.takeFirst().at(0).toString().isEmpty()); QVERIFY(model.property("delegateText").toString().isEmpty()); } void shouldReactToArtifactPropertyChanges_data() { QTest::addColumn("artifact"); QTest::addColumn("propertyName"); QTest::addColumn("propertyValue"); QTest::addColumn("signal"); QTest::newRow("note text") << Domain::Artifact::Ptr(Domain::Note::Ptr::create()) << QByteArray("text") << QVariant("new text") << QByteArray(SIGNAL(textChanged(QString))); QTest::newRow("note title") << Domain::Artifact::Ptr(Domain::Note::Ptr::create()) << QByteArray("title") << QVariant("new title") << QByteArray(SIGNAL(titleChanged(QString))); QTest::newRow("task text") << Domain::Artifact::Ptr(Domain::Task::Ptr::create()) << QByteArray("text") << QVariant("new text") << QByteArray(SIGNAL(textChanged(QString))); QTest::newRow("task title") << Domain::Artifact::Ptr(Domain::Task::Ptr::create()) << QByteArray("title") << QVariant("new title") << QByteArray(SIGNAL(titleChanged(QString))); QTest::newRow("task done") << Domain::Artifact::Ptr(Domain::Task::Ptr::create()) << QByteArray("done") << QVariant(true) << QByteArray(SIGNAL(doneChanged(bool))); QTest::newRow("task start") << Domain::Artifact::Ptr(Domain::Task::Ptr::create()) << QByteArray("startDate") << QVariant(QDateTime::currentDateTime()) << QByteArray(SIGNAL(startDateChanged(QDateTime))); QTest::newRow("task due") << Domain::Artifact::Ptr(Domain::Task::Ptr::create()) << QByteArray("dueDate") << QVariant(QDateTime::currentDateTime().addDays(2)) << QByteArray(SIGNAL(dueDateChanged(QDateTime))); QTest::newRow("task recurrence") << Domain::Artifact::Ptr(Domain::Task::Ptr::create()) << QByteArray("recurrence") << QVariant::fromValue(Domain::Task::RecursDaily) << QByteArray(SIGNAL(recurrenceChanged(Domain::Task::Recurrence))); } void shouldReactToArtifactPropertyChanges() { // GIVEN QFETCH(Domain::Artifact::Ptr, artifact); QFETCH(QByteArray, propertyName); QFETCH(QVariant, propertyValue); QFETCH(QByteArray, signal); Presentation::ArtifactEditorModel model; model.setArtifact(artifact); QSignalSpy spy(&model, signal.constData()); // WHEN artifact->setProperty(propertyName, propertyValue); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0), propertyValue); QCOMPARE(model.property(propertyName), propertyValue); } void shouldNotReactToArtifactPropertyChangesWhenEditing_data() { shouldReactToArtifactPropertyChanges_data(); } void shouldNotReactToArtifactPropertyChangesWhenEditing() { // GIVEN QFETCH(Domain::Artifact::Ptr, artifact); QFETCH(QByteArray, propertyName); QFETCH(QVariant, propertyValue); QFETCH(QByteArray, signal); Presentation::ArtifactEditorModel model; model.setArtifact(artifact); QSignalSpy spy(&model, signal.constData()); // WHEN const auto oldPropertyValue = artifact->property(propertyName); model.setEditingInProgress(true); artifact->setProperty(propertyName, propertyValue); // THEN QVERIFY(spy.isEmpty()); QCOMPARE(model.property(propertyName), oldPropertyValue); } void shouldReactToTaskDelegateChanges() { // GIVEN auto task = Domain::Task::Ptr::create(); Presentation::ArtifactEditorModel model; model.setArtifact(task); QSignalSpy spy(&model, &Presentation::ArtifactEditorModel::delegateTextChanged); // WHEN task->setDelegate(Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("john@doe.com"))); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), task->delegate().display()); QCOMPARE(model.property("delegateText").toString(), task->delegate().display()); } void shouldApplyChangesBackToArtifactAfterADelay_data() { shouldReactToArtifactPropertyChanges_data(); } void shouldApplyChangesBackToArtifactAfterADelay() { // GIVEN QFETCH(Domain::Artifact::Ptr, artifact); QFETCH(QByteArray, propertyName); QFETCH(QVariant, propertyValue); QFETCH(QByteArray, signal); auto savedArtifact = Domain::Artifact::Ptr(); auto save = [this, &savedArtifact] (const Domain::Artifact::Ptr &artifact) { savedArtifact = artifact; return new FakeJob(this); }; Presentation::ArtifactEditorModel model; model.setSaveFunction(save); model.setArtifact(artifact); QSignalSpy spy(&model, signal.constData()); // WHEN model.setProperty(propertyName, propertyValue); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0), propertyValue); QCOMPARE(model.property(propertyName), propertyValue); QVERIFY(artifact->property(propertyName) != propertyValue); QVERIFY(!savedArtifact); // WHEN (apply after delay) QTest::qWait(model.autoSaveDelay() + 50); // THEN QCOMPARE(savedArtifact, artifact); QCOMPARE(artifact->property(propertyName), propertyValue); } void shouldApplyChangesImmediatelyIfANewArtifactIsSet_data() { shouldReactToArtifactPropertyChanges_data(); } void shouldApplyChangesImmediatelyIfANewArtifactIsSet() { // GIVEN QFETCH(Domain::Artifact::Ptr, artifact); QFETCH(QByteArray, propertyName); QFETCH(QVariant, propertyValue); QFETCH(QByteArray, signal); auto savedArtifact = Domain::Artifact::Ptr(); auto save = [this, &savedArtifact] (const Domain::Artifact::Ptr &artifact) { savedArtifact = artifact; return new FakeJob(this); }; Presentation::ArtifactEditorModel model; model.setSaveFunction(save); QVERIFY(model.hasSaveFunction()); model.setArtifact(artifact); QSignalSpy spy(&model, signal.constData()); // WHEN model.setProperty(propertyName, propertyValue); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0), propertyValue); QCOMPARE(model.property(propertyName), propertyValue); QVERIFY(artifact->property(propertyName) != propertyValue); QVERIFY(!savedArtifact); // WHEN (apply immediately) model.setArtifact(Domain::Task::Ptr::create()); // THEN QCOMPARE(savedArtifact, artifact); QCOMPARE(artifact->property(propertyName), propertyValue); savedArtifact.clear(); // WHEN (nothing else happens after a delay) QTest::qWait(model.autoSaveDelay() + 50); // THEN QVERIFY(!savedArtifact); QCOMPARE(artifact->property(propertyName), propertyValue); } void shouldApplyChangesImmediatelyIfDeleted_data() { shouldReactToArtifactPropertyChanges_data(); } void shouldApplyChangesImmediatelyIfDeleted() { // GIVEN QFETCH(Domain::Artifact::Ptr, artifact); QFETCH(QByteArray, propertyName); QFETCH(QVariant, propertyValue); QFETCH(QByteArray, signal); auto savedArtifact = Domain::Artifact::Ptr(); auto save = [this, &savedArtifact] (const Domain::Artifact::Ptr &artifact) { savedArtifact = artifact; return new FakeJob(this); }; auto model = new Presentation::ArtifactEditorModel; model->setSaveFunction(save); QVERIFY(model->hasSaveFunction()); model->setArtifact(artifact); QSignalSpy spy(model, signal.constData()); // WHEN model->setProperty(propertyName, propertyValue); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0), propertyValue); QCOMPARE(model->property(propertyName), propertyValue); QVERIFY(artifact->property(propertyName) != propertyValue); QVERIFY(!savedArtifact); // WHEN (apply immediately) delete model; // THEN QCOMPARE(savedArtifact, artifact); QCOMPARE(artifact->property(propertyName), propertyValue); } void shouldLaunchDelegation() { // GIVEN auto task = Domain::Task::Ptr::create(); auto expectedDelegate = Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("john@doe.com")); auto delegatedTask = Domain::Task::Ptr(); auto delegate = Domain::Task::Delegate(); auto delegateFunction = [this, &delegatedTask, &delegate] (const Domain::Task::Ptr &task, const Domain::Task::Delegate &d) { delegatedTask = task; delegate = d; return new FakeJob(this); }; Presentation::ArtifactEditorModel model; model.setDelegateFunction(delegateFunction); QVERIFY(model.hasDelegateFunction()); model.setArtifact(task); // WHEN model.delegate(QStringLiteral("John Doe"), QStringLiteral("john@doe.com")); // THEN QCOMPARE(delegatedTask, task); QCOMPARE(delegate, expectedDelegate); QVERIFY(!task->delegate().isValid()); } void shouldGetAnErrorMessageWhenSaveFailed() { // GIVEN auto task = Domain::Task::Ptr::create(); task->setTitle(QStringLiteral("Task 1")); auto savedArtifact = Domain::Artifact::Ptr(); auto save = [this, &savedArtifact] (const Domain::Artifact::Ptr &artifact) { savedArtifact = artifact; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); return job; }; auto model = new Presentation::ArtifactEditorModel; model->setSaveFunction(save); QVERIFY(model->hasSaveFunction()); FakeErrorHandler errorHandler; model->setErrorHandler(&errorHandler); model->setArtifact(task); // WHEN model->setProperty("title", "Foo"); delete model; // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify task Task 1: Foo")); } void shouldDisconnectFromPreviousArtifact_data() { shouldReactToArtifactPropertyChanges_data(); } void shouldDisconnectFromPreviousArtifact() { // GIVEN QFETCH(Domain::Artifact::Ptr, artifact); QFETCH(QByteArray, propertyName); QFETCH(QVariant, propertyValue); QFETCH(QByteArray, signal); Presentation::ArtifactEditorModel model; model.setArtifact(artifact); QSignalSpy spy(&model, signal.constData()); Domain::Artifact::Ptr newArtifact = Domain::Task::Ptr::create(); // WHEN model.setArtifact(newArtifact); // modifying the *old* artifact should have no effect. artifact->setProperty(propertyName, propertyValue); // THEN QCOMPARE(spy.size(), 1); // emitted by setArtifact QVERIFY(model.property(propertyName) != artifact->property(propertyName)); } void shouldAddAttachments() { // GIVEN QTemporaryFile temporaryFile(QDir::tempPath() + "/artifacteditormodeltest_XXXXXX.txt"); temporaryFile.open(); temporaryFile.write("foo bar"); temporaryFile.close(); auto fileName = temporaryFile.fileName().mid(QDir::tempPath().size() + 1); auto task = Domain::Task::Ptr::create(); auto savedArtifact = Domain::Artifact::Ptr(); auto save = [this, &savedArtifact] (const Domain::Artifact::Ptr &artifact) { savedArtifact = artifact; return new FakeJob(this); }; Presentation::ArtifactEditorModel model; model.setSaveFunction(save); model.setArtifact(task); QSignalSpy spy(model.attachmentModel(), &QAbstractItemModel::modelReset); // WHEN model.addAttachment(temporaryFile.fileName()); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(model.attachmentModel()->rowCount(), 1); QVERIFY(!savedArtifact); // WHEN (nothing else happens after a delay) QTest::qWait(model.autoSaveDelay() + 50); // THEN QCOMPARE(savedArtifact.objectCast(), task); QCOMPARE(task->attachments().size(), 1); QCOMPARE(task->attachments().first().label(), fileName); QCOMPARE(task->attachments().first().mimeType(), QStringLiteral("text/plain")); QCOMPARE(task->attachments().first().iconName(), QStringLiteral("text-plain")); QCOMPARE(task->attachments().first().data(), QByteArrayLiteral("foo bar")); } void shouldRemoveAttachments() { // GIVEN auto task = Domain::Task::Ptr::create(); task->setAttachments(Domain::Task::Attachments() << Domain::Task::Attachment("foo") << Domain::Task::Attachment("bar")); auto savedArtifact = Domain::Artifact::Ptr(); auto save = [this, &savedArtifact] (const Domain::Artifact::Ptr &artifact) { savedArtifact = artifact; return new FakeJob(this); }; Presentation::ArtifactEditorModel model; model.setSaveFunction(save); model.setArtifact(task); QSignalSpy spy(model.attachmentModel(), &QAbstractItemModel::modelReset); // WHEN model.removeAttachment(model.attachmentModel()->index(0, 0)); // THEN QCOMPARE(spy.size(), 1); QCOMPARE(model.attachmentModel()->rowCount(), 1); QVERIFY(!savedArtifact); // WHEN (nothing else happens after a delay) QTest::qWait(model.autoSaveDelay() + 50); // THEN QCOMPARE(savedArtifact.objectCast(), task); QCOMPARE(task->attachments().size(), 1); QCOMPARE(task->attachments().first().data(), QByteArrayLiteral("bar")); } }; ZANSHIN_TEST_MAIN(ArtifactEditorModelTest) #include "artifacteditormodeltest.moc" diff --git a/tests/units/presentation/availablenotepagesmodeltest.cpp b/tests/units/presentation/availablenotepagesmodeltest.cpp index acbadbfd..21ef1bf8 100644 --- a/tests/units/presentation/availablenotepagesmodeltest.cpp +++ b/tests/units/presentation/availablenotepagesmodeltest.cpp @@ -1,470 +1,470 @@ /* This file is part of Zanshin Copyright 2015 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "utils/mockobject.h" #include "presentation/availablenotepagesmodel.h" #include "presentation/errorhandler.h" #include "presentation/noteinboxpagemodel.h" #include "presentation/querytreemodelbase.h" #include "presentation/tagpagemodel.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class AvailableNotePagesModelTest : public QObject { Q_OBJECT private slots: void shouldDeclareOnlyProjectAndContextPages() { // GIVEN Presentation::AvailableNotePagesModel pages({}, {}, {}, {}); // THEN QVERIFY(!pages.hasProjectPages()); QVERIFY(!pages.hasContextPages()); QVERIFY(pages.hasTagPages()); } void shouldListAvailablePages() { // GIVEN // Two tags auto tag1 = Domain::Tag::Ptr::create(); tag1->setName(QStringLiteral("Tag 1")); auto tag2 = Domain::Tag::Ptr::create(); tag2->setName(QStringLiteral("Tag 2")); auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); tagProvider->append(tag1); tagProvider->append(tag2); // One note (used for dropping later on) auto noteToDrop = Domain::Note::Ptr::create(); Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Utils::MockObject tagRepositoryMock; Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), tagRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex inboxIndex = model->index(0, 0); const QModelIndex tagsIndex = model->index(1, 0); const QModelIndex tag1Index = model->index(0, 0, tagsIndex); const QModelIndex tag2Index = model->index(1, 0, tagsIndex); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(inboxIndex), 0); QCOMPARE(model->rowCount(tagsIndex), 2); QCOMPARE(model->rowCount(tag1Index), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; QCOMPARE(model->flags(inboxIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(tagsIndex), Qt::NoItemFlags); QCOMPARE(model->flags(tag1Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(tag2Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->data(inboxIndex).toString(), i18n("Inbox")); QCOMPARE(model->data(tagsIndex).toString(), i18n("Tags")); QCOMPARE(model->data(tag1Index).toString(), tag1->name()); QCOMPARE(model->data(tag2Index).toString(), tag2->name()); QVERIFY(!model->data(inboxIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(tagsIndex, Qt::EditRole).isValid()); QCOMPARE(model->data(tag1Index, Qt::EditRole).toString(), tag1->name()); QCOMPARE(model->data(tag2Index, Qt::EditRole).toString(), tag2->name()); QCOMPARE(model->data(inboxIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("mail-folder-inbox")); QCOMPARE(model->data(tagsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(tag1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(tag2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QVERIFY(!model->data(inboxIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(tagsIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(tag1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(tag2Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->setData(inboxIndex, "foo", Qt::EditRole)); QVERIFY(!model->setData(tagsIndex, "foo", Qt::EditRole)); QVERIFY(!model->setData(tag1Index, "foo", Qt::EditRole)); QVERIFY(!model->setData(tag2Index, "foo", Qt::EditRole)); // WHEN tagRepositoryMock(&Domain::TagRepository::associate).when(tag1, noteToDrop).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << noteToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, tag1Index); // THEN QVERIFY(tagRepositoryMock(&Domain::TagRepository::associate).when(tag1, noteToDrop).exactly(1)); // WHEN tagRepositoryMock(&Domain::TagRepository::dissociateAll).when(noteToDrop).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << noteToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex); QTest::qWait(150); // THEN QVERIFY(tagRepositoryMock(&Domain::TagRepository::dissociateAll).when(noteToDrop).exactly(1)); } void shouldCreateInboxPage() { // GIVEN // Empty tag provider auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), Domain::TagRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex inboxIndex = model->index(0, 0); QObject *inboxPage = pages.createPageForIndex(inboxIndex); QVERIFY(qobject_cast(inboxPage)); } void shouldCreateTagsPage() { // GIVEN // Two tags auto tag1 = Domain::Tag::Ptr::create(); tag1->setName(QStringLiteral("tag 1")); auto tag2 = Domain::Tag::Ptr::create(); tag2->setName(QStringLiteral("tag 2")); auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); tagProvider->append(tag1); tagProvider->append(tag2); // tags mocking Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), Domain::TagRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex tagsIndex = model->index(1, 0); const QModelIndex tag1Index = model->index(0, 0, tagsIndex); const QModelIndex tag2Index = model->index(1, 0, tagsIndex); QObject *tagsPage = pages.createPageForIndex(tagsIndex); QObject *tag1Page = pages.createPageForIndex(tag1Index); QObject *tag2Page = pages.createPageForIndex(tag2Index); QVERIFY(!tagsPage); QVERIFY(qobject_cast(tag1Page)); QCOMPARE(qobject_cast(tag1Page)->tag(), tag1); QVERIFY(qobject_cast(tag2Page)); QCOMPARE(qobject_cast(tag2Page)->tag(), tag2); } void shouldAddTags() { // GIVEN Utils::MockObject tagRepositoryMock; tagRepositoryMock(&Domain::TagRepository::create).when(any()) .thenReturn(new FakeJob(this)); Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), Domain::TagQueries::Ptr(), tagRepositoryMock.getInstance()); // WHEN pages.addTag(QStringLiteral("Foo")); // THEN QVERIFY(tagRepositoryMock(&Domain::TagRepository::create).when(any()) .exactly(1)); } void shouldGetAnErrorMessageWhenAddTagFailed() { // GIVEN Utils::MockObject tagRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); tagRepositoryMock(&Domain::TagRepository::create).when(any()) .thenReturn(job); Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), Domain::TagQueries::Ptr(), tagRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); // WHEN pages.addTag(QStringLiteral("Foo")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add tag Foo: Foo")); } void shouldRemoveTag() { // GIVEN // Two tags auto tag1 = Domain::Tag::Ptr::create(); tag1->setName(QStringLiteral("tag 1")); auto tag2 = Domain::Tag::Ptr::create(); tag2->setName(QStringLiteral("tag 2")); auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); tagProvider->append(tag1); tagProvider->append(tag2); // tags mocking Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Utils::MockObject tagRepositoryMock; Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), tagRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex tagsIndex = model->index(1, 0); const QModelIndex tag1Index = model->index(0, 0, tagsIndex); auto job = new FakeJob(this); tagRepositoryMock(&Domain::TagRepository::remove).when(tag1).thenReturn(job); // WHEN pages.removeItem(tag1Index); // THEN QTest::qWait(150); QVERIFY(errorHandler.m_message.isEmpty()); QVERIFY(tagRepositoryMock(&Domain::TagRepository::remove).when(tag1).exactly(1)); } void shouldGetAnErrorMessageWhenRemoveTagFailed() { // GIVEN // Two tags auto tag1 = Domain::Tag::Ptr::create(); tag1->setName(QStringLiteral("tag 1")); auto tag2 = Domain::Tag::Ptr::create(); tag2->setName(QStringLiteral("tag 2")); auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); tagProvider->append(tag1); tagProvider->append(tag2); // tags mocking Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Utils::MockObject tagRepositoryMock; Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), tagRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex tagsIndex = model->index(1, 0); const QModelIndex tag1Index = model->index(0, 0, tagsIndex); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); tagRepositoryMock(&Domain::TagRepository::remove).when(tag1).thenReturn(job); // WHEN pages.removeItem(tag1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove tag tag 1: Foo")); } void shouldGetAnErrorMessageWhenAssociateTagFailed() { // GIVEN // Two tags auto tag1 = Domain::Tag::Ptr::create(); tag1->setName(QStringLiteral("Tag 1")); auto tag2 = Domain::Tag::Ptr::create(); tag2->setName(QStringLiteral("Tag 2")); auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); tagProvider->append(tag1); tagProvider->append(tag2); // One note (used for dropping later on) auto noteToDrop = Domain::Note::Ptr::create(); noteToDrop->setTitle(QStringLiteral("noteDropped")); // tags mocking Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Utils::MockObject tagRepositoryMock; Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), tagRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex tagsIndex = model->index(1, 0); const QModelIndex tag1Index = model->index(0, 0, tagsIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); tagRepositoryMock(&Domain::TagRepository::associate).when(tag1, noteToDrop).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << noteToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, tag1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot tag noteDropped with Tag 1: Foo")); } void shouldGetAnErrorMessageWhenDissociateTaskFailed() { // GIVEN // Two tags auto tag1 = Domain::Tag::Ptr::create(); tag1->setName(QStringLiteral("tag 1")); auto tag2 = Domain::Tag::Ptr::create(); tag2->setName(QStringLiteral("tag 2")); auto tagProvider = Domain::QueryResultProvider::Ptr::create(); auto tagResult = Domain::QueryResult::create(tagProvider); tagProvider->append(tag1); tagProvider->append(tag2); // One note (used for dropping later on) auto noteToDrop = Domain::Note::Ptr::create(); noteToDrop->setTitle(QStringLiteral("noteDropped")); // tags mocking Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findAll).when().thenReturn(tagResult); Utils::MockObject tagRepositoryMock; Presentation::AvailableNotePagesModel pages(Domain::NoteQueries::Ptr(), Domain::NoteRepository::Ptr(), tagQueriesMock.getInstance(), tagRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex inboxIndex = model->index(0, 0); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); tagRepositoryMock(&Domain::TagRepository::dissociateAll).when(noteToDrop).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << noteToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move noteDropped to Inbox: Foo")); } }; ZANSHIN_TEST_MAIN(AvailableNotePagesModelTest) #include "availablenotepagesmodeltest.moc" diff --git a/tests/units/presentation/availablesourcesmodeltest.cpp b/tests/units/presentation/availablesourcesmodeltest.cpp index 7d48ca6e..6f150110 100644 --- a/tests/units/presentation/availablesourcesmodeltest.cpp +++ b/tests/units/presentation/availablesourcesmodeltest.cpp @@ -1,282 +1,282 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "utils/mockobject.h" #define ZANSHIN_I_SWEAR_I_AM_IN_A_PRESENTATION_TEST #include "domain/datasourcequeries.h" #include "domain/datasourcerepository.h" #include "presentation/availablesourcesmodel.h" #include "presentation/querytreemodelbase.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" Q_DECLARE_METATYPE(QModelIndex); using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class AvailableSourcesModelTest : public QObject { Q_OBJECT public: explicit AvailableSourcesModelTest(QObject *parent = Q_NULLPTR) : QObject(parent) { qRegisterMetaType(); } private slots: void shouldListAvailableSources() { // GIVEN // Two top level sources auto source1 = Domain::DataSource::Ptr::create(); source1->setName(QStringLiteral("Source 1")); source1->setIconName(QStringLiteral("foo-icon")); source1->setSelected(true); auto source2 = Domain::DataSource::Ptr::create(); source2->setName(QStringLiteral("Source 2")); source2->setSelected(false); source2->setContentTypes(Domain::DataSource::Tasks); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(source1); topLevelProvider->append(source2); // Two other sources under source1 auto source3 = Domain::DataSource::Ptr::create(); source3->setName(QStringLiteral("Source 3")); source3->setSelected(false); source3->setContentTypes(Domain::DataSource::Notes); auto source4 = Domain::DataSource::Ptr::create(); source4->setSelected(true); source4->setName(QStringLiteral("Source 4")); source4->setContentTypes(Domain::DataSource::Notes | Domain::DataSource::Tasks); auto source1Provider = Domain::QueryResultProvider::Ptr::create(); auto source1Result = Domain::QueryResult::create(source1Provider); source1Provider->append(source3); source1Provider->append(source4); // Nothing under source2, source3 or source4 auto source2Provider = Domain::QueryResultProvider::Ptr::create(); auto source2Result = Domain::QueryResult::create(source2Provider); auto source3Provider = Domain::QueryResultProvider::Ptr::create(); auto source3Result = Domain::QueryResult::create(source3Provider); auto source4Provider = Domain::QueryResultProvider::Ptr::create(); auto source4Result = Domain::QueryResult::create(source4Provider); Utils::MockObject sourceQueriesMock; sourceQueriesMock(&Domain::DataSourceQueries::findTopLevel).when().thenReturn(topLevelResult); sourceQueriesMock(&Domain::DataSourceQueries::findChildren).when(source1).thenReturn(source1Result); sourceQueriesMock(&Domain::DataSourceQueries::findChildren).when(source2).thenReturn(source2Result); sourceQueriesMock(&Domain::DataSourceQueries::findChildren).when(source3).thenReturn(source3Result); sourceQueriesMock(&Domain::DataSourceQueries::findChildren).when(source4).thenReturn(source4Result); // We'll simulate a default source change later on sourceQueriesMock(&Domain::DataSourceQueries::isDefaultSource).when(source1).thenReturn(false); sourceQueriesMock(&Domain::DataSourceQueries::isDefaultSource).when(source2).thenReturn(true) .thenReturn(false); sourceQueriesMock(&Domain::DataSourceQueries::isDefaultSource).when(source3).thenReturn(false); sourceQueriesMock(&Domain::DataSourceQueries::isDefaultSource).when(source4).thenReturn(false) .thenReturn(false) .thenReturn(true); Utils::MockObject sourceRepositoryMock; Presentation::AvailableSourcesModel sources(sourceQueriesMock.getInstance(), sourceRepositoryMock.getInstance(), Q_NULLPTR); // WHEN QAbstractItemModel *model = sources.sourceListModel(); // THEN const QModelIndex source1Index = model->index(0, 0); const QModelIndex source2Index = model->index(1, 0); const QModelIndex source3Index = model->index(0, 0, source1Index); const QModelIndex source4Index = model->index(1, 0, source1Index); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(source1Index), 2); QCOMPARE(model->rowCount(source2Index), 0); QCOMPARE(model->rowCount(source3Index), 0); QCOMPARE(model->rowCount(source4Index), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; QCOMPARE(model->flags(source1Index), defaultFlags); QCOMPARE(model->flags(source2Index), defaultFlags | Qt::ItemIsUserCheckable); QCOMPARE(model->flags(source3Index), defaultFlags | Qt::ItemIsUserCheckable); QCOMPARE(model->flags(source4Index), defaultFlags | Qt::ItemIsUserCheckable); QCOMPARE(model->data(source1Index).toString(), source1->name()); QCOMPARE(model->data(source2Index).toString(), source2->name()); QCOMPARE(model->data(source3Index).toString(), source3->name()); QCOMPARE(model->data(source4Index).toString(), source4->name()); QCOMPARE(model->data(source1Index, Qt::EditRole).toString(), source1->name()); QCOMPARE(model->data(source2Index, Qt::EditRole).toString(), source2->name()); QCOMPARE(model->data(source3Index, Qt::EditRole).toString(), source3->name()); QCOMPARE(model->data(source4Index, Qt::EditRole).toString(), source4->name()); QVERIFY(!model->data(source1Index, Qt::CheckStateRole).isValid()); QCOMPARE(model->data(source2Index, Qt::CheckStateRole).toBool(), source2->isSelected()); QCOMPARE(model->data(source3Index, Qt::CheckStateRole).toBool(), source3->isSelected()); QCOMPARE(model->data(source4Index, Qt::CheckStateRole).toBool(), source4->isSelected()); QCOMPARE(model->data(source1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), source1->iconName()); QCOMPARE(model->data(source2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(source3Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(source4Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(source1Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), false); QCOMPARE(model->data(source2Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), true); QCOMPARE(model->data(source3Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), false); QCOMPARE(model->data(source4Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), false); // WHEN sourceRepositoryMock(&Domain::DataSourceRepository::update).when(source2).thenReturn(new FakeJob(this)); sourceRepositoryMock(&Domain::DataSourceRepository::update).when(source4).thenReturn(new FakeJob(this)); QVERIFY(!model->setData(source1Index, Qt::Unchecked, Qt::CheckStateRole)); QVERIFY(model->setData(source2Index, Qt::Checked, Qt::CheckStateRole)); QVERIFY(model->setData(source4Index, Qt::Unchecked, Qt::CheckStateRole)); // THEN QVERIFY(sourceRepositoryMock(&Domain::DataSourceRepository::update).when(source2).exactly(1)); QVERIFY(sourceRepositoryMock(&Domain::DataSourceRepository::update).when(source4).exactly(1)); QVERIFY(source2->isSelected()); QVERIFY(!source4->isSelected()); // WHEN QSignalSpy spy(model, &QAbstractItemModel::dataChanged); sourceQueriesMock(&Domain::DataSourceQueries::changeDefaultSource).when(source4).thenReturn(); sources.setDefaultItem(source4Index); // THEN QCOMPARE(model->data(source1Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), false); QCOMPARE(model->data(source2Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), false); QCOMPARE(model->data(source3Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), false); QCOMPARE(model->data(source4Index, Presentation::QueryTreeModelBase::IsDefaultRole).toBool(), true); // Not overly efficient way of signaling the change, but doesn't happen often QCOMPARE(spy.count(), 4); QCOMPARE(spy.at(0).at(0).toModelIndex(), source1Index); QCOMPARE(spy.at(0).at(1).toModelIndex(), source1Index); QCOMPARE(spy.at(1).at(0).toModelIndex(), source3Index); QCOMPARE(spy.at(1).at(1).toModelIndex(), source3Index); QCOMPARE(spy.at(2).at(0).toModelIndex(), source4Index); QCOMPARE(spy.at(2).at(1).toModelIndex(), source4Index); QCOMPARE(spy.at(3).at(0).toModelIndex(), source2Index); QCOMPARE(spy.at(3).at(1).toModelIndex(), source2Index); QVERIFY(sourceQueriesMock(&Domain::DataSourceQueries::changeDefaultSource).when(source4).exactly(1)); } void shouldGetAnErrorMessageWhenSetDataSourceFailed() { // GIVEN // Two top level sources auto source1 = Domain::DataSource::Ptr::create(); source1->setName(QStringLiteral("Source 1")); source1->setIconName(QStringLiteral("foo-icon")); source1->setSelected(false); source1->setContentTypes(Domain::DataSource::Tasks); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(source1); // Nothing under source1 auto source1Provider = Domain::QueryResultProvider::Ptr::create(); auto source1Result = Domain::QueryResult::create(source1Provider); Utils::MockObject sourceQueriesMock; sourceQueriesMock(&Domain::DataSourceQueries::findTopLevel).when().thenReturn(topLevelResult); sourceQueriesMock(&Domain::DataSourceQueries::findChildren).when(source1).thenReturn(source1Result); Utils::MockObject sourceRepositoryMock; Presentation::AvailableSourcesModel sources(sourceQueriesMock.getInstance(), sourceRepositoryMock.getInstance(), Q_NULLPTR); FakeErrorHandler errorHandler; sources.setErrorHandler(&errorHandler); // WHEN QAbstractItemModel *model = sources.sourceListModel(); // THEN const QModelIndex source1Index = model->index(0, 0); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); sourceRepositoryMock(&Domain::DataSourceRepository::update).when(source1).thenReturn(job); QVERIFY(model->setData(source1Index, Qt::Unchecked, Qt::CheckStateRole)); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify source Source 1: Foo")); } void shouldExecBackendSettingsDialog() { // GIVEN Utils::MockObject sourceRepositoryMock; sourceRepositoryMock(&Domain::DataSourceRepository::showConfigDialog).when().thenReturn(); Presentation::AvailableSourcesModel sources(Domain::DataSourceQueries::Ptr(), sourceRepositoryMock.getInstance()); // WHEN sources.showConfigDialog(); // THEN QVERIFY(sourceRepositoryMock(&Domain::DataSourceRepository::showConfigDialog).when().exactly(1)); } }; ZANSHIN_TEST_MAIN(AvailableSourcesModelTest) #include "availablesourcesmodeltest.moc" diff --git a/tests/units/presentation/availabletaskpagesmodeltest.cpp b/tests/units/presentation/availabletaskpagesmodeltest.cpp index 6cc41e06..66c48f10 100644 --- a/tests/units/presentation/availabletaskpagesmodeltest.cpp +++ b/tests/units/presentation/availabletaskpagesmodeltest.cpp @@ -1,1283 +1,1283 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "utils/mockobject.h" #include "utils/datetime.h" #include "domain/note.h" #include "presentation/availabletaskpagesmodel.h" #include "presentation/contextpagemodel.h" #include "presentation/errorhandler.h" #include "presentation/projectpagemodel.h" #include "presentation/querytreemodelbase.h" #include "presentation/taskinboxpagemodel.h" #include "presentation/workdaypagemodel.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class AvailableTaskPagesModelTest : public QObject { Q_OBJECT private slots: void shouldDeclareOnlyProjectAndContextPages() { // GIVEN Presentation::AvailableTaskPagesModel pages({}, {}, {}, {}, {}, {}, {}); // THEN QVERIFY(pages.hasProjectPages()); QVERIFY(pages.hasContextPages()); QVERIFY(!pages.hasTagPages()); } void shouldListAvailablePages() { // GIVEN // Two selected data sources auto source1 = Domain::DataSource::Ptr::create(); source1->setName("source1"); auto source2 = Domain::DataSource::Ptr::create(); source2->setName("source2"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source1); sourceProvider->append(source2); // Two projects under source 1 auto project11 = Domain::Project::Ptr::create(); project11->setName(QStringLiteral("Project 11")); auto project12 = Domain::Project::Ptr::create(); project12->setName(QStringLiteral("Project 12")); auto project1Provider = Domain::QueryResultProvider::Ptr::create(); auto project1Result = Domain::QueryResult::create(project1Provider); project1Provider->append(project12); project1Provider->append(project11); // note: reversed order, to test sorting // Two projects under source 2 auto project21 = Domain::Project::Ptr::create(); project21->setName(QStringLiteral("Project 21")); auto project22 = Domain::Project::Ptr::create(); project22->setName(QStringLiteral("Project 22")); auto project2Provider = Domain::QueryResultProvider::Ptr::create(); auto project2Result = Domain::QueryResult::create(project2Provider); project2Provider->append(project22); project2Provider->append(project21); // note: reversed order, to test sorting // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // Two artifacts (used for dropping later on) Domain::Artifact::Ptr taskToDrop(new Domain::Task); Domain::Artifact::Ptr noteToDrop(new Domain::Note); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source1).thenReturn(project1Result); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source2).thenReturn(project2Result); Utils::MockObject projectRepositoryMock; Utils::MockObject taskRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex inboxIndex = model->index(0, 0); const QModelIndex workdayIndex = model->index(1, 0); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex source1Index = model->index(0, 0, projectsIndex); const QModelIndex project11Index = model->index(0, 0, source1Index); const QModelIndex project12Index = model->index(1, 0, source1Index); const QModelIndex source2Index = model->index(1, 0, projectsIndex); const QModelIndex project21Index = model->index(0, 0, source2Index); const QModelIndex project22Index = model->index(1, 0, source2Index); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); const QModelIndex context2Index = model->index(1, 0, contextsIndex); QCOMPARE(model->rowCount(), 4); QCOMPARE(model->rowCount(inboxIndex), 0); QCOMPARE(model->rowCount(workdayIndex), 0); QCOMPARE(model->rowCount(projectsIndex), 2); QCOMPARE(model->rowCount(source1Index), 2); QCOMPARE(model->rowCount(project11Index), 0); QCOMPARE(model->rowCount(project12Index), 0); QCOMPARE(model->rowCount(source2Index), 2); QCOMPARE(model->rowCount(project21Index), 0); QCOMPARE(model->rowCount(project22Index), 0); QCOMPARE(model->rowCount(contextsIndex), 2); QCOMPARE(model->rowCount(context1Index), 0); QCOMPARE(model->rowCount(context2Index), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; QCOMPARE(model->flags(inboxIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(workdayIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(projectsIndex), Qt::NoItemFlags); QCOMPARE(model->flags(source1Index), Qt::NoItemFlags); QCOMPARE(model->flags(project11Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(project12Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(source2Index), Qt::NoItemFlags); QCOMPARE(model->flags(project21Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(project22Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(contextsIndex), Qt::NoItemFlags); QCOMPARE(model->flags(context1Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(context2Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->data(inboxIndex).toString(), i18n("Inbox")); QCOMPARE(model->data(workdayIndex).toString(), i18n("Workday")); QCOMPARE(model->data(projectsIndex).toString(), i18n("Projects")); QCOMPARE(model->data(source1Index).toString(), source1->name()); QCOMPARE(model->data(project11Index).toString(), project11->name()); QCOMPARE(model->data(project12Index).toString(), project12->name()); QCOMPARE(model->data(source2Index).toString(), source2->name()); QCOMPARE(model->data(project21Index).toString(), project21->name()); QCOMPARE(model->data(project22Index).toString(), project22->name()); QCOMPARE(model->data(contextsIndex).toString(), i18n("Contexts")); QCOMPARE(model->data(context1Index).toString(), context1->name()); QCOMPARE(model->data(context2Index).toString(), context2->name()); QVERIFY(!model->data(inboxIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(workdayIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(projectsIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(source1Index, Qt::EditRole).isValid()); QCOMPARE(model->data(project11Index, Qt::EditRole).toString(), project11->name()); QCOMPARE(model->data(project12Index, Qt::EditRole).toString(), project12->name()); QVERIFY(!model->data(source2Index, Qt::EditRole).isValid()); QCOMPARE(model->data(project21Index, Qt::EditRole).toString(), project21->name()); QCOMPARE(model->data(project22Index, Qt::EditRole).toString(), project22->name()); QVERIFY(!model->data(contextsIndex, Qt::EditRole).isValid()); QCOMPARE(model->data(context1Index, Qt::EditRole).toString(), context1->name()); QCOMPARE(model->data(context2Index, Qt::EditRole).toString(), context2->name()); QCOMPARE(model->data(inboxIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("mail-folder-inbox")); QCOMPARE(model->data(workdayIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("go-jump-today")); QCOMPARE(model->data(projectsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(source1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(project11Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(project12Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(source2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(project21Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(project22Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(contextsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(context1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-notes")); QCOMPARE(model->data(context2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-notes")); QVERIFY(!model->data(inboxIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(workdayIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(projectsIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(source1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project11Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project12Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(source2Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project21Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project22Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(contextsIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(context1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(context2Index, Qt::CheckStateRole).isValid()); // WHEN projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::update).when(project12).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::update).when(project21).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::update).when(project22).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::update).when(context1).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::update).when(context2).thenReturn(new FakeJob(this)); QVERIFY(!model->setData(inboxIndex, "Foo")); QVERIFY(!model->setData(projectsIndex, "Foo")); QVERIFY(!model->setData(source1Index, "Foo")); QVERIFY(model->setData(project11Index, "New Project 11")); QVERIFY(model->setData(project12Index, "New Project 12")); QVERIFY(!model->setData(source2Index, "Foo")); QVERIFY(model->setData(project21Index, "New Project 21")); QVERIFY(model->setData(project22Index, "New Project 22")); QVERIFY(!model->setData(contextsIndex, "Foo")); QVERIFY(model->setData(context1Index, "New Context 1")); QVERIFY(model->setData(context2Index, "New Context 2")); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project12).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project21).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project22).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::update).when(context1).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::update).when(context2).exactly(1)); QCOMPARE(project11->name(), QStringLiteral("New Project 11")); QCOMPARE(project12->name(), QStringLiteral("New Project 12")); QCOMPARE(project21->name(), QStringLiteral("New Project 21")); QCOMPARE(project22->name(), QStringLiteral("New Project 22")); QCOMPARE(context1->name(), QStringLiteral("New Context 1")); QCOMPARE(context2->name(), QStringLiteral("New Context 2")); // WHEN projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project11Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop).exactly(1)); // WHEN a task is dropped on a context contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop.objectCast()).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop.objectCast()).exactly(1)); // WHEN projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop.objectCast()).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex); QTest::qWait(150); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop.objectCast()).exactly(1)); // WHEN projectRepositoryMock(&Domain::ProjectRepository::associate).when(project12, noteToDrop).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << noteToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project12Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project12, noteToDrop).exactly(1)); // WHEN Domain::Artifact::Ptr taskToDrop2(new Domain::Task); Domain::Artifact::Ptr noteToDrop2(new Domain::Note); projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop2).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, noteToDrop2).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop2 << noteToDrop2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project11Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop2).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, noteToDrop2).exactly(1)); // WHEN a task and a note are dropped on a context data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop2 << noteToDrop2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop2.objectCast()).exactly(0)); // WHEN two tasks are dropped on a context Domain::Task::Ptr taskToDrop3(new Domain::Task); Domain::Task::Ptr taskToDrop4(new Domain::Task); contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop3).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop4).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop3 << taskToDrop4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop3).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop4).exactly(1)); // WHEN a task is drop on the workday Domain::Task::Ptr taskToDrop5(new Domain::Task); taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop5).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop5)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, workdayIndex); // THEN QCOMPARE(taskToDrop5->startDate().date(), Utils::DateTime::currentDateTime().date()); // WHEN two task are drop on the workday Domain::Task::Ptr taskToDrop6(new Domain::Task); Domain::Task::Ptr taskToDrop7(new Domain::Task); taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop6).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop7).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop6 << taskToDrop7)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, workdayIndex); // THEN QCOMPARE(taskToDrop6->startDate().date(), Utils::DateTime::currentDateTime().date()); QCOMPARE(taskToDrop7->startDate().date(), Utils::DateTime::currentDateTime().date()); } void shouldCreateInboxPage() { // GIVEN // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // Empty context provider auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // context mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Utils::MockObject projectRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex inboxIndex = model->index(0, 0); QObject *inboxPage = pages.createPageForIndex(inboxIndex); QVERIFY(qobject_cast(inboxPage)); } void shouldCreateWorkdayPage() { // GIVEN // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // Empty context provider auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // context mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Utils::MockObject projectRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex workdayIndex = model->index(1, 0); QObject *workdayPage = pages.createPageForIndex(workdayIndex); QVERIFY(qobject_cast(workdayPage)); } void shouldCreateProjectsPage() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 11")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 12")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // No contexts auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // data source mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); // projects mocking Utils::MockObject projectRepositoryMock; // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); const QModelIndex project2Index = model->index(1, 0, sourceIndex); QObject *projectsPage = pages.createPageForIndex(projectsIndex); QObject *sourcesPage = pages.createPageForIndex(sourceIndex); QObject *project1Page = pages.createPageForIndex(project1Index); QObject *project2Page = pages.createPageForIndex(project2Index); QVERIFY(!projectsPage); QVERIFY(!sourcesPage); QVERIFY(qobject_cast(project1Page)); QCOMPARE(qobject_cast(project1Page)->project(), project1); QVERIFY(qobject_cast(project2Page)); QCOMPARE(qobject_cast(project2Page)->project(), project2); } void shouldCreateContextsPage() { // GIVEN // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); // projects mocking Utils::MockObject projectRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); const QModelIndex context2Index = model->index(1, 0, contextsIndex); QObject *contextsPage = pages.createPageForIndex(contextsIndex); QObject *context1Page = pages.createPageForIndex(context1Index); QObject *context2Page = pages.createPageForIndex(context2Index); QVERIFY(!contextsPage); QVERIFY(qobject_cast(context1Page)); QCOMPARE(qobject_cast(context1Page)->context(), context1); QVERIFY(qobject_cast(context2Page)); QCOMPARE(qobject_cast(context2Page)->context(), context2); } void shouldAddProjects() { // GIVEN auto source = Domain::DataSource::Ptr::create(); Utils::MockObject projectRepositoryMock; projectRepositoryMock(&Domain::ProjectRepository::create).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), Domain::ContextQueries::Ptr(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN pages.addProject(QStringLiteral("Foo"), source); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::create).when(any(), any()) .exactly(1)); } void shouldGetAnErrorMessageWhenAddProjectFailed() { // GIVEN auto source = Domain::DataSource::Ptr::create(); source->setName(QStringLiteral("Source1")); Utils::MockObject projectRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::create).when(any(), any()) .thenReturn(job); Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), Domain::ContextQueries::Ptr(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); // WHEN pages.addProject(QStringLiteral("Foo"), source); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add project Foo in dataSource Source1: Foo")); } void shouldAddContexts() { // GIVEN Utils::MockObject contextRepositoryMock; contextRepositoryMock(&Domain::ContextRepository::create).when(any()) .thenReturn(new FakeJob(this)); Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), Domain::ContextQueries::Ptr(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN pages.addContext(QStringLiteral("Foo")); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::create).when(any()) .exactly(1)); } void shouldGetAnErrorMessageWhenAddContextFailed() { // GIVEN Utils::MockObject contextRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::create).when(any()) .thenReturn(job); Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), Domain::ContextQueries::Ptr(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); // WHEN pages.addContext(QStringLiteral("Foo")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add context Foo: Foo")); } void shouldRemoveProject() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // No contexts auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // data source mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); // projects mocking Utils::MockObject projectRepositoryMock; // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).thenReturn(new FakeJob(this)); // WHEN pages.removeItem(project1Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).exactly(1)); } void shouldGetAnErrorMessageWhenRemoveProjectFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // No contexts auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // data source mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); // projects mocking Utils::MockObject projectRepositoryMock; // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).thenReturn(job); // WHEN pages.removeItem(project1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove project Project 1: Foo")); } void shouldRemoveContext() { // GIVEN // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(new FakeJob(this)); // WHEN pages.removeItem(context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).exactly(1)); } void shouldGetAnErrorMessageWhenRemoveContextFailed() { // GIVEN // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(job); // WHEN pages.removeItem(context1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove context context 1: Foo")); } void shouldGetAnErrorMessageWhenUpdateProjectFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::update).when(project1).thenReturn(job); QVERIFY(model->setData(project1Index, "New Project 1")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify project Project 1: Foo")); } void shouldGetAnErrorMessageWhenUpdateContextFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::update).when(context1).thenReturn(job); QVERIFY(model->setData(context1Index, "New Context 1")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify context context 1: Foo")); } void shouldGetAnErrorMessageWhenAssociateProjectFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // One task (used for dropping later on) Domain::Artifact::Ptr taskToDrop(new Domain::Task); taskToDrop->setTitle(QStringLiteral("taskDropped")); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::associate).when(project1, taskToDrop).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add taskDropped to project Project 1: Foo")); } void shouldGetAnErrorMessageWhenAssociateContextFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // One task (used for dropping later on) Domain::Artifact::Ptr taskToDrop(new Domain::Task); taskToDrop->setTitle(QStringLiteral("taskDropped")); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop.objectCast()).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add taskDropped to context context 1: Foo")); } void shouldGetAnErrorMessageWhenDissociateFailed() { // GIVEN // Empty source provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // Empty context provider auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // One task (used for dropping later on) Domain::Artifact::Ptr taskToDrop(new Domain::Task); taskToDrop->setTitle(QStringLiteral("taskDropped")); // context mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskRepositoryMock; Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex inboxIndex = model->index(0, 0); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).thenReturn(job); taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop.objectCast()).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move taskDropped to Inbox: Foo")); } }; ZANSHIN_TEST_MAIN(AvailableTaskPagesModelTest) #include "availabletaskpagesmodeltest.moc" diff --git a/tests/units/presentation/contextpagemodeltest.cpp b/tests/units/presentation/contextpagemodeltest.cpp index e5dd5c80..32c66614 100644 --- a/tests/units/presentation/contextpagemodeltest.cpp +++ b/tests/units/presentation/contextpagemodeltest.cpp @@ -1,713 +1,713 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens Copyright 2014 Rémi Benoit This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "utils/mockobject.h" #include "domain/context.h" #include "domain/task.h" #include "domain/contextqueries.h" #include "domain/contextrepository.h" #include "domain/taskqueries.h" #include "domain/taskrepository.h" #include "domain/noterepository.h" #include "presentation/contextpagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class ContextPageModelTest : public QObject { Q_OBJECT private slots: void shouldListAssociatedTaskInContextCentralListView() { // GIVEN // A context auto context = Domain::Context::Ptr::create(); // Three tasks auto task1 = Domain::Task::Ptr::create(); task1->setTitle(QStringLiteral("task1")); auto task2 = Domain::Task::Ptr::create(); task2->setTitle(QStringLiteral("task2")); auto task3 = Domain::Task::Ptr::create(); task3->setTitle(QStringLiteral("task3")); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task1); taskProvider->append(task2); taskProvider->append(task3); // Two tasks under the task1 auto childTask11 = Domain::Task::Ptr::create(); childTask11->setTitle(QStringLiteral("childTask11")); auto childTask12 = Domain::Task::Ptr::create(); childTask12->setTitle(QStringLiteral("childTask12")); auto childTaskProvider = Domain::QueryResultProvider::Ptr::create(); auto childTaskResult = Domain::QueryResult::create(childTaskProvider); taskProvider->append(childTask12); childTaskProvider->append(childTask11); childTaskProvider->append(childTask12); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(childTaskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task3).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask11).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask12).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject contextRepositoryMock; Utils::MockObject taskRepositoryMock; Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = page.centralListModel(); // THEN const QModelIndex task1Index = model->index(0, 0); const QModelIndex task2Index = model->index(1, 0); const QModelIndex task3Index = model->index(2, 0); const QModelIndex taskChildTask12Index = model->index(3, 0); const QModelIndex childTask11Index = model->index(0, 0, task1Index); const QModelIndex childTask12Index = model->index(1, 0, task1Index); QCOMPARE(page.context(), context); QCOMPARE(model->rowCount(), 4); QCOMPARE(model->rowCount(task1Index), 2); QCOMPARE(model->rowCount(task2Index), 0); QCOMPARE(model->rowCount(task3Index), 0); QCOMPARE(model->rowCount(taskChildTask12Index), 0); QVERIFY(childTask11Index.isValid()); QVERIFY(childTask12Index.isValid()); QCOMPARE(model->rowCount(childTask11Index), 0); QCOMPARE(model->rowCount(childTask12Index), 0); const Qt::ItemFlags taskFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled; QCOMPARE(model->flags(task1Index), taskFlags); QCOMPARE(model->flags(childTask11Index), taskFlags); QCOMPARE(model->flags(childTask12Index), taskFlags); QCOMPARE(model->flags(task2Index), taskFlags); QCOMPARE(model->flags(task3Index), taskFlags); QCOMPARE(model->flags(taskChildTask12Index), taskFlags); QCOMPARE(model->data(task1Index).toString(), task1->title()); QCOMPARE(model->data(childTask11Index).toString(), childTask11->title()); QCOMPARE(model->data(childTask12Index).toString(), childTask12->title()); QCOMPARE(model->data(task2Index).toString(), task2->title()); QCOMPARE(model->data(task3Index).toString(), task3->title()); QCOMPARE(model->data(taskChildTask12Index).toString(), childTask12->title()); QCOMPARE(model->data(task1Index, Qt::EditRole).toString(), task1->title()); QCOMPARE(model->data(childTask11Index, Qt::EditRole).toString(), childTask11->title()); QCOMPARE(model->data(childTask12Index, Qt::EditRole).toString(), childTask12->title()); QCOMPARE(model->data(task2Index, Qt::EditRole).toString(), task2->title()); QCOMPARE(model->data(task3Index, Qt::EditRole).toString(), task3->title()); QCOMPARE(model->data(taskChildTask12Index, Qt::EditRole).toString(), childTask12->title()); QVERIFY(model->data(task1Index, Qt::CheckStateRole).isValid()); QVERIFY(model->data(childTask11Index, Qt::CheckStateRole).isValid()); QVERIFY(model->data(childTask12Index, Qt::CheckStateRole).isValid()); QVERIFY(model->data(task2Index, Qt::CheckStateRole).isValid()); QVERIFY(model->data(task3Index, Qt::CheckStateRole).isValid()); QVERIFY(model->data(taskChildTask12Index, Qt::CheckStateRole).isValid()); QCOMPARE(model->data(task1Index, Qt::CheckStateRole).toBool(), task1->isDone()); QCOMPARE(model->data(childTask11Index, Qt::CheckStateRole).toBool(), childTask11->isDone()); QCOMPARE(model->data(childTask12Index, Qt::CheckStateRole).toBool(), childTask12->isDone()); QCOMPARE(model->data(task2Index, Qt::CheckStateRole).toBool(), task2->isDone()); QCOMPARE(model->data(task3Index, Qt::CheckStateRole).toBool(), task3->isDone()); QCOMPARE(model->data(taskChildTask12Index, Qt::CheckStateRole).toBool(), childTask12->isDone()); // WHEN taskRepositoryMock(&Domain::TaskRepository::update).when(task1).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(childTask11).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(childTask12).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(task2).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(task3).thenReturn(new FakeJob(this)); QVERIFY(model->setData(task1Index, "newTask1")); QVERIFY(model->setData(childTask11Index, "newChildTask11")); QVERIFY(model->setData(task2Index, "newTask2")); QVERIFY(model->setData(task3Index, "newTask3")); QVERIFY(model->setData(taskChildTask12Index, "newChildTask12")); QVERIFY(model->setData(task1Index, Qt::Unchecked, Qt::CheckStateRole)); QVERIFY(model->setData(childTask11Index, Qt::Unchecked, Qt::CheckStateRole)); QVERIFY(model->setData(task2Index, Qt::Checked, Qt::CheckStateRole)); QVERIFY(model->setData(task3Index, Qt::Unchecked, Qt::CheckStateRole)); QVERIFY(model->setData(taskChildTask12Index, Qt::Checked, Qt::CheckStateRole)); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task1).exactly(2)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask11).exactly(2)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask12).exactly(2)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task2).exactly(2)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task3).exactly(2)); QCOMPARE(task1->title(), QStringLiteral("newTask1")); QCOMPARE(childTask11->title(), QStringLiteral("newChildTask11")); QCOMPARE(childTask12->title(), QStringLiteral("newChildTask12")); QCOMPARE(task2->title(), QStringLiteral("newTask2")); QCOMPARE(task3->title(), QStringLiteral("newTask3")); QCOMPARE(task1->isDone(), false); QCOMPARE(childTask11->isDone(), false); QCOMPARE(childTask12->isDone(), true); QCOMPARE(task2->isDone(), true); QCOMPARE(task3->isDone(), false); // WHEN QVERIFY(!model->setData(task1Index, QVariant(), Qt::WhatsThisRole)); QVERIFY(!model->setData(task1Index, QVariant(), Qt::ForegroundRole)); QVERIFY(!model->setData(task1Index, QVariant(), Qt::InitialSortOrderRole)); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task1).exactly(2)); QCOMPARE(task1->title(), QStringLiteral("newTask1")); QCOMPARE(task2->title(), QStringLiteral("newTask2")); // WHEN a task is dragged auto data = std::unique_ptr(model->mimeData(QModelIndexList() << task2Index)); // THEN QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); QCOMPARE(data->property("objects").value(), Domain::Artifact::List() << task2); // WHEN a task is dropped auto childTask2 = Domain::Task::Ptr::create(); taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask2).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, task1Index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask2).exactly(1)); // WHEN two tasks are dropped auto childTask3 = Domain::Task::Ptr::create(); auto childTask4 = Domain::Task::Ptr::create(); taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask3).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask4).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask3 << childTask4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, task1Index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask3).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask4).exactly(1)); // WHEN a task and a note are dropped Domain::Artifact::Ptr childTask5(new Domain::Task); Domain::Artifact::Ptr childNote(new Domain::Note); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask5 << childNote)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, task1Index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(task1, childTask5.objectCast()).exactly(0)); } void shouldAddTasksInContext() { // GIVEN // One Context auto context = Domain::Context::Ptr::create(); // ... in fact we won't list any model Utils::MockObject contextQueriesMock; Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; // We'll gladly create a task though Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::createInContext).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN auto title = QStringLiteral("New task"); auto task = page.addItem(title).objectCast(); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createInContext).when(any(), any()) .exactly(1)); QVERIFY(task); QCOMPARE(task->title(), title); } void shouldAddChildTask() { // GIVEN // One Context auto context = Domain::Context::Ptr::create(); // A task auto task = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task); auto childProvider = Domain::QueryResultProvider::Ptr::create(); auto childResult = Domain::QueryResult::create(childProvider); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task).thenReturn(childResult); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const auto title = QStringLiteral("New task"); const auto parentIndex = page.centralListModel()->index(0, 0); const auto createdTask = page.addItem(title, parentIndex).objectCast(); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), any()) .exactly(1)); QVERIFY(createdTask); QCOMPARE(createdTask->title(), title); } void shouldRemoveTopLevelItem() { // GIVEN // One context auto context = Domain::Context::Ptr::create(); // A task auto task = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task); auto childProvider = Domain::QueryResultProvider::Ptr::create(); auto childResult = Domain::QueryResult::create(childProvider); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject contextRepositoryMock; contextRepositoryMock(&Domain::ContextRepository::dissociate).when(context, task).thenReturn(new FakeJob(this)); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task).thenReturn(childResult); Utils::MockObject taskRepositoryMock; Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const QModelIndex indexTask = page.centralListModel()->index(0, 0); page.removeItem(indexTask); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::dissociate).when(context, task).exactly(1)); } void shouldRemoveChildItem() { // GIVEN // One context auto context = Domain::Context::Ptr::create(); // A task... auto task = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task); // ... with a child auto childTask = Domain::Task::Ptr::create(); auto childProvider = Domain::QueryResultProvider::Ptr::create(); auto childResult = Domain::QueryResult::create(childProvider); childProvider->append(childTask); auto emptyProvider = Domain::QueryResultProvider::Ptr::create(); auto emptyResult = Domain::QueryResult::create(emptyProvider); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task).thenReturn(childResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask).thenReturn(emptyResult); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask).thenReturn(new FakeJob(this)); Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const auto taskIndex = page.centralListModel()->index(0, 0); const auto childTaskIndex = page.centralListModel()->index(0, 0, taskIndex); page.removeItem(childTaskIndex); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask).exactly(1)); } void shouldPromoteItem() { // GIVEN // One context auto context = Domain::Context::Ptr::create(); // A task auto task = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task); auto childProvider = Domain::QueryResultProvider::Ptr::create(); auto childResult = Domain::QueryResult::create(childProvider); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task).thenReturn(childResult); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task).thenReturn(new FakeJob(this)); Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const QModelIndex indexTask = page.centralListModel()->index(0, 0); page.promoteItem(indexTask); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task).exactly(1)); } void shouldGetAnErrorMessageWhenAddTaskFailed() { // GIVEN // One Context auto context = Domain::Context::Ptr::create(); context->setName(QStringLiteral("Context1")); // ... in fact we won't list any model Utils::MockObject contextQueriesMock; Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; // We'll gladly create a task though Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::createInContext).when(any(), any()) .thenReturn(job); Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN page.addItem(QStringLiteral("New task")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add task New task in context Context1: Foo")); } void shouldGetAnErrorMessageWhenUpdateTaskFailed() { // GIVEN // A context auto context = Domain::Context::Ptr::create(); context->setName(QStringLiteral("Context1")); // A task auto task = Domain::Task::Ptr::create(); task->setTitle(QStringLiteral("A task")); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task); auto childProvider = Domain::QueryResultProvider::Ptr::create(); auto childResult = Domain::QueryResult::create(childProvider); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task).thenReturn(childResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskRepositoryMock; Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); QAbstractItemModel *model = page.centralListModel(); const QModelIndex taskIndex = model->index(0, 0); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::update).when(task).thenReturn(job); QVERIFY(model->setData(taskIndex, "newTask")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify task A task in context Context1: Foo")); } void shouldGetAnErrorMessageWhenAssociateTaskFailed() { // GIVEN // A context auto context = Domain::Context::Ptr::create(); context->setName(QStringLiteral("Context1")); // A parent task and a child task auto parentTask = Domain::Task::Ptr::create(); parentTask->setTitle(QStringLiteral("A parent task")); auto childTask = Domain::Task::Ptr::create(); childTask->setTitle(QStringLiteral("A child task")); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(parentTask); taskProvider->append(childTask); auto childProvider = Domain::QueryResultProvider::Ptr::create(); auto childResult = Domain::QueryResult::create(childProvider); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(parentTask).thenReturn(childResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask).thenReturn(childResult); Utils::MockObject taskRepositoryMock; Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = page.centralListModel(); const QModelIndex parentTaskIndex = model->index(0, 0); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN a task is dropped auto childTask2 = Domain::Task::Ptr::create(); childTask2->setTitle(QStringLiteral("childTask2")); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::associate).when(parentTask, childTask2).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, parentTaskIndex); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move task childTask2 as sub-task of A parent task: Foo")); } void shouldAssociateToContextWithNoParentWhenDroppingOnEmptyArea() { // GIVEN // One context auto context = Domain::Context::Ptr::create(); context->setName(QStringLiteral("Context")); // One top level task auto topLevelTask = Domain::Task::Ptr::create(); topLevelTask->setTitle(QStringLiteral("rootTask")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(topLevelTask); // Two tasks under the top level task auto childTask1 = Domain::Task::Ptr::create(); childTask1->setTitle(QStringLiteral("childTask1")); childTask1->setDone(true); auto childTask2 = Domain::Task::Ptr::create(); childTask2->setTitle(QStringLiteral("childTask2")); childTask2->setDone(false); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(childTask1); taskProvider->append(childTask2); Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(topLevelResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(topLevelTask).thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::ContextPageModel page(context, contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); auto model = page.centralListModel(); // WHEN taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask1).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask2).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::associate).when(context, childTask1).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::associate).when(context, childTask2).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask1 << childTask2)); // both will be DnD on the empty part model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, QModelIndex()); // THEN QTest::qWait(150); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask1).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask2).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context, childTask1).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context, childTask2).exactly(1)); } }; ZANSHIN_TEST_MAIN(ContextPageModelTest) #include "contextpagemodeltest.moc" diff --git a/tests/units/presentation/errorhandlertest.cpp b/tests/units/presentation/errorhandlertest.cpp index 695bf441..46ec4a9d 100644 --- a/tests/units/presentation/errorhandlertest.cpp +++ b/tests/units/presentation/errorhandlertest.cpp @@ -1,89 +1,89 @@ /* This file is part of Zanshin Copyright 2014 Mario Bensi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "presentation/errorhandler.h" #include "testlib/fakejob.h" class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class ErrorHandlerTest : public QObject { Q_OBJECT private slots: void shouldDisplayErrorMessage() { // GIVEN // create job auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); // create ErrorHandler FakeErrorHandler errorHandler; const QString message = QStringLiteral("I Failed !!!!!!!!!!"); // WHEN errorHandler.installHandler(job, message); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("I Failed !!!!!!!!!!: Foo")); } void shouldDisplayNothing() { // GIVEN // create job auto job = new FakeJob(this); // create ErrorHandler FakeErrorHandler errorHandler; const QString message = QStringLiteral("I Failed !!!!!!!!!!"); // WHEN errorHandler.installHandler(job, message); // THEN QTest::qWait(150); QVERIFY(errorHandler.m_message.isEmpty()); } }; ZANSHIN_TEST_MAIN(ErrorHandlerTest) #include "errorhandlertest.moc" diff --git a/tests/units/presentation/errorhandlingmodelbasetest.cpp b/tests/units/presentation/errorhandlingmodelbasetest.cpp index cdc1de54..9fa935a9 100644 --- a/tests/units/presentation/errorhandlingmodelbasetest.cpp +++ b/tests/units/presentation/errorhandlingmodelbasetest.cpp @@ -1,104 +1,104 @@ /* This file is part of Zanshin Copyright 2014 Mario Bensi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "presentation/errorhandlingmodelbase.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class FakeErrorHandlingModelBase : public Presentation::ErrorHandlingModelBase { public: void install(KJob *job, const QString &message) { installHandler(job, message); } }; class ErrorHandlingModelBaseTest : public QObject { Q_OBJECT private slots: void shouldDisplayMessageOnError() { // GIVEN // create job auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); // create ErrorHandlingModelBase FakeErrorHandler errorHandler; FakeErrorHandlingModelBase errorHandling; errorHandling.setErrorHandler(&errorHandler); const QString message = QStringLiteral("I Failed !!!!!!!!!!"); // WHEN errorHandling.install(job, message); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("I Failed !!!!!!!!!!: Foo")); QCOMPARE(errorHandling.errorHandler(), &errorHandler); } void shouldNotDisplayMessageWhenNoErrorOccurred() { // GIVEN // create job auto job = new FakeJob(this); // create ErrorHandlingModelBase FakeErrorHandler errorHandler; FakeErrorHandlingModelBase errorHandling; errorHandling.setErrorHandler(&errorHandler); const QString message = QStringLiteral("I Failed !!!!!!!!!!"); // WHEN errorHandling.install(job, message); // THEN QTest::qWait(150); QVERIFY(errorHandler.m_message.isEmpty()); } }; ZANSHIN_TEST_MAIN(ErrorHandlingModelBaseTest) #include "errorhandlingmodelbasetest.moc" diff --git a/tests/units/presentation/noteinboxpagemodeltest.cpp b/tests/units/presentation/noteinboxpagemodeltest.cpp index fd142360..75120f21 100644 --- a/tests/units/presentation/noteinboxpagemodeltest.cpp +++ b/tests/units/presentation/noteinboxpagemodeltest.cpp @@ -1,291 +1,291 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "utils/mockobject.h" #include "presentation/noteinboxpagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class NoteInboxPageModelTest : public QObject { Q_OBJECT private slots: void shouldListInboxInCentralListModel() { // GIVEN // Two notes auto note1 = Domain::Note::Ptr::create(); note1->setTitle(QStringLiteral("note1")); auto note2 = Domain::Note::Ptr::create(); note2->setTitle(QStringLiteral("note2")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject noteQueriesMock; noteQueriesMock(&Domain::NoteQueries::findInbox).when().thenReturn(noteResult); Utils::MockObject noteRepositoryMock; Presentation::NoteInboxPageModel inbox(noteQueriesMock.getInstance(), noteRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = inbox.centralListModel(); // THEN const QModelIndex note1Index = model->index(0, 0); const QModelIndex note2Index = model->index(1, 0); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(note1Index), 0); QCOMPARE(model->rowCount(note2Index), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled; QCOMPARE(model->flags(note1Index), defaultFlags); QCOMPARE(model->flags(note2Index), defaultFlags); QCOMPARE(model->data(note1Index).toString(), note1->title()); QCOMPARE(model->data(note2Index).toString(), note2->title()); QCOMPARE(model->data(note1Index, Qt::EditRole).toString(), note1->title()); QCOMPARE(model->data(note2Index, Qt::EditRole).toString(), note2->title()); QVERIFY(!model->data(note1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(note2Index, Qt::CheckStateRole).isValid()); // WHEN noteRepositoryMock(&Domain::NoteRepository::update).when(note1).thenReturn(new FakeJob(this)); noteRepositoryMock(&Domain::NoteRepository::update).when(note2).thenReturn(new FakeJob(this)); QVERIFY(model->setData(note1Index, "newNote1")); QVERIFY(model->setData(note2Index, "newNote2")); QVERIFY(!model->setData(note1Index, Qt::Checked, Qt::CheckStateRole)); QVERIFY(!model->setData(note2Index, Qt::Checked, Qt::CheckStateRole)); // THEN QVERIFY(noteRepositoryMock(&Domain::NoteRepository::update).when(note1).exactly(1)); QVERIFY(noteRepositoryMock(&Domain::NoteRepository::update).when(note2).exactly(1)); QCOMPARE(note1->title(), QStringLiteral("newNote1")); QCOMPARE(note2->title(), QStringLiteral("newNote2")); // WHEN auto data = std::unique_ptr(model->mimeData(QModelIndexList() << note2Index)); // THEN QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); QCOMPARE(data->property("objects").value(), Domain::Artifact::List() << note2); } void shouldAddNotes() { // GIVEN // ... in fact we won't list any model Utils::MockObject noteQueriesMock; // We'll gladly create a note though Utils::MockObject noteRepositoryMock; noteRepositoryMock(&Domain::NoteRepository::create).when(any()).thenReturn(new FakeJob(this)); Presentation::NoteInboxPageModel inbox(noteQueriesMock.getInstance(), noteRepositoryMock.getInstance()); // WHEN auto title = QStringLiteral("New note"); auto note = inbox.addItem(title).objectCast(); // THEN QVERIFY(noteRepositoryMock(&Domain::NoteRepository::create).when(any()).exactly(1)); QVERIFY(note); QCOMPARE(note->title(), title); } void shouldGetAnErrorMessageWhenAddNoteFailed() { // GIVEN // ... in fact we won't list any model Utils::MockObject noteQueriesMock; // We'll gladly create a note though Utils::MockObject noteRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); noteRepositoryMock(&Domain::NoteRepository::create).when(any()).thenReturn(job); Presentation::NoteInboxPageModel inbox(noteQueriesMock.getInstance(), noteRepositoryMock.getInstance()); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN inbox.addItem(QStringLiteral("New note")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add note New note in Inbox: Foo")); } void shouldDeleteItems() { // GIVEN // Two notes auto note1 = Domain::Note::Ptr::create(); note1->setTitle(QStringLiteral("note1")); auto note2 = Domain::Note::Ptr::create(); note2->setTitle(QStringLiteral("note2")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject noteQueriesMock; noteQueriesMock(&Domain::NoteQueries::findInbox).when().thenReturn(noteResult); Utils::MockObject noteRepositoryMock; noteRepositoryMock(&Domain::NoteRepository::remove).when(note2).thenReturn(new FakeJob(this)); Presentation::NoteInboxPageModel inbox(noteQueriesMock.getInstance(), noteRepositoryMock.getInstance()); // WHEN const QModelIndex index = inbox.centralListModel()->index(1, 0); inbox.removeItem(index); // THEN QVERIFY(noteRepositoryMock(&Domain::NoteRepository::remove).when(note2).exactly(1)); } void shouldGetAnErrorMessageWhenDeleteItemsFailed() { // GIVEN // Two notes auto note1 = Domain::Note::Ptr::create(); note1->setTitle(QStringLiteral("note1")); auto note2 = Domain::Note::Ptr::create(); note2->setTitle(QStringLiteral("note2")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject noteQueriesMock; noteQueriesMock(&Domain::NoteQueries::findInbox).when().thenReturn(noteResult); Utils::MockObject noteRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); noteRepositoryMock(&Domain::NoteRepository::remove).when(note2).thenReturn(job); Presentation::NoteInboxPageModel inbox(noteQueriesMock.getInstance(), noteRepositoryMock.getInstance()); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN const QModelIndex index = inbox.centralListModel()->index(1, 0); inbox.removeItem(index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove note note2 from Inbox: Foo")); } void shouldGetAnErrorMessageWhenUpdateNoteFailed() { // GIVEN // Two notes auto note1 = Domain::Note::Ptr::create(); note1->setTitle(QStringLiteral("note1")); auto note2 = Domain::Note::Ptr::create(); note2->setTitle(QStringLiteral("note2")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject noteQueriesMock; noteQueriesMock(&Domain::NoteQueries::findInbox).when().thenReturn(noteResult); Utils::MockObject noteRepositoryMock; Presentation::NoteInboxPageModel inbox(noteQueriesMock.getInstance(), noteRepositoryMock.getInstance()); QAbstractItemModel *model = inbox.centralListModel(); const QModelIndex note1Index = model->index(0, 0); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); noteRepositoryMock(&Domain::NoteRepository::update).when(note1).thenReturn(job); QVERIFY(model->setData(note1Index, "newNote1")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify note note1 in Inbox: Foo")); } }; ZANSHIN_TEST_MAIN(NoteInboxPageModelTest) #include "noteinboxpagemodeltest.moc" diff --git a/tests/units/presentation/pagemodeltest.cpp b/tests/units/presentation/pagemodeltest.cpp index 2f1dc61c..6605506a 100644 --- a/tests/units/presentation/pagemodeltest.cpp +++ b/tests/units/presentation/pagemodeltest.cpp @@ -1,87 +1,87 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "presentation/pagemodel.h" class FakePageModel : public Presentation::PageModel { Q_OBJECT public: explicit FakePageModel(QObject *parent = Q_NULLPTR) : Presentation::PageModel(parent), createCount(0), itemModel(Q_NULLPTR) { } - Domain::Artifact::Ptr addItem(const QString &, const QModelIndex &) { return Domain::Artifact::Ptr::create(); } - void removeItem(const QModelIndex &) {} - void promoteItem(const QModelIndex &) {} + Domain::Artifact::Ptr addItem(const QString &, const QModelIndex &) override { return Domain::Artifact::Ptr::create(); } + void removeItem(const QModelIndex &) override {} + void promoteItem(const QModelIndex &) override {} private: - QAbstractItemModel *createCentralListModel() + QAbstractItemModel *createCentralListModel() override { createCount++; itemModel = new QStringListModel(this); return itemModel; } public: int createCount; QAbstractItemModel *itemModel; }; class PageModelTest : public QObject { Q_OBJECT private slots: void shouldLazilyCreateModelOnlyOnce() { // GIVEN FakePageModel model; QCOMPARE(model.createCount, 0); QVERIFY(!model.itemModel); // WHEN QAbstractItemModel *itemModel = model.centralListModel(); // THEN QCOMPARE(model.createCount, 1); QCOMPARE(itemModel, model.itemModel); // WHEN itemModel = model.centralListModel(); // THEN QCOMPARE(model.createCount, 1); QCOMPARE(itemModel, model.itemModel); } }; ZANSHIN_TEST_MAIN(PageModelTest) #include "pagemodeltest.moc" diff --git a/tests/units/presentation/projectpagemodeltest.cpp b/tests/units/presentation/projectpagemodeltest.cpp index 58b2ca0a..46f4baf8 100644 --- a/tests/units/presentation/projectpagemodeltest.cpp +++ b/tests/units/presentation/projectpagemodeltest.cpp @@ -1,650 +1,650 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "utils/mockobject.h" #include "presentation/projectpagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class ProjectPageModelTest : public QObject { Q_OBJECT private slots: void shouldListProjectInCentralListModel() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); // One task auto rootTask = Domain::Task::Ptr::create(); rootTask->setTitle(QStringLiteral("rootTask")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(rootTask); // One task under the root task auto childTask = Domain::Task::Ptr::create(); childTask->setTitle(QStringLiteral("childTask")); childTask->setDone(true); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(childTask); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(rootTask).thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = page.centralListModel(); // THEN const QModelIndex rootTaskIndex = model->index(0, 0); const QModelIndex childTaskIndex = model->index(0, 0, rootTaskIndex); QCOMPARE(page.project(), project); QCOMPARE(model->rowCount(), 1); QCOMPARE(model->rowCount(rootTaskIndex), 1); QCOMPARE(model->rowCount(childTaskIndex), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled; QCOMPARE(model->flags(rootTaskIndex), defaultFlags); QCOMPARE(model->flags(childTaskIndex), defaultFlags); QCOMPARE(model->data(rootTaskIndex).toString(), rootTask->title()); QCOMPARE(model->data(childTaskIndex).toString(), childTask->title()); QCOMPARE(model->data(rootTaskIndex, Qt::EditRole).toString(), rootTask->title()); QCOMPARE(model->data(childTaskIndex, Qt::EditRole).toString(), childTask->title()); QVERIFY(model->data(rootTaskIndex, Qt::CheckStateRole).isValid()); QVERIFY(model->data(childTaskIndex, Qt::CheckStateRole).isValid()); QCOMPARE(model->data(rootTaskIndex, Qt::CheckStateRole).toBool(), rootTask->isDone()); QCOMPARE(model->data(childTaskIndex, Qt::CheckStateRole).toBool(), childTask->isDone()); // WHEN taskRepositoryMock(&Domain::TaskRepository::update).when(rootTask).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(childTask).thenReturn(new FakeJob(this)); QVERIFY(model->setData(rootTaskIndex, "newRootTask")); QVERIFY(model->setData(childTaskIndex, "newChildTask")); QVERIFY(model->setData(rootTaskIndex, Qt::Checked, Qt::CheckStateRole)); QVERIFY(model->setData(childTaskIndex, Qt::Unchecked, Qt::CheckStateRole)); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(rootTask).exactly(2)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask).exactly(2)); QCOMPARE(rootTask->title(), QStringLiteral("newRootTask")); QCOMPARE(childTask->title(), QStringLiteral("newChildTask")); QCOMPARE(rootTask->isDone(), true); QCOMPARE(childTask->isDone(), false); // WHEN auto data = std::unique_ptr(model->mimeData(QModelIndexList() << childTaskIndex)); // THEN QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); QCOMPARE(data->property("objects").value(), Domain::Artifact::List() << childTask); // WHEN auto childTask2 = Domain::Task::Ptr::create(); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask2).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, rootTaskIndex); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask2).exactly(1)); // WHEN auto childTask3 = Domain::Task::Ptr::create(); auto childTask4 = Domain::Task::Ptr::create(); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask3).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask3 << childTask4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, rootTaskIndex); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask3).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).exactly(1)); } void shouldAddTasksInProject() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); // ... in fact we won't list any model Utils::MockObject projectQueriesMock; Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; // We'll gladly create a task though Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::createInProject).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN auto title = QStringLiteral("New task"); auto task = page.addItem(title).objectCast(); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createInProject).when(any(), any()) .exactly(1)); QVERIFY(task); QCOMPARE(task->title(), title); } void shouldAddChildTask() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(task1); topLevelProvider->append(task2); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const auto title = QStringLiteral("New task"); const auto parentIndex = page.centralListModel()->index(0, 0); const auto createdTask = page.addItem(title, parentIndex).objectCast(); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), any()) .exactly(1)); QVERIFY(createdTask); QCOMPARE(createdTask->title(), title); } void shouldGetAnErrorMessageWhenAddTaskFailed() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("Project1")); // ... in fact we won't list any model Utils::MockObject projectQueriesMock; Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; // We'll gladly create a task though Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::createInProject).when(any(), any()) .thenReturn(job); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN page.addItem(QStringLiteral("New task")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add task New task in project Project1: Foo")); } void shouldDeleteItems() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(task1); topLevelProvider->append(task2); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).thenReturn(new FakeJob(this)); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const QModelIndex index = page.centralListModel()->index(1, 0); page.removeItem(index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).exactly(1)); } void shouldGetAnErrorMessageWhenDeleteItemsFailed() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("Project1")); // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); task2->setTitle(QStringLiteral("Task2")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(task1); topLevelProvider->append(task2); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).thenReturn(job); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN const QModelIndex index = page.centralListModel()->index(1, 0); page.removeItem(index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove task Task2 from project Project1: Foo")); } void shouldPromoteItem() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(task1); topLevelProvider->append(task2); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this)); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const QModelIndex index = page.centralListModel()->index(1, 0); page.promoteItem(index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1)); } void shouldGetAnErrorMessageWhenPromoteItemFailed() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("Project1")); // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); task2->setTitle(QStringLiteral("Task2")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(task1); topLevelProvider->append(task2); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(job); Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN const QModelIndex index = page.centralListModel()->index(1, 0); page.promoteItem(index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot promote task Task2 to be a project: Foo")); } void shouldGetAnErrorMessageWhenUpdateTaskFailed() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("Project1")); // One task auto rootTask = Domain::Task::Ptr::create(); rootTask->setTitle(QStringLiteral("rootTask")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(rootTask); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(rootTask).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); QAbstractItemModel *model = page.centralListModel(); const QModelIndex rootTaskIndex = model->index(0, 0); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::update).when(rootTask).thenReturn(job); QVERIFY(model->setData(rootTaskIndex, "newRootTask")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify task rootTask in project Project1: Foo")); } void shouldGetAnErrorMessageWhenAssociateTaskFailed() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("Project1")); // One task auto rootTask = Domain::Task::Ptr::create(); rootTask->setTitle(QStringLiteral("rootTask")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(rootTask); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(rootTask).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); QAbstractItemModel *model = page.centralListModel(); const QModelIndex rootTaskIndex = model->index(0, 0); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN auto childTask3 = Domain::Task::Ptr::create(); childTask3->setTitle(QStringLiteral("childTask3")); auto childTask4 = Domain::Task::Ptr::create(); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask3).thenReturn(job); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask3 << childTask4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, rootTaskIndex); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move task childTask3 as a sub-task of rootTask: Foo")); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).exactly(1)); } void shouldAssociateToProjectWhenDroppingOnEmptyArea() { // GIVEN // One project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("Project")); // One top level task auto topLevelTask = Domain::Task::Ptr::create(); topLevelTask->setTitle(QStringLiteral("rootTask")); auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); auto topLevelResult = Domain::QueryResult::create(topLevelProvider); topLevelProvider->append(topLevelTask); // Two tasks under the top level task auto childTask1 = Domain::Task::Ptr::create(); childTask1->setTitle(QStringLiteral("childTask1")); childTask1->setDone(true); auto childTask2 = Domain::Task::Ptr::create(); childTask2->setTitle(QStringLiteral("childTask2")); childTask2->setDone(false); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(childTask1); taskProvider->append(childTask2); Utils::MockObject projectQueriesMock; projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findChildren).when(topLevelTask).thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::ProjectPageModel page(project, projectQueriesMock.getInstance(), projectRepositoryMock.getInstance(), taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); auto model = page.centralListModel(); // WHEN projectRepositoryMock(&Domain::ProjectRepository::associate).when(project, childTask1).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::associate).when(project, childTask2).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask1 << childTask2)); // both will be DnD on the empty part model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, QModelIndex()); // THEN QTest::qWait(150); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project, childTask1).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project, childTask2).exactly(1)); } }; ZANSHIN_TEST_MAIN(ProjectPageModelTest) #include "projectpagemodeltest.moc" diff --git a/tests/units/presentation/tagpagemodeltest.cpp b/tests/units/presentation/tagpagemodeltest.cpp index a1c80107..0d745a88 100644 --- a/tests/units/presentation/tagpagemodeltest.cpp +++ b/tests/units/presentation/tagpagemodeltest.cpp @@ -1,340 +1,340 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens Copyright 2014 Franck Arrecot This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "utils/mockobject.h" #include "domain/noterepository.h" #include "domain/tagqueries.h" #include "domain/tagrepository.h" #include "presentation/tagpagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class TagPageModelTest : public QObject { Q_OBJECT private slots: void shouldListTagNotesInCentralListModel() { // GIVEN // One Tag auto tag = Domain::Tag::Ptr::create(); // Two notes auto note1 = Domain::Note::Ptr::create(); note1->setTitle(QStringLiteral("note1")); auto note2 = Domain::Note::Ptr::create(); note2->setTitle(QStringLiteral("note2")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findNotes).when(tag).thenReturn(noteResult); Utils::MockObject tagRepositoryMock; Utils::MockObject noteRepositoryMock; Presentation::TagPageModel page(tag, tagQueriesMock.getInstance(), tagRepositoryMock.getInstance(), noteRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = page.centralListModel(); // THEN const QModelIndex note1Index = model->index(0, 0); const QModelIndex note2Index = model->index(1, 0); QCOMPARE(page.tag(), tag); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(note1Index), 0); QCOMPARE(model->rowCount(note2Index), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled; QCOMPARE(model->flags(note1Index), defaultFlags); QCOMPARE(model->flags(note2Index), defaultFlags); QCOMPARE(model->data(note1Index).toString(), note1->title()); QCOMPARE(model->data(note2Index).toString(), note2->title()); QCOMPARE(model->data(note1Index, Qt::EditRole).toString(), note1->title()); QCOMPARE(model->data(note2Index, Qt::EditRole).toString(), note2->title()); QVERIFY(!model->data(note1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(note2Index, Qt::CheckStateRole).isValid()); // WHEN noteRepositoryMock(&Domain::NoteRepository::update).when(note1).thenReturn(new FakeJob(this)); noteRepositoryMock(&Domain::NoteRepository::update).when(note2).thenReturn(new FakeJob(this)); QVERIFY(model->setData(note1Index, "newNote1")); QVERIFY(model->setData(note2Index, "newNote2")); QVERIFY(!model->setData(note1Index, Qt::Checked, Qt::CheckStateRole)); QVERIFY(!model->setData(note2Index, Qt::Checked, Qt::CheckStateRole)); // THEN QVERIFY(noteRepositoryMock(&Domain::NoteRepository::update).when(note1).exactly(1)); QVERIFY(noteRepositoryMock(&Domain::NoteRepository::update).when(note2).exactly(1)); QCOMPARE(note1->title(), QStringLiteral("newNote1")); QCOMPARE(note2->title(), QStringLiteral("newNote2")); // WHEN auto data = std::unique_ptr(model->mimeData(QModelIndexList() << note2Index)); // THEN QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); QCOMPARE(data->property("objects").value(), Domain::Artifact::List() << note2); } void shouldAddNotes() { // GIVEN // One Tag auto tag = Domain::Tag::Ptr::create(); // ... in fact we won't list any model Utils::MockObject tagQueriesMock; Utils::MockObject tagRepositoryMock; // We'll gladly create a note though Utils::MockObject noteRepositoryMock; noteRepositoryMock(&Domain::NoteRepository::createInTag).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::TagPageModel page(tag, tagQueriesMock.getInstance(), tagRepositoryMock.getInstance(), noteRepositoryMock.getInstance()); // WHEN auto title = QStringLiteral("New note"); auto note = page.addItem(title).objectCast(); // THEN QVERIFY(noteRepositoryMock(&Domain::NoteRepository::createInTag).when(any(), any()) .exactly(1)); QVERIFY(note); QCOMPARE(note->title(), title); } void shouldRemoveItem() { // GIVEN // One domain tag auto tag = Domain::Tag::Ptr::create(); // Two notes auto note1 = Domain::Note::Ptr::create(); auto note2 = Domain::Note::Ptr::create(); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findNotes).when(tag).thenReturn(noteResult); Utils::MockObject tagRepositoryMock; tagRepositoryMock(&Domain::TagRepository::dissociate).when(tag, note2).thenReturn(new FakeJob(this)); Utils::MockObject noteRepositoryMock; Presentation::TagPageModel page(tag, tagQueriesMock.getInstance(), tagRepositoryMock.getInstance(), noteRepositoryMock.getInstance()); // WHEN const QModelIndex indexNote2 = page.centralListModel()->index(1, 0); page.removeItem(indexNote2); // THEN QVERIFY(tagRepositoryMock(&Domain::TagRepository::dissociate).when(tag, note2).exactly(1)); } void shouldGetAnErrorMessageWhenRemoveItemFailed() { // GIVEN // One domain tag auto tag = Domain::Tag::Ptr::create(); tag->setName(QStringLiteral("Tag1")); // Two notes auto note1 = Domain::Note::Ptr::create(); note1->setTitle(QStringLiteral("Note 1")); auto note2 = Domain::Note::Ptr::create(); note2->setTitle(QStringLiteral("Note 2")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(note1); noteProvider->append(note2); Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findNotes).when(tag).thenReturn(noteResult); Utils::MockObject tagRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); tagRepositoryMock(&Domain::TagRepository::dissociate).when(tag, note2).thenReturn(job); Utils::MockObject noteRepositoryMock; Presentation::TagPageModel page(tag, tagQueriesMock.getInstance(), tagRepositoryMock.getInstance(), noteRepositoryMock.getInstance()); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN const QModelIndex indexNote2 = page.centralListModel()->index(1, 0); page.removeItem(indexNote2); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove note Note 2 from tag Tag1: Foo")); } void shouldGetAnErrorMessageWhenAddNoteFailed() { // GIVEN // One Tag auto tag = Domain::Tag::Ptr::create(); tag->setName(QStringLiteral("Tag1")); // ... in fact we won't list any model Utils::MockObject tagQueriesMock; Utils::MockObject tagRepositoryMock; // We'll gladly create a note though Utils::MockObject noteRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); noteRepositoryMock(&Domain::NoteRepository::createInTag).when(any(), any()) .thenReturn(job); Presentation::TagPageModel page(tag, tagQueriesMock.getInstance(), tagRepositoryMock.getInstance(), noteRepositoryMock.getInstance()); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN page.addItem(QStringLiteral("New note")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add note New note in tag Tag1: Foo")); } void shouldGetAnErrorMessageWhenUpdateNoteFailed() { // GIVEN // One Tag auto tag = Domain::Tag::Ptr::create(); tag->setName(QStringLiteral("Tag1")); // One note auto rootNote = Domain::Note::Ptr::create(); rootNote->setTitle(QStringLiteral("rootNote")); auto noteProvider = Domain::QueryResultProvider::Ptr::create(); auto noteResult = Domain::QueryResult::create(noteProvider); noteProvider->append(rootNote); Utils::MockObject tagQueriesMock; tagQueriesMock(&Domain::TagQueries::findNotes).when(tag).thenReturn(noteResult); Utils::MockObject noteRepositoryMock; Utils::MockObject tagRepositoryMock; Presentation::TagPageModel page(tag, tagQueriesMock.getInstance(), tagRepositoryMock.getInstance(), noteRepositoryMock.getInstance()); QAbstractItemModel *model = page.centralListModel(); const QModelIndex rootNoteIndex = model->index(0, 0); FakeErrorHandler errorHandler; page.setErrorHandler(&errorHandler); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); noteRepositoryMock(&Domain::NoteRepository::update).when(rootNote).thenReturn(job); QVERIFY(model->setData(rootNoteIndex, "newRootNote")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify note rootNote in tag Tag1: Foo")); } }; ZANSHIN_TEST_MAIN(TagPageModelTest) #include "tagpagemodeltest.moc" diff --git a/tests/units/presentation/taskinboxpagemodeltest.cpp b/tests/units/presentation/taskinboxpagemodeltest.cpp index 89db9cc5..a433a4ff 100644 --- a/tests/units/presentation/taskinboxpagemodeltest.cpp +++ b/tests/units/presentation/taskinboxpagemodeltest.cpp @@ -1,541 +1,541 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "utils/mockobject.h" #include "domain/taskqueries.h" #include "domain/taskrepository.h" #include "presentation/taskinboxpagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: - void doDisplayMessage(const QString &message) + void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; class TaskInboxPageModelTest : public QObject { Q_OBJECT private slots: void shouldListInboxInCentralListModel() { // GIVEN // One task auto rootTask = Domain::Task::Ptr::create(); rootTask->setTitle(QStringLiteral("rootTask")); auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); auto inboxResult = Domain::QueryResult::create(inboxProvider); inboxProvider->append(rootTask); // One task under the root task auto childTask = Domain::Task::Ptr::create(); childTask->setTitle(QStringLiteral("childTask")); childTask->setDone(true); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(childTask); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(rootTask).thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = inbox.centralListModel(); // THEN const QModelIndex rootTaskIndex = model->index(0, 0); const QModelIndex childTaskIndex = model->index(0, 0, rootTaskIndex); QCOMPARE(model->rowCount(), 1); QCOMPARE(model->rowCount(rootTaskIndex), 1); QCOMPARE(model->rowCount(childTaskIndex), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled; QCOMPARE(model->flags(rootTaskIndex), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(childTaskIndex), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); QCOMPARE(model->data(rootTaskIndex).toString(), rootTask->title()); QCOMPARE(model->data(childTaskIndex).toString(), childTask->title()); QCOMPARE(model->data(rootTaskIndex, Qt::EditRole).toString(), rootTask->title()); QCOMPARE(model->data(childTaskIndex, Qt::EditRole).toString(), childTask->title()); QVERIFY(model->data(rootTaskIndex, Qt::CheckStateRole).isValid()); QVERIFY(model->data(childTaskIndex, Qt::CheckStateRole).isValid()); QCOMPARE(model->data(rootTaskIndex, Qt::CheckStateRole).toBool(), rootTask->isDone()); QCOMPARE(model->data(childTaskIndex, Qt::CheckStateRole).toBool(), childTask->isDone()); // WHEN taskRepositoryMock(&Domain::TaskRepository::update).when(rootTask).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(childTask).thenReturn(new FakeJob(this)); QVERIFY(model->setData(rootTaskIndex, "newRootTask")); QVERIFY(model->setData(childTaskIndex, "newChildTask")); QVERIFY(model->setData(rootTaskIndex, Qt::Checked, Qt::CheckStateRole)); QVERIFY(model->setData(childTaskIndex, Qt::Unchecked, Qt::CheckStateRole)); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(rootTask).exactly(2)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask).exactly(2)); QCOMPARE(rootTask->title(), QStringLiteral("newRootTask")); QCOMPARE(childTask->title(), QStringLiteral("newChildTask")); QCOMPARE(rootTask->isDone(), true); QCOMPARE(childTask->isDone(), false); // WHEN auto data = std::unique_ptr(model->mimeData(QModelIndexList() << childTaskIndex)); // THEN QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); QCOMPARE(data->property("objects").value(), Domain::Artifact::List() << childTask); // WHEN auto childTask2 = Domain::Task::Ptr::create(); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask2).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, rootTaskIndex); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask2).exactly(1)); // WHEN auto childTask3 = Domain::Task::Ptr::create(); auto childTask4 = Domain::Task::Ptr::create(); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask3).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask3 << childTask4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, rootTaskIndex); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask3).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).exactly(1)); } void shouldAddTasksInInbox() { // GIVEN // ... in fact we won't list any model Utils::MockObject taskQueriesMock; // We'll gladly create a task though Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::create).when(any()).thenReturn(new FakeJob(this)); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN auto title = QStringLiteral("New task"); auto task = inbox.addItem(title).objectCast(); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::create).when(any()).exactly(1)); QVERIFY(task); QCOMPARE(task->title(), title); } void shouldAddChildTask() { // GIVEN // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task1); taskProvider->append(task2); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const auto title = QStringLiteral("New task"); const auto parentIndex = inbox.centralListModel()->index(0, 0); const auto createdTask = inbox.addItem(title, parentIndex).objectCast(); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), any()) .exactly(1)); QVERIFY(createdTask); QCOMPARE(createdTask->title(), title); } void shouldGetAnErrorMessageWhenAddTaskFailed() { // GIVEN // ... in fact we won't list any model Utils::MockObject taskQueriesMock; // We'll gladly create a task though Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::create).when(any()).thenReturn(job); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN inbox.addItem(QStringLiteral("New task")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add task New task in Inbox: Foo")); } void shouldDeleteItems() { // GIVEN // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task1); taskProvider->append(task2); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).thenReturn(new FakeJob(this)); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const QModelIndex index = inbox.centralListModel()->index(1, 0); inbox.removeItem(index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).exactly(1)); } void shouldGetAnErrorMessageWhenDeleteItemsFailed() { // GIVEN // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); task2->setTitle(QStringLiteral("task2")); auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); auto inboxResult = Domain::QueryResult::create(inboxProvider); inboxProvider->append(task1); inboxProvider->append(task2); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).thenReturn(job); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN const QModelIndex index = inbox.centralListModel()->index(1, 0); inbox.removeItem(index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove task task2 from Inbox: Foo")); } void shouldPromoteItem() { // GIVEN // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(task1); taskProvider->append(task2); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this)); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); // WHEN const QModelIndex index = inbox.centralListModel()->index(1, 0); inbox.promoteItem(index); // THEN QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1)); } void shouldGetAnErrorMessageWhenPromoteItemFailed() { // GIVEN // Two tasks auto task1 = Domain::Task::Ptr::create(); auto task2 = Domain::Task::Ptr::create(); task2->setTitle(QStringLiteral("task2")); auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); auto inboxResult = Domain::QueryResult::create(inboxProvider); inboxProvider->append(task1); inboxProvider->append(task2); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(job); Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN const QModelIndex index = inbox.centralListModel()->index(1, 0); inbox.promoteItem(index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot promote task task2 to be a project: Foo")); } void shouldGetAnErrorMessageWhenUpdateTaskFailed() { // GIVEN // One task auto rootTask = Domain::Task::Ptr::create(); rootTask->setTitle(QStringLiteral("rootTask")); auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); auto inboxResult = Domain::QueryResult::create(inboxProvider); inboxProvider->append(rootTask); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(rootTask).thenReturn(taskResult); Utils::MockObject taskRepositoryMock; Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); QAbstractItemModel *model = inbox.centralListModel(); const QModelIndex rootTaskIndex = model->index(0, 0); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::update).when(rootTask).thenReturn(job); QVERIFY(model->setData(rootTaskIndex, "newRootTask")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify task rootTask in Inbox: Foo")); } void shouldGetAnErrorMessageWhenAssociateTaskFailed() { // GIVEN // One task auto rootTask = Domain::Task::Ptr::create(); rootTask->setTitle(QStringLiteral("rootTask")); auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); auto inboxResult = Domain::QueryResult::create(inboxProvider); inboxProvider->append(rootTask); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(rootTask).thenReturn(taskResult); Utils::MockObject taskRepositoryMock; Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); QAbstractItemModel *model = inbox.centralListModel(); const QModelIndex rootTaskIndex = model->index(0, 0); FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN auto childTask3 = Domain::Task::Ptr::create(); childTask3->setTitle(QStringLiteral("childTask3")); auto childTask4 = Domain::Task::Ptr::create(); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask3).thenReturn(job); taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask3 << childTask4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, rootTaskIndex); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move task childTask3 as sub-task of rootTask: Foo")); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(rootTask, childTask4).exactly(1)); } void shouldDeparentWhenNoErrorHappens() { // GIVEN // One task, top level auto topLevelTask = Domain::Task::Ptr::create(); topLevelTask->setTitle(QStringLiteral("topLevelTask")); auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); auto inboxResult = Domain::QueryResult::create(inboxProvider); inboxProvider->append(topLevelTask); // Two tasks under the top level task auto childTask = Domain::Task::Ptr::create(); childTask->setTitle(QStringLiteral("childTask")); childTask->setDone(true); auto childTask2 = Domain::Task::Ptr::create(); childTask2->setTitle(QStringLiteral("childTask2")); childTask2->setDone(false); auto taskProvider = Domain::QueryResultProvider::Ptr::create(); auto taskResult = Domain::QueryResult::create(taskProvider); taskProvider->append(childTask); taskProvider->append(childTask2); Utils::MockObject taskQueriesMock; taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(topLevelTask).thenReturn(taskResult); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask).thenReturn(Domain::QueryResult::Ptr()); taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask2).thenReturn(Domain::QueryResult::Ptr()); Utils::MockObject taskRepositoryMock; Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), taskRepositoryMock.getInstance()); QAbstractItemModel *model = inbox.centralListModel(); const QModelIndex emptyPartModel = QModelIndex(); // model root, drop on the empty part is equivalent FakeErrorHandler errorHandler; inbox.setErrorHandler(&errorHandler); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask).thenReturn(job); taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask2).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Artifact::List() << childTask << childTask2)); // both will be DnD on the empty part model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, emptyPartModel); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot deparent task childTask from its parent: Foo")); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask2).exactly(1)); } }; ZANSHIN_TEST_MAIN(TaskInboxPageModelTest) #include "taskinboxpagemodeltest.moc" diff --git a/tests/units/utils/dependencymanagertest.cpp b/tests/units/utils/dependencymanagertest.cpp index ef1a3237..39bfb4cf 100644 --- a/tests/units/utils/dependencymanagertest.cpp +++ b/tests/units/utils/dependencymanagertest.cpp @@ -1,367 +1,367 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "utils/dependencymanager.h" using namespace Utils; class Interface0 { public: typedef QSharedPointer Ptr; Interface0() {} virtual ~Interface0() {} virtual void doSomething() = 0; }; class FirstImplementation0 : public Interface0 { public: - virtual void doSomething() { qDebug() << "FirstImplementation"; } + void doSomething() override { qDebug() << "FirstImplementation"; } }; class SecondImplementation0 : public Interface0 { public: - virtual void doSomething() { qDebug() << "SecondImplementation"; } + void doSomething() override { qDebug() << "SecondImplementation"; } }; #define DECLARE_IMPLEMENTED_INTERFACE(N) \ class Interface##N \ { \ public: \ typedef QSharedPointer Ptr; \ \ Interface##N() {} \ virtual ~Interface##N() {} \ virtual void doSomething() = 0; \ }; \ \ class Implementation##N : public Interface##N \ { \ public: \ - virtual void doSomething() { qDebug() << "Implementation##N"; } \ + void doSomething() override { qDebug() << "Implementation##N"; } \ }; DECLARE_IMPLEMENTED_INTERFACE(1) DECLARE_IMPLEMENTED_INTERFACE(2) DECLARE_IMPLEMENTED_INTERFACE(3) DECLARE_IMPLEMENTED_INTERFACE(4) DECLARE_IMPLEMENTED_INTERFACE(5) DECLARE_IMPLEMENTED_INTERFACE(6) DECLARE_IMPLEMENTED_INTERFACE(7) DECLARE_IMPLEMENTED_INTERFACE(8) DECLARE_IMPLEMENTED_INTERFACE(9) DECLARE_IMPLEMENTED_INTERFACE(10) DECLARE_IMPLEMENTED_INTERFACE(11) DECLARE_IMPLEMENTED_INTERFACE(12) DECLARE_IMPLEMENTED_INTERFACE(13) DECLARE_IMPLEMENTED_INTERFACE(14) class AnotherInterface { public: AnotherInterface() {} virtual ~AnotherInterface() {} virtual void doSomethingDelegated() = 0; }; class AnotherFirstImplementation : public AnotherInterface { public: explicit AnotherFirstImplementation(const Interface0::Ptr &iface) : m_iface(iface) {} void doSomethingDelegated() Q_DECL_OVERRIDE { m_iface->doSomething(); } Interface0::Ptr iface() const { return m_iface; } private: Interface0::Ptr m_iface; }; class AnotherSecondImplementation : public AnotherInterface { public: AnotherSecondImplementation(Interface0::Ptr iface0, Interface1::Ptr iface1, Interface2::Ptr iface2, Interface3::Ptr iface3, Interface4::Ptr iface4, Interface5::Ptr iface5, Interface6::Ptr iface6, Interface7::Ptr iface7, Interface8::Ptr iface8, Interface9::Ptr iface9, Interface10::Ptr iface10, Interface11::Ptr iface11, Interface12::Ptr iface12, Interface13::Ptr iface13, Interface14::Ptr iface14) : m_iface0(iface0), m_iface1(iface1), m_iface2(iface2), m_iface3(iface3), m_iface4(iface4), m_iface5(iface5), m_iface6(iface6), m_iface7(iface7), m_iface8(iface8), m_iface9(iface9), m_iface10(iface10), m_iface11(iface11), m_iface12(iface12), m_iface13(iface13), m_iface14(iface14) { } void doSomethingDelegated() Q_DECL_OVERRIDE { m_iface1->doSomething(); } Interface0::Ptr iface0() const { return m_iface0; } Interface1::Ptr iface1() const { return m_iface1; } Interface2::Ptr iface2() const { return m_iface2; } Interface3::Ptr iface3() const { return m_iface3; } Interface4::Ptr iface4() const { return m_iface4; } Interface5::Ptr iface5() const { return m_iface5; } Interface6::Ptr iface6() const { return m_iface6; } Interface7::Ptr iface7() const { return m_iface7; } Interface8::Ptr iface8() const { return m_iface8; } Interface9::Ptr iface9() const { return m_iface9; } Interface10::Ptr iface10() const { return m_iface10; } Interface11::Ptr iface11() const { return m_iface11; } Interface12::Ptr iface12() const { return m_iface12; } Interface13::Ptr iface13() const { return m_iface13; } Interface14::Ptr iface14() const { return m_iface14; } private: Interface0::Ptr m_iface0; Interface1::Ptr m_iface1; Interface2::Ptr m_iface2; Interface3::Ptr m_iface3; Interface4::Ptr m_iface4; Interface5::Ptr m_iface5; Interface6::Ptr m_iface6; Interface7::Ptr m_iface7; Interface8::Ptr m_iface8; Interface9::Ptr m_iface9; Interface10::Ptr m_iface10; Interface11::Ptr m_iface11; Interface12::Ptr m_iface12; Interface13::Ptr m_iface13; Interface14::Ptr m_iface14; }; class DependencyManagerTest : public QObject { Q_OBJECT private: static bool s_firstImplFactoryCalled; static DependencyManager *s_manager; static Interface0 *firstImplFactory(DependencyManager *manager) { s_firstImplFactoryCalled = true; s_manager = manager; return new FirstImplementation0; } private slots: void shouldMemorizeDependency() { DependencyManager deps; deps.add(); auto object1 = deps.create(); QVERIFY(object1.dynamicCast()); auto object2 = deps.create(); QVERIFY(object2.dynamicCast()); QVERIFY(object1 != object2); } void shouldAllowOurOwnFactory() { s_firstImplFactoryCalled = false; s_manager = Q_NULLPTR; DependencyManager deps; deps.add(&DependencyManagerTest::firstImplFactory); auto object = deps.create(); QVERIFY(object.dynamicCast()); QVERIFY(s_firstImplFactoryCalled); QVERIFY(s_manager == &deps); } void shouldAllowUniqueInstances() { DependencyManager deps; deps.add(); auto object1 = deps.create(); QVERIFY(object1.dynamicCast()); auto object2 = deps.create(); QVERIFY(object2.dynamicCast()); QVERIFY(object1 == object2); } void shouldAllowUniqueInstancesWithOurOwnFactory() { s_firstImplFactoryCalled = false; s_manager = Q_NULLPTR; DependencyManager deps; deps.add(&DependencyManagerTest::firstImplFactory); auto object1 = deps.create(); QVERIFY(object1.dynamicCast()); auto object2 = deps.create(); QVERIFY(object2.dynamicCast()); QVERIFY(s_firstImplFactoryCalled); QVERIFY(s_manager == &deps); QVERIFY(object1 == object2); } void shouldAllowOurOwnFactoryAsLambda() { #ifdef Q_COMPILER_LAMBDA bool ownFactoryCalled = false; DependencyManager *managerCalled = Q_NULLPTR; DependencyManager deps; deps.add([&](DependencyManager *manager) -> Interface0* { ownFactoryCalled = true; managerCalled = manager; return new FirstImplementation0; }); auto object = deps.create(); QVERIFY(object.dynamicCast()); QVERIFY(ownFactoryCalled); QVERIFY(managerCalled == &deps); #endif } void shouldMakeManagerSpecificDependencies() { DependencyManager deps1; deps1.add(); DependencyManager deps2; deps2.add(); auto object1 = deps1.create(); auto object2 = deps2.create(); QVERIFY(object1.dynamicCast()); QVERIFY(object2.dynamicCast()); } void shouldCleanupProviders() { QCOMPARE(Internal::Supplier::providersCount(), 0); { DependencyManager deps1; deps1.add(); QCOMPARE(Internal::Supplier::providersCount(), 1); { DependencyManager deps2; deps2.add(); QCOMPARE(Internal::Supplier::providersCount(), 2); } QCOMPARE(Internal::Supplier::providersCount(), 1); } QCOMPARE(Internal::Supplier::providersCount(), 0); } void shouldInjectDependencyInConstructor() { DependencyManager deps; deps.add(); deps.add(); auto object = deps.create(); auto impl = object.dynamicCast(); QVERIFY(impl != Q_NULLPTR); QVERIFY(impl->iface().dynamicCast()); } void shouldInjectDependenciesInConstructor() { DependencyManager deps; deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); auto object = deps.create(); auto impl = object.dynamicCast(); QVERIFY(impl != Q_NULLPTR); QVERIFY(impl->iface0().dynamicCast()); QVERIFY(impl->iface1().dynamicCast()); QVERIFY(impl->iface2().dynamicCast()); QVERIFY(impl->iface3().dynamicCast()); QVERIFY(impl->iface4().dynamicCast()); QVERIFY(impl->iface5().dynamicCast()); QVERIFY(impl->iface6().dynamicCast()); QVERIFY(impl->iface7().dynamicCast()); QVERIFY(impl->iface8().dynamicCast()); QVERIFY(impl->iface9().dynamicCast()); QVERIFY(impl->iface10().dynamicCast()); QVERIFY(impl->iface11().dynamicCast()); QVERIFY(impl->iface12().dynamicCast()); QVERIFY(impl->iface13().dynamicCast()); QVERIFY(impl->iface14().dynamicCast()); } }; bool DependencyManagerTest::s_firstImplFactoryCalled = false; DependencyManager *DependencyManagerTest::s_manager = Q_NULLPTR; ZANSHIN_TEST_MAIN(DependencyManagerTest) #include "dependencymanagertest.moc" diff --git a/tests/units/widgets/applicationcomponentstest.cpp b/tests/units/widgets/applicationcomponentstest.cpp index cca8dce8..390111a9 100644 --- a/tests/units/widgets/applicationcomponentstest.cpp +++ b/tests/units/widgets/applicationcomponentstest.cpp @@ -1,688 +1,688 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "utils/mem_fn.h" #include "domain/note.h" #include "domain/task.h" #include "presentation/artifactfilterproxymodel.h" #include "presentation/querytreemodelbase.h" #include "widgets/applicationcomponents.h" #include "widgets/availablepagesview.h" #include "widgets/availablesourcesview.h" #include "widgets/editorview.h" #include "widgets/filterwidget.h" #include "widgets/pageview.h" #include "widgets/pageviewerrorhandler.h" #include "widgets/quickselectdialog.h" class CustomModelStub : public QStandardItemModel { Q_OBJECT - QMimeData *mimeData(const QModelIndexList &indexes) const + QMimeData *mimeData(const QModelIndexList &indexes) const override { QStringList dataString; std::transform(indexes.begin(), indexes.end(), std::back_inserter(dataString), [] (const QModelIndex &index) { return index.data().toString(); }); auto data = new QMimeData; data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(dataString)); return data; } - bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &destination) + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &destination) override { Q_UNUSED(action); Q_ASSERT(row == -1); Q_ASSERT(column == -1); Q_ASSERT(destination.isValid()); Q_ASSERT(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); auto dataString = data->property("objects").toStringList(); Q_ASSERT(!dataString.isEmpty()); droppedItemDataString = dataString; dropDestination = destination.data().toString(); return true; } public: QStringList droppedItemDataString; QString dropDestination; }; class ApplicationModelStub : public QObject { Q_OBJECT Q_PROPERTY(QObject* currentPage READ currentPage WRITE setCurrentPage) public: typedef QSharedPointer Ptr; explicit ApplicationModelStub(QObject *parent = Q_NULLPTR) : QObject(parent), m_currentPage(Q_NULLPTR) {} QObject *currentPage() { return m_currentPage; } void setCurrentPage(QObject *page) { if (page == m_currentPage) return; m_currentPage = page; emit currentPageChanged(m_currentPage); } signals: void currentPageChanged(QObject *page); private: QObject *m_currentPage; }; class AvailablePagesModelStub : public QObject { Q_OBJECT Q_PROPERTY(QAbstractItemModel* pageListModel READ pageListModel) public: explicit AvailablePagesModelStub(QObject *parent = Q_NULLPTR) : QObject(parent) { QStandardItem *inbox = new QStandardItem; inbox->setData("Inbox", Qt::DisplayRole); itemModel.appendRow(inbox); QStandardItem *project = new QStandardItem; project->setData("Project", Qt::DisplayRole); itemModel.appendRow(project); } QAbstractItemModel *pageListModel() { return &itemModel; } Q_SCRIPTABLE QObject *createPageForIndex(const QModelIndex &index) { auto page = new QObject(this); auto model = new QStringListModel(page); model->setStringList(QStringList() << QStringLiteral("Items") << QStringLiteral("from") << index.data().toString()); page->setProperty("centralListModel", QVariant::fromValue(model)); createdPages << page; return page; } public: QList createdPages; CustomModelStub itemModel; }; class PageModelStub : public QObject { Q_OBJECT Q_PROPERTY(QAbstractItemModel* centralListModel READ centralListModel) public: QAbstractItemModel *centralListModel() { return &itemModel; } template void addItem(const QString &title) { auto artifact = T::Ptr::create(); artifact->setTitle(title); addItem(artifact); } void addItem(const Domain::Artifact::Ptr &artifact) { QStandardItem *item = new QStandardItem; item->setData(QVariant::fromValue(artifact), Presentation::QueryTreeModelBase::ObjectRole); item->setData(artifact->title(), Qt::DisplayRole); itemModel.appendRow(item); } Domain::Artifact::Ptr itemAtRow(int row) const { return itemModel.index(row, 0).data(Presentation::QueryTreeModelBase::ObjectRole) .value(); } QModelIndexList selectedIndexes() const { return selectedItems; } public: QModelIndexList selectedItems; CustomModelStub itemModel; }; class EditorModelStub : public QObject { Q_OBJECT public: explicit EditorModelStub(QObject *parent = Q_NULLPTR) : QObject(parent) { } void setPropertyAndSignal(const QByteArray &name, const QVariant &value) { if (property(name) == value) return; setProperty(name, value); if (name == "text") emit textChanged(value.toString()); else if (name == "title") emit titleChanged(value.toString()); else if (name == "done") emit doneChanged(value.toBool()); else if (name == "startDate") emit startDateChanged(value.toDateTime()); else if (name == "dueDate") emit dueDateChanged(value.toDateTime()); else if (name == "hasTaskProperties") emit hasTaskPropertiesChanged(value.toBool()); else qFatal("Unsupported property %s", name.constData()); } public slots: void setTitle(const QString &title) { setPropertyAndSignal("title", title); } void setText(const QString &text) { setPropertyAndSignal("text", text); } void setDone(bool done) { setPropertyAndSignal("done", done); } void setStartDate(const QDateTime &start) { setPropertyAndSignal("startDate", start); } void setDueDate(const QDateTime &due) { setPropertyAndSignal("dueDate", due); } signals: void hasTaskPropertiesChanged(bool hasTaskProperties); void textChanged(const QString &text); void titleChanged(const QString &title); void doneChanged(bool done); void startDateChanged(const QDateTime &date); void dueDateChanged(const QDateTime &due); }; class QuickSelectDialogStub : public Widgets::QuickSelectDialogInterface { public: typedef QSharedPointer Ptr; explicit QuickSelectDialogStub() : parent(Q_NULLPTR), execCount(0), itemModel(Q_NULLPTR) { } int exec() Q_DECL_OVERRIDE { execCount++; return QDialog::Accepted; } void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE { itemModel = model; } QPersistentModelIndex selectedIndex() const Q_DECL_OVERRIDE { return index; } QWidget *parent; int execCount; QAbstractItemModel *itemModel; QPersistentModelIndex index; }; class ApplicationComponentsTest : public QObject { Q_OBJECT public: explicit ApplicationComponentsTest(QObject *parent = Q_NULLPTR) : QObject(parent) { qputenv("ZANSHIN_UNIT_TEST_RUN", "1"); } private slots: void shouldHaveApplicationModelAndSetErrorHandler() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); // WHEN components.setModel(model); // THEN QCOMPARE(components.model(), model); auto errorHandlerBase = model->property("errorHandler").value(); QVERIFY(errorHandlerBase); auto errorHandler = static_cast(errorHandlerBase); QVERIFY(errorHandler); QVERIFY(!errorHandler->pageView()); // WHEN auto pageView = components.pageView(); // THEN QCOMPARE(errorHandler->pageView(), pageView); } void shouldApplyAvailableSourcesModelToAvailableSourcesView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject availableSources; model->setProperty("availableSources", QVariant::fromValue(&availableSources)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availableSourcesView()->model(), &availableSources); } void shouldApplyAvailableSourcesModelAlsoToCreatedAvailableSourcesView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.availableSourcesView(); auto model = QObjectPtr::create(); QObject availableSources; model->setProperty("availableSources", QVariant::fromValue(&availableSources)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availableSourcesView()->model(), &availableSources); } void shouldApplyAvailablePagesModelToAvailablePagesView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject availablePages; model->setProperty("availablePages", QVariant::fromValue(&availablePages)); QObject availableSources; QAbstractItemModel *sourcesModel = new QStandardItemModel(model.data()); availableSources.setProperty("sourceListModel", QVariant::fromValue(sourcesModel)); model->setProperty("availableSources", QVariant::fromValue(&availableSources)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availablePagesView()->model(), &availablePages); QCOMPARE(components.availablePagesView()->projectSourcesModel(), sourcesModel); } void shouldApplyAvailablePagesModelAlsoToCreatedAvailablePagesView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.availablePagesView(); auto model = QObjectPtr::create(); QObject availablePages; QAbstractItemModel *sourcesModel = new QStandardItemModel(model.data()); model->setProperty("dataSourcesModel", QVariant::fromValue(sourcesModel)); model->setProperty("availablePages", QVariant::fromValue(&availablePages)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availablePagesView()->model(), &availablePages); QCOMPARE(components.availablePagesView()->projectSourcesModel(), sourcesModel); } void shouldApplyCurrentPageModelToPageView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject currentPage; model->setProperty("currentPage", QVariant::fromValue(¤tPage)); // WHEN components.setModel(model); // THEN QCOMPARE(components.pageView()->model(), ¤tPage); } void shouldApplyCurrentPageModelAlsoToCreatedPageView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.pageView(); auto model = QObjectPtr::create(); QObject currentPage; model->setProperty("currentPage", QVariant::fromValue(¤tPage)); // WHEN components.setModel(model); // THEN QCOMPARE(components.pageView()->model(), ¤tPage); } void shouldApplyEditorModelToEditorView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject *editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); // WHEN components.setModel(model); // THEN QCOMPARE(components.editorView()->model(), editorModel); } void shouldApplyEditorModelAltoToCreatedPageView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.editorView(); auto model = QObjectPtr::create(); QObject *editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); // WHEN components.setModel(model); // THEN QCOMPARE(components.editorView()->model(), editorModel); } void shouldPropageNullModelsToViews() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); auto availableSources = new QObject(model.data()); model->setProperty("availableSources", QVariant::fromValue(availableSources)); auto availablePages = new QObject(model.data()); model->setProperty("availablePages", QVariant::fromValue(availablePages)); auto currentPage = new QObject(model.data()); model->setProperty("currentPage", QVariant::fromValue(currentPage)); auto editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); components.setModel(model); // WHEN components.setModel(QObjectPtr()); components.availableSourcesView(); components.availablePagesView(); components.pageView(); components.editorView(); // THEN QVERIFY(!components.availableSourcesView()->model()); QVERIFY(!components.availablePagesView()->model()); QVERIFY(!components.pageView()->model()); QVERIFY(!components.editorView()->model()); } void shouldPropageNullModelsToCreatedViews() { // GIVEN Widgets::ApplicationComponents components; components.availableSourcesView(); components.availablePagesView(); components.pageView(); components.editorView(); auto model = QObjectPtr::create(); auto availableSources = new QObject(model.data()); model->setProperty("availableSources", QVariant::fromValue(availableSources)); auto availablePages = new QObject(model.data()); model->setProperty("availablePages", QVariant::fromValue(availablePages)); auto currentPage = new QObject(model.data()); model->setProperty("currentPage", QVariant::fromValue(currentPage)); auto editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); components.setModel(model); // WHEN components.setModel(QObjectPtr()); // THEN QVERIFY(!components.availableSourcesView()->model()); QVERIFY(!components.availablePagesView()->model()); QVERIFY(!components.pageView()->model()); QVERIFY(!components.editorView()->model()); } void shouldApplyAvailablePagesSelectionToApplicationModel() { // GIVEN auto model = ApplicationModelStub::Ptr::create(); AvailablePagesModelStub availablePagesModel; model->setProperty("availablePages", QVariant::fromValue(&availablePagesModel)); model->setProperty("currentPage", QVariant::fromValue(Q_NULLPTR)); QObject editorModel; editorModel.setProperty("artifact", QVariant::fromValue(Domain::Task::Ptr::create())); model->setProperty("editor", QVariant::fromValue(&editorModel)); Widgets::ApplicationComponents components; components.setModel(model); Widgets::AvailablePagesView *availablePagesView = components.availablePagesView(); auto pagesView = availablePagesView->findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); Widgets::PageView *pageView = components.pageView(); QVERIFY(pageView); QVERIFY(!pageView->model()); QModelIndex index = pagesView->model()->index(0, 0); // WHEN pagesView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); // THEN QCOMPARE(availablePagesModel.createdPages.size(), 1); QCOMPARE(model->property("currentPage").value(), availablePagesModel.createdPages.first()); QCOMPARE(pageView->model(), availablePagesModel.createdPages.first()); QVERIFY(editorModel.property("artifact").value().isNull()); } void shouldApplyPageViewSelectionToEditorModel() { // GIVEN auto model = QObjectPtr::create(); PageModelStub pageModel; pageModel.addItem(QStringLiteral("0. First task")); pageModel.addItem(QStringLiteral("1. A note")); pageModel.addItem(QStringLiteral("2. Second task")); pageModel.addItem(QStringLiteral("3. Another note")); model->setProperty("currentPage", QVariant::fromValue(&pageModel)); EditorModelStub editorModel; model->setProperty("editor", QVariant::fromValue(&editorModel)); Widgets::ApplicationComponents components; components.setModel(model); Widgets::PageView *pageView = components.pageView(); auto centralView = pageView->findChild(QStringLiteral("centralView")); QModelIndex index = centralView->model()->index(2, 0); // WHEN centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); // THEN QCOMPARE(editorModel.property("artifact").value(), pageModel.itemAtRow(index.row())); } void shouldHaveDefaultActionsList() { // GIVEN Widgets::ApplicationComponents components; // WHEN auto actions = components.globalActions(); // THEN // availablePages view auto available = components.availablePagesView(); foreach (const auto &key, available->globalActions().keys()) QCOMPARE(actions.value(key), available->globalActions().value(key)); // availableSources view auto availableSources = components.availableSourcesView(); foreach (const auto &key, availableSources->globalActions().keys()) QCOMPARE(actions.value(key), availableSources->globalActions().value(key)); // page view auto page = components.pageView(); foreach (const auto &key, page->globalActions().keys()) QCOMPARE(actions.value(key), page->globalActions().value(key)); // application component own action auto moveAction = components.findChild(QStringLiteral("moveItemAction")); QCOMPARE(actions.value(QStringLiteral("page_view_move")), moveAction); } void shouldMoveItem() { // GIVEN auto model = QObjectPtr::create(); PageModelStub pageModel; pageModel.addItem(QStringLiteral("0. First task")); pageModel.addItem(QStringLiteral("1. A note")); pageModel.addItem(QStringLiteral("2. Second task")); pageModel.addItem(QStringLiteral("3. Another note")); model->setProperty("currentPage", QVariant::fromValue(&pageModel)); AvailablePagesModelStub availablePagesModelStub; model->setProperty("availablePages", QVariant::fromValue(&availablePagesModelStub)); QWidget *mainWidget = new QWidget; Widgets::ApplicationComponents components(mainWidget); components.setModel(model); auto availablePageView = components.availablePagesView(); auto availablePagesTreeView = availablePageView->findChild(QStringLiteral("pagesView")); Q_ASSERT(availablePagesTreeView); auto dialogStub = QuickSelectDialogStub::Ptr::create(); dialogStub->index = availablePagesModelStub.pageListModel()->index(0, 0); // inbox selected components.setQuickSelectDialogFactory([dialogStub] (QWidget *parent) { dialogStub->parent = parent; return dialogStub; }); auto pageView = components.pageView(); auto centralView = pageView->findChild(QStringLiteral("centralView")); QModelIndex index1 = pageModel.itemModel.index(0,0); QModelIndex index2 = pageModel.itemModel.index(2,0); auto filterWidget = pageView->findChild(QStringLiteral("filterWidget")); auto displayedModel = filterWidget->proxyModel(); auto displayedIndex = displayedModel->index(0, 0); auto displayedIndex2 = displayedModel->index(2, 0); auto moveAction = components.findChild(QStringLiteral("moveItemAction")); // WHEN pageModel.selectedItems << index1 << index2; centralView->selectionModel()->setCurrentIndex(displayedIndex, QItemSelectionModel::ClearAndSelect); centralView->selectionModel()->setCurrentIndex(displayedIndex2, QItemSelectionModel::Select); moveAction->trigger(); // THEN QCOMPARE(dialogStub->execCount, 1); QCOMPARE(dialogStub->parent, pageView); QCOMPARE(dialogStub->itemModel, availablePagesModelStub.pageListModel()); QCOMPARE(availablePagesModelStub.itemModel.dropDestination, QStringLiteral("Inbox")); QCOMPARE(availablePagesModelStub.itemModel.droppedItemDataString.size(), 2); QCOMPARE(availablePagesModelStub.itemModel.droppedItemDataString.at(0), index1.data().toString()); QCOMPARE(availablePagesModelStub.itemModel.droppedItemDataString.at(1), index2.data().toString()); } }; ZANSHIN_TEST_MAIN(ApplicationComponentsTest) #include "applicationcomponentstest.moc"