diff options
author | Daniel d'Andrada <daniel.dandrada@canonical.com> | 2015-08-19 17:17:56 -0300 |
---|---|---|
committer | Paul Olav Tvete <paul.tvete@theqtcompany.com> | 2015-08-26 11:46:35 +0000 |
commit | 5ab43ed3da5a6cda7dc8f4fe796c9c47e9d731ad (patch) | |
tree | 564d33f5bd49269233c6403e89281b1c19388c64 | |
parent | 072e49ca55beaaf87cf5b6a035393fd82ccc49dd (diff) |
Add some Application tests
Change-Id: I7ceb141dadb99f09009f2776fc3e4709a4ba4e61
Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
-rw-r--r-- | src/modules/Unity/Application/desktopfilereader.h | 3 | ||||
-rw-r--r-- | tests/modules/Application/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/modules/Application/application_test.cpp | 148 | ||||
-rw-r--r-- | tests/modules/common/fake_desktopfilereader.h | 51 | ||||
-rw-r--r-- | tests/modules/common/fake_session.h | 107 |
5 files changed, 281 insertions, 29 deletions
diff --git a/src/modules/Unity/Application/desktopfilereader.h b/src/modules/Unity/Application/desktopfilereader.h index 2cd09fb..8f037bd 100644 --- a/src/modules/Unity/Application/desktopfilereader.h +++ b/src/modules/Unity/Application/desktopfilereader.h @@ -63,12 +63,11 @@ public: static bool parseBoolean(const QString &rawString, bool &result); protected: + DesktopFileReader() : d_ptr(nullptr) {} DesktopFileReader(const QString &appId, const QFileInfo &desktopFile); DesktopFileReaderPrivate * const d_ptr; - friend class DesktopFileReaderFactory; - private: Q_DECLARE_PRIVATE(DesktopFileReader) }; diff --git a/tests/modules/Application/CMakeLists.txt b/tests/modules/Application/CMakeLists.txt index 7787d26..fdd2b50 100644 --- a/tests/modules/Application/CMakeLists.txt +++ b/tests/modules/Application/CMakeLists.txt @@ -1,6 +1,7 @@ set( APPLICATION_TEST_SOURCES application_test.cpp + ${CMAKE_SOURCE_DIR}/tests/modules/common/fake_session.h ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp ) diff --git a/tests/modules/Application/application_test.cpp b/tests/modules/Application/application_test.cpp index 419da24..0e10f46 100644 --- a/tests/modules/Application/application_test.cpp +++ b/tests/modules/Application/application_test.cpp @@ -19,6 +19,8 @@ #include "qtmir_test.h" +#include <fake_desktopfilereader.h> +#include <fake_session.h> #include <mock_session.h> #include <QScopedPointer> @@ -36,21 +38,14 @@ public: TEST_F(ApplicationTests, acquiresWakelockWhenRunningAndReleasesWhenSuspended) { using namespace ::testing; - QString appId("foo-app"); - - auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); - ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); QScopedPointer<Application> application(new Application( QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), - desktopFileReader, QStringList(), nullptr)); + new FakeDesktopFileReader, QStringList(), nullptr)); application->setProcessState(Application::ProcessRunning); - NiceMock<MockSession> *session = new NiceMock<MockSession>; - - EXPECT_CALL(*session, setApplication(_)); - EXPECT_CALL(*session, fullscreen()).WillRepeatedly(Return(false)); + FakeSession *session = new FakeSession; application->setSession(session); @@ -81,14 +76,10 @@ TEST_F(ApplicationTests, acquiresWakelockWhenRunningAndReleasesWhenSuspended) TEST_F(ApplicationTests, checkResumeAcquiresWakeLock) { using namespace ::testing; - QString appId("foo-app"); - - auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); - ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); QScopedPointer<Application> application(new Application( QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), - desktopFileReader, QStringList(), nullptr)); + new FakeDesktopFileReader, QStringList(), nullptr)); NiceMock<MockSession> *session = new NiceMock<MockSession>; // Get it running and then suspend it @@ -112,14 +103,10 @@ TEST_F(ApplicationTests, checkResumeAcquiresWakeLock) TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock) { using namespace ::testing; - QString appId("foo-app"); - - auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); - ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); QScopedPointer<Application> application(new Application( QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), - desktopFileReader, QStringList(), nullptr)); + new FakeDesktopFileReader, QStringList(), nullptr)); NiceMock<MockSession> *session = new NiceMock<MockSession>; // Get it running, suspend it, and finally stop it @@ -131,7 +118,7 @@ TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock) application->setProcessState(Application::ProcessSuspended); ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); session->setState(SessionInterface::Stopped); - application->setProcessState(Application::ProcessStopped); + application->setProcessState(Application::ProcessKilled); ASSERT_EQ(Application::InternalState::StoppedUnexpectedly, application->internalState()); EXPECT_FALSE(sharedWakelock.enabled()); @@ -149,13 +136,12 @@ TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock) TEST_F(ApplicationTests, checkDashDoesNotImpactWakeLock) { using namespace ::testing; - QString appId("unity8-dash"); EXPECT_CALL(sharedWakelock, acquire(_)).Times(0); EXPECT_CALL(sharedWakelock, release(_)).Times(0); - auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); - ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); + FakeDesktopFileReader *desktopFileReader = new FakeDesktopFileReader; + desktopFileReader->m_appId = QString("unity8-dash"); QScopedPointer<Application> application(new Application( QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), @@ -163,10 +149,7 @@ TEST_F(ApplicationTests, checkDashDoesNotImpactWakeLock) application->setProcessState(Application::ProcessRunning); - NiceMock<MockSession> *session = new NiceMock<MockSession>; - - EXPECT_CALL(*session, setApplication(_)); - EXPECT_CALL(*session, fullscreen()).WillRepeatedly(Return(false)); + FakeSession *session = new FakeSession; application->setSession(session); @@ -193,3 +176,114 @@ TEST_F(ApplicationTests, checkDashDoesNotImpactWakeLock) ASSERT_EQ(Application::InternalState::Running, application->internalState()); } + +TEST_F(ApplicationTests, emitsStoppedWhenRunningAppStops) +{ + using namespace ::testing; + + QScopedPointer<Application> application(new Application( + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), + new FakeDesktopFileReader, QStringList(), nullptr)); + + application->setProcessState(Application::ProcessRunning); + + FakeSession *session = new FakeSession; + application->setSession(session); + + QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped())); + + session->setState(SessionInterface::Running); + + ASSERT_EQ(Application::InternalState::Running, application->internalState()); + + //// + // Simulate a running application closing itself (ie, ending its own process) + + session->setState(SessionInterface::Stopped); + + ASSERT_EQ(Application::InternalState::Stopped, application->internalState()); + + application->setProcessState(Application::ProcessStopped); + + ASSERT_EQ(1, spyAppStopped.count()); +} + +/** + * Regression test for https://bugs.launchpad.net/qtmir/+bug/1485608 + * In that case, the camera-app closes itself right after unity8 unfocus it (and thus requests it to be suspended). + */ +TEST_F(ApplicationTests, emitsStoppedWhenAppStopsWhileSuspending) +{ + using namespace ::testing; + + QScopedPointer<Application> application(new Application( + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), + new FakeDesktopFileReader, QStringList(), nullptr)); + + application->setProcessState(Application::ProcessRunning); + + FakeSession *session = new FakeSession; + application->setSession(session); + + QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped())); + + session->setState(SessionInterface::Running); + + ASSERT_EQ(Application::InternalState::Running, application->internalState()); + + application->setRequestedState(Application::RequestedSuspended); + + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); + + // Now the application closes itself (ie, ending its own process) + // Session always responds before the process state. + session->setState(SessionInterface::Stopped); + application->setProcessState(Application::ProcessStopped); + + ASSERT_EQ(Application::InternalState::Stopped, application->internalState()); + ASSERT_EQ(1, spyAppStopped.count()); +} + +TEST_F(ApplicationTests, doesNotEmitStoppedWhenKilledWhileSuspended) +{ + using namespace ::testing; + + QScopedPointer<Application> application(new Application( + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), + new FakeDesktopFileReader, QStringList(), nullptr)); + + application->setProcessState(Application::ProcessRunning); + + FakeSession *session = new FakeSession; + application->setSession(session); + + QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped())); + + session->setState(SessionInterface::Running); + + ASSERT_EQ(Application::InternalState::Running, application->internalState()); + + application->setRequestedState(Application::RequestedSuspended); + + ASSERT_EQ(SessionInterface::Suspending, session->state()); + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); + + session->setState(SessionInterface::Suspended); + + ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState()); + + application->setProcessState(Application::ProcessSuspended); + + /// + // Now simulate the process getting killed. Mir session always ends before + // we get notified about the process state + + session->setState(SessionInterface::Stopped); + + application->setProcessState(Application::ProcessKilled); + + ASSERT_EQ(Application::InternalState::StoppedUnexpectedly, application->internalState()); + + ASSERT_EQ(0, spyAppStopped.count()); + +} diff --git a/tests/modules/common/fake_desktopfilereader.h b/tests/modules/common/fake_desktopfilereader.h new file mode 100644 index 0000000..f1664f1 --- /dev/null +++ b/tests/modules/common/fake_desktopfilereader.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef FAKE_DESKTOPFILEREADER_H +#define FAKE_DESKTOPFILEREADER_H + +namespace qtmir { + +class FakeDesktopFileReader : public qtmir::DesktopFileReader { +public: + FakeDesktopFileReader() : DesktopFileReader() + , m_appId("foo-app") + {} + + QString file() const override { return QString(); } + QString appId() const override { return m_appId; } + QString name() const override { return QString(); } + QString comment() const override { return QString(); } + QString icon() const override { return QString(); } + QString exec() const override { return QString(); } + QString path() const override { return QString(); } + QString stageHint() const override { return QString(); } + QString splashTitle() const override { return QString(); } + QString splashImage() const override { return QString(); } + QString splashShowHeader() const override { return QString(); } + QString splashColor() const override { return QString(); } + QString splashColorHeader() const override { return QString(); } + QString splashColorFooter() const override { return QString(); } + Qt::ScreenOrientations supportedOrientations() const override { return Qt::PortraitOrientation; } + bool rotatesWindowContents() const override { return false; } + bool loaded() const override { return true; } + + QString m_appId; +}; + +} // namespace qtmir + +#endif // FAKE_DESKTOPFILEREADER_H diff --git a/tests/modules/common/fake_session.h b/tests/modules/common/fake_session.h new file mode 100644 index 0000000..bb2e4d6 --- /dev/null +++ b/tests/modules/common/fake_session.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2015 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <Unity/Application/session_interface.h> + +#ifndef QTMIR_FAKE_SESSION_H +#define QTMIR_FAKE_SESSION_H + +namespace qtmir { + +class FakeSession : public SessionInterface { + Q_OBJECT + +public: + FakeSession() + : SessionInterface(0) + , m_state(Starting) + { + } + + // For QML use + void release() override {} + + QString name() const override { return QString("foo-session"); } + unity::shell::application::ApplicationInfoInterface* application() const override { return m_application; } + MirSurfaceItemInterface* surface() const override { return nullptr; } + SessionInterface* parentSession() const override { return nullptr; } + SessionModel* childSessions() const override { return nullptr; } + State state() const override { return m_state; } + bool fullscreen() const override { return false; } + bool live() const override { return true; } + + std::shared_ptr<mir::scene::Session> session() const override { return nullptr; } + + // For MirSurfaceItem and MirSurfaceManager use + + void setSurface(MirSurfaceItemInterface*) override {} + + // For Application use + + void setApplication(unity::shell::application::ApplicationInfoInterface* app) override { + if (m_application != app) { + m_application = app; + Q_EMIT applicationChanged(m_application); + } + } + void suspend() override { + if (m_state == Running) { + setState(Suspending); + } + } + void resume() override { + if (m_state == Suspending || m_state == Suspended) { + setState(Running); + } + } + void stop() override { + setState(Stopped); + } + + // For SessionManager use + + void addChildSession(SessionInterface*) override {} + void insertChildSession(uint, SessionInterface*) override {} + void removeChildSession(SessionInterface*) override {} + void foreachChildSession(std::function<void(SessionInterface* session)>) const override {} + + std::shared_ptr<mir::scene::PromptSession> activePromptSession() const override { + return std::shared_ptr<mir::scene::PromptSession>(); + } + void foreachPromptSession(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)>) const override {} + + void setFullscreen(bool) override {} + void setLive(const bool) override {} + void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>&) override {} + void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>&) override {} + + // For tests + + void setState(State state) { + if (m_state != state) { + m_state = state; + Q_EMIT stateChanged(m_state); + } + } + +private: + unity::shell::application::ApplicationInfoInterface* m_application; + State m_state; +}; + +} // namespace qtmi + +#endif // QTMIR_FAKE_SESSION_H |