summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel d'Andrada <daniel.dandrada@canonical.com>2015-08-19 17:17:56 -0300
committerPaul Olav Tvete <paul.tvete@theqtcompany.com>2015-08-26 11:46:35 +0000
commit5ab43ed3da5a6cda7dc8f4fe796c9c47e9d731ad (patch)
tree564d33f5bd49269233c6403e89281b1c19388c64
parent072e49ca55beaaf87cf5b6a035393fd82ccc49dd (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.h3
-rw-r--r--tests/modules/Application/CMakeLists.txt1
-rw-r--r--tests/modules/Application/application_test.cpp148
-rw-r--r--tests/modules/common/fake_desktopfilereader.h51
-rw-r--r--tests/modules/common/fake_session.h107
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