From 387900ee391748c321ca761424abf8d716a2d731 Mon Sep 17 00:00:00 2001 From: Colin Duquesnoy Date: Thu, 20 Jul 2017 14:19:35 +0200 Subject: [PATCH] #48 Finish binding View and ViewModels + UnitTests --- .../Converters/UpdaterStatusConverter.cpp | 8 +- .../Converters/UpdaterStatusConverter.hpp | 2 +- .../ViewModels/UpdaterViewModel.cpp | 73 +++++++++++----- .../ViewModels/UpdaterViewModel.hpp | 18 ++-- .../MellowPlayer/Controls/MainToolBar.qml | 3 +- .../MellowPlayer/Controls/UpdateToolBar.qml | 3 +- .../Converters/UpdateStatusConverterTests.cpp | 18 +++- .../ViewModels/UpdaterViewModelTests.cpp | 84 +++++++++++++++++++ 8 files changed, 172 insertions(+), 37 deletions(-) create mode 100644 tests/UnitTests/Presentation/ViewModels/UpdaterViewModelTests.cpp diff --git a/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.cpp b/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.cpp index 3201870c..9f1c4f91 100644 --- a/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.cpp +++ b/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.cpp @@ -2,12 +2,12 @@ #include "UpdaterStatusConverter.hpp" using namespace MellowPlayer::Application; -using namespace MellowPlayer::Infrastructure; +using namespace MellowPlayer::Presentation; const QString UpdaterStatusConverter::NONE = ""; -const QString UpdaterStatusConverter::CHECKING = QObject::tr("Checking for update"); -const QString UpdaterStatusConverter::DOWNLOADING = QObject::tr("Downloading update"); -const QString UpdaterStatusConverter::INSTALLING = QObject::tr("Installing update"); +const QString UpdaterStatusConverter::CHECKING = "Checking for update"; +const QString UpdaterStatusConverter::DOWNLOADING = "Downloading update"; +const QString UpdaterStatusConverter::INSTALLING = "Installing update"; QString UpdaterStatusConverter::toString(Updater::Status status) { static QMap map = { diff --git a/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.hpp b/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.hpp index 5d18e8ea..e14545af 100644 --- a/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.hpp +++ b/lib/MellowPlayer/Presentation/Converters/UpdaterStatusConverter.hpp @@ -2,7 +2,7 @@ #include -namespace MellowPlayer::Infrastructure { +namespace MellowPlayer::Presentation { class UpdaterStatusConverter { public: diff --git a/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.cpp b/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.cpp index 98fd7165..af26342f 100644 --- a/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.cpp +++ b/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.cpp @@ -1,27 +1,37 @@ +#include #include "UpdaterViewModel.hpp" using namespace MellowPlayer::Application; using namespace MellowPlayer::Presentation; -UpdaterViewModel::UpdaterViewModel(Updater& updater): updater_(updater) { +UpdaterViewModel::UpdaterViewModel(Updater& updater): updater_(updater) +{ connect(&updater, &Updater::updateAvailable, this, &UpdaterViewModel::onUpdateAvailable); connect(&updater, &Updater::noUpdateAvailable, this, &UpdaterViewModel::onNoUpdateAvailable); + connect(&updater, &Updater::statusChanged, this, &UpdaterViewModel::statusChanged); + connect(&updater, &Updater::statusChanged, this, &UpdaterViewModel::busyChanged); + emit statusChanged(); + emit busyChanged(); } -QString UpdaterViewModel::getMessage() const { +QString UpdaterViewModel::getMessage() const +{ return message_; } -bool UpdaterViewModel::isVisible() const { +bool UpdaterViewModel::isVisible() const +{ return visible_; } -bool UpdaterViewModel::canInstall() const { - return canInstall_; +bool UpdaterViewModel::isInstallEnabled() const +{ + return installEnabled_; } -int UpdaterViewModel::getProgress() const { +int UpdaterViewModel::getProgress() const +{ return progress_; } @@ -30,24 +40,29 @@ bool UpdaterViewModel::isProgressVisible() const return progressVisible_; } -void UpdaterViewModel::close() { +void UpdaterViewModel::close() +{ setVisible(false); } -void UpdaterViewModel::check() { +void UpdaterViewModel::check() +{ setProgressVisible(true); setProgress(-1); updater_.check(); } -void UpdaterViewModel::install() { +void UpdaterViewModel::install() +{ setMessage("Downloading update..."); + setInstallEnabled(false); setProgressVisible(true); setProgress(-1); updater_.install(); } -void UpdaterViewModel::setVisible(bool visible) { +void UpdaterViewModel::setVisible(bool visible) +{ if (visible_ == visible) return; @@ -55,15 +70,17 @@ void UpdaterViewModel::setVisible(bool visible) { emit visibleChanged(); } -void UpdaterViewModel::setCanInstall(bool canInstall) { - if (canInstall_ == canInstall) +void UpdaterViewModel::setInstallEnabled(bool enabled) +{ + if (installEnabled_ == enabled) return; - canInstall_ = canInstall; - emit canInstallChanged(); + installEnabled_ = enabled; + emit installEnabledChanged(); } -void UpdaterViewModel::setProgress(int progress) { +void UpdaterViewModel::setProgress(int progress) +{ if (progress_ == progress) return; @@ -80,8 +97,9 @@ void UpdaterViewModel::setProgressVisible(bool progressVisible) emit progressVisibleChanged(); } -void UpdaterViewModel::onUpdateAvailable() { - setCanInstall(updater_.canInstall()); +void UpdaterViewModel::onUpdateAvailable() +{ + setInstallEnabled(updater_.canInstall()); setProgressVisible(false); setProgress(-1); setVisible(true); @@ -90,20 +108,33 @@ void UpdaterViewModel::onUpdateAvailable() { void UpdaterViewModel::onNoUpdateAvailable() { - setCanInstall(false); + setInstallEnabled(false); setProgressVisible(false); setProgress(-1); setVisible(false); setMessage(""); } -void UpdaterViewModel::setMessage(const QString& message) { +void UpdaterViewModel::setMessage(const QString& message) +{ if (message_ == message) return; message_ = message; emit messageChanged(); } -QString UpdaterViewModel::getUrl() const { - return updater_.getLatestRelease()->getUrl(); +QString UpdaterViewModel::getUrl() const +{ + const Release* r = updater_.getLatestRelease(); + if (r != nullptr) + return r->getUrl(); + return ""; +} + +QString UpdaterViewModel::getStatus() const { + return UpdaterStatusConverter::toString(updater_.getStatus()); +} + +bool UpdaterViewModel::isBusy() const { + return updater_.getStatus() != Updater::Status::None; } diff --git a/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.hpp b/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.hpp index 2dc98e25..9b1b7feb 100644 --- a/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.hpp +++ b/lib/MellowPlayer/Presentation/ViewModels/UpdaterViewModel.hpp @@ -9,8 +9,10 @@ namespace MellowPlayer::Presentation { Q_OBJECT Q_PROPERTY(QString message READ getMessage NOTIFY messageChanged) Q_PROPERTY(QString url READ getUrl CONSTANT) + Q_PROPERTY(QString status READ getStatus NOTIFY statusChanged) + Q_PROPERTY(bool busy READ isBusy NOTIFY busyChanged) Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged) - Q_PROPERTY(bool canInstall READ canInstall NOTIFY canInstallChanged) + Q_PROPERTY(bool installEnabled READ isInstallEnabled NOTIFY installEnabledChanged) Q_PROPERTY(int progress READ getProgress NOTIFY progressChanged) Q_PROPERTY(bool progressVisible READ isProgressVisible NOTIFY progressVisibleChanged) public: @@ -18,8 +20,10 @@ namespace MellowPlayer::Presentation { QString getMessage() const; QString getUrl() const; + QString getStatus() const; + bool isBusy() const; bool isVisible() const; - bool canInstall() const; + bool isInstallEnabled() const; int getProgress() const; bool isProgressVisible() const; @@ -30,14 +34,16 @@ namespace MellowPlayer::Presentation { signals: void messageChanged(); void visibleChanged(); - void canInstallChanged(); + void installEnabledChanged(); void progressChanged(); void progressVisibleChanged(); + void statusChanged(); + void busyChanged(); private slots: void setMessage(const QString& message); void setVisible(bool visible); - void setCanInstall(bool canInstall); + void setInstallEnabled(bool enabled); void setProgress(int progress); void setProgressVisible(bool progressVisible); void onUpdateAvailable(); @@ -47,8 +53,8 @@ namespace MellowPlayer::Presentation { Application::Updater& updater_; QString message_; bool visible_ = false; - bool canInstall_ = false; + bool installEnabled_ = false; int progress_ = -1; - bool progressVisible_ = true; + bool progressVisible_ = false; }; } diff --git a/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/MainToolBar.qml b/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/MainToolBar.qml index 38336b3e..2a82445c 100644 --- a/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/MainToolBar.qml +++ b/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/MainToolBar.qml @@ -364,7 +364,8 @@ ToolBar { MenuIconItem { icon: MaterialIcons.icon_update - text: "Check for updates" + text: _updater.busy ? _updater.status : "Check for update" + enabled: !_updater.busy onClicked: _updater.check() ProgressBar { diff --git a/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/UpdateToolBar.qml b/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/UpdateToolBar.qml index a56e92a7..ebbd4baa 100644 --- a/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/UpdateToolBar.qml +++ b/lib/MellowPlayer/Presentation/Views/MellowPlayer/Controls/UpdateToolBar.qml @@ -8,6 +8,7 @@ import MellowPlayer 3.0 ToolBar { id: updateToolBar + enabled: !_updater.busy height: 0 transform: Scale { id: scaleTransform @@ -61,7 +62,7 @@ ToolBar { highlighted: true text: "Install" onClicked: _updater.install() -// visible: _updater.canInstall + visible: _updater.installEnabled } ToolButton { diff --git a/tests/UnitTests/Presentation/Converters/UpdateStatusConverterTests.cpp b/tests/UnitTests/Presentation/Converters/UpdateStatusConverterTests.cpp index b71e0630..14730594 100644 --- a/tests/UnitTests/Presentation/Converters/UpdateStatusConverterTests.cpp +++ b/tests/UnitTests/Presentation/Converters/UpdateStatusConverterTests.cpp @@ -2,7 +2,7 @@ #include using namespace MellowPlayer::Application; -using namespace MellowPlayer::Infrastructure; +using namespace MellowPlayer::Presentation; SCENARIO("Updater status can be converted to a string") { GIVEN("UpdaterStatus::None") { @@ -11,8 +11,8 @@ SCENARIO("Updater status can be converted to a string") { WHEN("converting to string") { QString statusString = UpdaterStatusConverter::toString(status); - THEN("the string is empty") { - REQUIRE(statusString.isEmpty()); + THEN("the string is None") { + REQUIRE(statusString == UpdaterStatusConverter::NONE); } } } @@ -67,6 +67,18 @@ SCENARIO("Updater status can be converted from a string") { } } + GIVEN("a None status string") { + QString statusString = UpdaterStatusConverter::NONE; + + WHEN("converting from string") { + Updater::Status status = UpdaterStatusConverter::fromString(statusString); + + THEN("Status is None") { + REQUIRE(status == Updater::Status::None); + } + } + } + GIVEN("a valid status string") { QString statusString = UpdaterStatusConverter::CHECKING; diff --git a/tests/UnitTests/Presentation/ViewModels/UpdaterViewModelTests.cpp b/tests/UnitTests/Presentation/ViewModels/UpdaterViewModelTests.cpp new file mode 100644 index 00000000..aa814653 --- /dev/null +++ b/tests/UnitTests/Presentation/ViewModels/UpdaterViewModelTests.cpp @@ -0,0 +1,84 @@ +#include +#include +#include + +using namespace MellowPlayer::Application; +using namespace MellowPlayer::Presentation; +using namespace MellowPlayer::Tests; + + +SCENARIO("check for updates") { + DependencyPool pool; + Updater& updater = pool.getUpdater(); + UpdaterViewModel& viewModel = pool.getUpdaterViewModel(); + + GIVEN("current version is 2.2.4 from April 2017") { + Release currentRelease("2.2.4", QDate::fromString("2017-04-29", Qt::ISODate)); + updater.setCurrentRelease(¤tRelease); + + REQUIRE(!viewModel.isBusy()); + REQUIRE(!viewModel.isVisible()); + REQUIRE(viewModel.getMessage().isEmpty()); + REQUIRE(viewModel.getUrl().isEmpty()); + REQUIRE(viewModel.getStatus().isEmpty()); + REQUIRE(!viewModel.isInstallEnabled()); + REQUIRE(!viewModel.isProgressVisible()); + REQUIRE(viewModel.getProgress() == -1); + + WHEN("checking for updates") { + viewModel.check(); + REQUIRE(!viewModel.isBusy()); + + THEN("an update is available") { + REQUIRE(viewModel.isVisible()); + REQUIRE(!viewModel.getMessage().isEmpty()); + REQUIRE(!viewModel.getUrl().isEmpty()); + + AND_WHEN("closing the pane") { + viewModel.close(); + + THEN("visible changed but all other properties remains") { + REQUIRE(!viewModel.isVisible()); + + REQUIRE(!viewModel.getMessage().isEmpty()); + REQUIRE(!viewModel.getUrl().isEmpty()); + } + } + + AND_WHEN("clicking on install") { + viewModel.install(); + + THEN("progress bar appear and updater starts downloading") { + REQUIRE(viewModel.isProgressVisible()); + REQUIRE(viewModel.isBusy()); + } + } + } + } + } + + GIVEN("current version is 3.0 from August 2017") { + Release currentRelease("3.0", QDate::fromString("2017-08-12", Qt::ISODate)); + updater.setCurrentRelease(¤tRelease); + + REQUIRE(!viewModel.isBusy()); + REQUIRE(!viewModel.isVisible()); + REQUIRE(viewModel.getMessage().isEmpty()); + REQUIRE(viewModel.getUrl().isEmpty()); + REQUIRE(viewModel.getStatus().isEmpty()); + REQUIRE(!viewModel.isInstallEnabled()); + REQUIRE(!viewModel.isProgressVisible()); + REQUIRE(viewModel.getProgress() == -1); + + WHEN("checking for updates") { + viewModel.check(); + REQUIRE(!viewModel.isBusy()); + + THEN("no update is available") { + REQUIRE(!viewModel.isVisible()); + REQUIRE(viewModel.getMessage().isEmpty()); + REQUIRE(viewModel.getUrl().isEmpty()); + } + } + } +}