Skip to content

Commit c10aa51

Browse files
committed
add workspace manager unit tests
1 parent 4fb23b2 commit c10aa51

File tree

6 files changed

+355
-0
lines changed

6 files changed

+355
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-only
3+
* MuseScore-CLA-applies
4+
*
5+
* MuseScore
6+
* Music Composition & Notation
7+
*
8+
* Copyright (C) 2026 MuseScore Limited and others
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License version 3 as
12+
* published by the Free Software Foundation.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
#pragma once
23+
24+
#include <gmock/gmock.h>
25+
26+
#include "multiwindows/imultiwindowsprovider.h"
27+
28+
namespace muse::mi {
29+
class MultiWindowsProviderMock : public IMultiWindowsProvider
30+
{
31+
public:
32+
MOCK_METHOD(size_t, windowCount, (), (const, override));
33+
MOCK_METHOD(bool, isFirstWindow, (), (const, override));
34+
MOCK_METHOD(bool, isProjectAlreadyOpened, (const io::path_t&), (const, override));
35+
MOCK_METHOD(void, activateWindowWithProject, (const io::path_t&), (override));
36+
MOCK_METHOD(bool, isHasWindowWithoutProject, (), (const, override));
37+
MOCK_METHOD(void, activateWindowWithoutProject, (const QStringList&), (override));
38+
MOCK_METHOD(bool, openNewWindow, (const QStringList&), (override));
39+
MOCK_METHOD(bool, isPreferencesAlreadyOpened, (), (const, override));
40+
MOCK_METHOD(void, activateWindowWithOpenedPreferences, (), (const, override));
41+
MOCK_METHOD(void, settingsBeginTransaction, (), (override));
42+
MOCK_METHOD(void, settingsCommitTransaction, (), (override));
43+
MOCK_METHOD(void, settingsRollbackTransaction, (), (override));
44+
MOCK_METHOD(void, settingsReset, (), (override));
45+
MOCK_METHOD(void, settingsSetValue, (const std::string&, const Val&), (override));
46+
MOCK_METHOD(bool, lockResource, (const std::string&), (override));
47+
MOCK_METHOD(bool, unlockResource, (const std::string&), (override));
48+
MOCK_METHOD(void, notifyAboutResourceChanged, (const std::string&), (override));
49+
MOCK_METHOD(async::Channel<std::string>, resourceChanged, (), (override));
50+
MOCK_METHOD(void, notifyAboutWindowWasQuited, (), (override));
51+
MOCK_METHOD(void, quitForAll, (), (override));
52+
MOCK_METHOD(void, quitWindow, (const modularity::ContextPtr&), (override));
53+
MOCK_METHOD(void, quitAllAndRestartLast, (), (override));
54+
MOCK_METHOD(void, quitAllAndRunInstallation, (const io::path_t&), (override));
55+
};
56+
}

src/framework/workspace/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ target_sources(muse_workspace PRIVATE
5353
if (MUSE_MODULE_WORKSPACE_QML)
5454
add_subdirectory(qml/Muse/Workspace)
5555
endif()
56+
57+
if (MUSE_MODULE_WORKSPACE_TESTS)
58+
add_subdirectory(tests)
59+
endif()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# SPDX-License-Identifier: GPL-3.0-only
2+
# MuseScore-CLA-applies
3+
#
4+
# MuseScore
5+
# Music Composition & Notation
6+
#
7+
# Copyright (C) 2026 MuseScore Limited and others
8+
#
9+
# This program is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License version 3 as
11+
# published by the Free Software Foundation.
12+
#
13+
# This program is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU General Public License
19+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
21+
set(MODULE_TEST muse_workspace_tests)
22+
23+
set(MODULE_TEST_SRC
24+
${CMAKE_CURRENT_LIST_DIR}/mocks/workspaceconfigurationmock.h
25+
${MUSE_FRAMEWORK_SRC_PATH}/multiwindows/tests/mocks/multiwindowsprovidermock.h
26+
${CMAKE_CURRENT_LIST_DIR}/environment.cpp
27+
${CMAKE_CURRENT_LIST_DIR}/workspacemanager_tests.cpp
28+
)
29+
30+
set(MODULE_TEST_LINK
31+
muse::workspace
32+
)
33+
34+
set(MODULE_TEST_INCLUDE
35+
${MUSE_FRAMEWORK_SRC_PATH}/workspace
36+
${MUSE_FRAMEWORK_SRC_PATH}/workspace/internal
37+
${MUSE_FRAMEWORK_SRC_PATH}/multiwindows
38+
)
39+
40+
set(MODULE_TEST_DEF
41+
BUILTIN_WORKSPACES_DIR="${CMAKE_SOURCE_DIR}/share/workspaces"
42+
)
43+
44+
include(SetupGTest)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-only
3+
* MuseScore-CLA-applies
4+
*
5+
* MuseScore
6+
* Music Composition & Notation
7+
*
8+
* Copyright (C) 2026 MuseScore Limited and others
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License version 3 as
12+
* published by the Free Software Foundation.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
#include "testing/environment.h"
24+
25+
#include "workspace/tests/mocks/workspaceconfigurationmock.h"
26+
27+
using namespace ::testing;
28+
29+
static muse::testing::SuiteEnvironment workspace_se
30+
= muse::testing::SuiteEnvironment()
31+
.setPreInit([](){
32+
auto workspaceConfig = std::make_shared<::testing::NiceMock<muse::workspace::WorkspaceConfigurationMock> >();
33+
34+
ON_CALL(*workspaceConfig, defaultWorkspaceName())
35+
.WillByDefault(Return("Default"));
36+
37+
muse::modularity::globalIoc()->registerExport<muse::workspace::IWorkspaceConfiguration>("utests", workspaceConfig);
38+
}).setDeInit([](){
39+
muse::modularity::globalIoc()->unregister<muse::workspace::IWorkspaceConfiguration>("utests");
40+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-only
3+
* MuseScore-CLA-applies
4+
*
5+
* MuseScore
6+
* Music Composition & Notation
7+
*
8+
* Copyright (C) 2026 MuseScore Limited and others
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License version 3 as
12+
* published by the Free Software Foundation.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
#pragma once
23+
24+
#include <gmock/gmock.h>
25+
26+
#include "workspace/iworkspaceconfiguration.h"
27+
28+
namespace muse::workspace {
29+
class WorkspaceConfigurationMock : public IWorkspaceConfiguration
30+
{
31+
public:
32+
MOCK_METHOD(io::paths_t, workspacePaths, (), (const, override));
33+
MOCK_METHOD(io::paths_t, builtinWorkspacesFilePaths, (), (const, override));
34+
MOCK_METHOD(io::path_t, userWorkspacesPath, (), (const, override));
35+
MOCK_METHOD(std::string, defaultWorkspaceName, (), (const, override));
36+
MOCK_METHOD(std::string, currentWorkspaceName, (), (const, override));
37+
MOCK_METHOD(void, setCurrentWorkspaceName, (const std::string&), (override));
38+
MOCK_METHOD(async::Channel<std::string>, currentWorkspaceNameChanged, (), (const, override));
39+
};
40+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-only
3+
* MuseScore-CLA-applies
4+
*
5+
* MuseScore
6+
* Music Composition & Notation
7+
*
8+
* Copyright (C) 2026 MuseScore Limited and others
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License version 3 as
12+
* published by the Free Software Foundation.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
#include <gtest/gtest.h>
23+
#include <gmock/gmock.h>
24+
25+
#include <QTemporaryDir>
26+
27+
#include "modularity/ioc.h"
28+
#include "workspace/internal/workspacemanager.h"
29+
#include "workspace/iworkspaceconfiguration.h"
30+
#include "workspace/tests/mocks/workspaceconfigurationmock.h"
31+
#include "multiwindows/tests/mocks/multiwindowsprovidermock.h"
32+
33+
using ::testing::Return;
34+
35+
using namespace muse;
36+
using namespace muse::workspace;
37+
38+
static const std::string BUILTIN_WORKSPACE_DIR = BUILTIN_WORKSPACES_DIR;
39+
40+
namespace muse::workspace {
41+
class Workspace_WorkspaceManagerTests : public ::testing::Test
42+
{
43+
public:
44+
void SetUp() override
45+
{
46+
m_userWorkspacesDir = std::make_unique<QTemporaryDir>();
47+
ASSERT_TRUE(m_userWorkspacesDir->isValid());
48+
49+
m_multiWindowsProvider = std::make_shared<::testing::NiceMock<mi::MultiWindowsProviderMock> >();
50+
modularity::globalIoc()->registerExport<mi::IMultiWindowsProvider>("utests", m_multiWindowsProvider);
51+
52+
m_workspaceConfig = std::dynamic_pointer_cast<muse::workspace::WorkspaceConfigurationMock>(
53+
modularity::globalIoc()->resolve<IWorkspaceConfiguration>("utests"));
54+
ASSERT_NE(m_workspaceConfig, nullptr);
55+
56+
m_userWorkspacesPath = m_userWorkspacesDir->path().toStdString();
57+
}
58+
59+
void TearDown() override
60+
{
61+
m_manager.reset();
62+
modularity::globalIoc()->unregister<mi::IMultiWindowsProvider>("utests");
63+
}
64+
65+
void setupBuiltinPaths(const std::vector<std::string>& filenames)
66+
{
67+
io::paths_t paths;
68+
for (const auto& name : filenames) {
69+
paths.push_back(io::path_t(BUILTIN_WORKSPACE_DIR + "/" + name));
70+
}
71+
72+
ON_CALL(*m_workspaceConfig, builtinWorkspacesFilePaths())
73+
.WillByDefault(Return(paths));
74+
75+
ON_CALL(*m_workspaceConfig, userWorkspacesPath())
76+
.WillByDefault(Return(io::path_t(m_userWorkspacesPath)));
77+
}
78+
79+
void initManager()
80+
{
81+
m_manager = std::make_unique<WorkspaceManager>(modularity::globalCtx());
82+
m_manager->init();
83+
}
84+
85+
protected:
86+
std::unique_ptr<QTemporaryDir> m_userWorkspacesDir;
87+
std::string m_userWorkspacesPath;
88+
89+
std::shared_ptr<::testing::NiceMock<mi::MultiWindowsProviderMock> > m_multiWindowsProvider;
90+
std::shared_ptr<muse::workspace::WorkspaceConfigurationMock> m_workspaceConfig;
91+
92+
std::unique_ptr<WorkspaceManager> m_manager;
93+
};
94+
95+
TEST_F(Workspace_WorkspaceManagerTests, BuiltinWorkspaceLoadsOnInit)
96+
{
97+
//! [GIVEN] Builtin workspace file exists
98+
setupBuiltinPaths({ "Default.mws" });
99+
100+
//! [GIVEN] Current workspace is "Default"
101+
ON_CALL(*m_workspaceConfig, currentWorkspaceName())
102+
.WillByDefault(Return("Default"));
103+
104+
//! [WHEN] WorkspaceManager is initialized
105+
initManager();
106+
107+
//! [THEN] Default workspace is loaded
108+
EXPECT_NE(m_manager->defaultWorkspace(), nullptr);
109+
EXPECT_EQ(m_manager->defaultWorkspace()->name(), "Default");
110+
111+
//! [THEN] Current workspace matches default
112+
EXPECT_NE(m_manager->currentWorkspace(), nullptr);
113+
EXPECT_EQ(m_manager->currentWorkspace()->name(), "Default");
114+
115+
//! [THEN] Builtin workspace is available
116+
EXPECT_EQ(m_manager->workspaces().size(), 1);
117+
118+
m_manager->deinit();
119+
}
120+
121+
TEST_F(Workspace_WorkspaceManagerTests, FallbackToDefaultOnMissingCurrentWorkspace)
122+
{
123+
//! [GIVEN] Builtin workspace file exists
124+
setupBuiltinPaths({ "Default.mws" });
125+
126+
//! [GIVEN] Current workspace name references a workspace that no longer exists
127+
ON_CALL(*m_workspaceConfig, currentWorkspaceName())
128+
.WillByDefault(Return("MyDeletedWorkspace"));
129+
130+
//! [GIVEN] Manager will correct the setting to default
131+
EXPECT_CALL(*m_workspaceConfig, setCurrentWorkspaceName("Default"))
132+
.Times(1);
133+
134+
//! [WHEN] WorkspaceManager is initialized
135+
initManager();
136+
137+
//! [THEN] Falls back to default workspace
138+
EXPECT_NE(m_manager->currentWorkspace(), nullptr);
139+
EXPECT_EQ(m_manager->currentWorkspace()->name(), "Default");
140+
EXPECT_NE(m_manager->defaultWorkspace(), nullptr);
141+
EXPECT_EQ(m_manager->defaultWorkspace()->name(), "Default");
142+
143+
m_manager->deinit();
144+
}
145+
146+
TEST_F(Workspace_WorkspaceManagerTests, EmptyUserDirUsesBuiltinWorkspaces)
147+
{
148+
//! [GIVEN] Builtin workspace file exists, user dir is empty
149+
setupBuiltinPaths({ "Default.mws" });
150+
151+
ON_CALL(*m_workspaceConfig, currentWorkspaceName())
152+
.WillByDefault(Return("Default"));
153+
154+
//! [WHEN] WorkspaceManager is initialized
155+
initManager();
156+
157+
//! [THEN] Workspaces are loaded from builtins only
158+
EXPECT_EQ(m_manager->workspaces().size(), 1);
159+
160+
//! [THEN] Current workspace is loaded and usable
161+
auto current = m_manager->currentWorkspace();
162+
ASSERT_NE(current, nullptr);
163+
EXPECT_EQ(current->name(), "Default");
164+
165+
//! [THEN] Reading workspace data does not crash
166+
auto data = current->rawData("ui_settings");
167+
EXPECT_TRUE(data.ret);
168+
169+
m_manager->deinit();
170+
}
171+
}

0 commit comments

Comments
 (0)