Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ static const auto& mappingByCategory(const mpe::SoundCategory category)

{ { mpe::SoundId::Quena, {} }, { midi::Program(0, 67) } },

{ { mpe::SoundId::Dulzaina, { mpe::SoundSubCategory::Castilian } }, { midi::Program(0, 68) } },

{ { mpe::SoundId::Heckelphone, {} }, { midi::Program(0, 68) } },
{ { mpe::SoundId::Oboe, { mpe::SoundSubCategory::Baroque } }, { midi::Program(0, 69) } },
{ { mpe::SoundId::Oboe, {} }, { midi::Program(0, 68) } },
Expand Down
4 changes: 4 additions & 0 deletions framework/mpe/soundid.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ enum class SoundId

WindsGroup,
Piccolo,
Dulzaina,
Heckelphone,
HeckelphoneClarinet,
Oboe,
Expand Down Expand Up @@ -288,6 +289,7 @@ enum class SoundSubCategory
African,
Indian,
Spanish,
Castilian,
Swedish,
Hungarian,
Romanian,
Expand Down Expand Up @@ -503,6 +505,7 @@ inline const std::unordered_map<SoundId, String> ID_STRINGS

{ SoundId::WindsGroup, String(u"winds_group") },
{ SoundId::Piccolo, String(u"piccolo") },
{ SoundId::Dulzaina, String(u"dulzaina") },
{ SoundId::Heckelphone, String(u"heckelphone") },
{ SoundId::HeckelphoneClarinet, String(u"heckelphone_clarinet") },
{ SoundId::Oboe, String(u"oboe") },
Expand Down Expand Up @@ -746,6 +749,7 @@ inline const std::unordered_map<SoundSubCategory, String> SUBCATEGORY_STRINGS
{ SoundSubCategory::African, String(u"african") },
{ SoundSubCategory::Indian, String(u"indian") },
{ SoundSubCategory::Spanish, String(u"spanish") },
{ SoundSubCategory::Castilian, String(u"castilian") },
{ SoundSubCategory::Swedish, String(u"swedish") },
{ SoundSubCategory::Hungarian, String(u"hungarian") },
{ SoundSubCategory::Romanian, String(u"romanian") },
Expand Down
27 changes: 26 additions & 1 deletion framework/workspace/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ set(MODULE_TEST muse_workspace_tests)

set(MODULE_TEST_SRC
${CMAKE_CURRENT_LIST_DIR}/mocks/workspaceconfigurationmock.h
${CMAKE_CURRENT_LIST_DIR}/workspace_test_helpers.h
${CMAKE_CURRENT_LIST_DIR}/workspace_test_helpers.cpp
${CMAKE_CURRENT_LIST_DIR}/environment.cpp
${CMAKE_CURRENT_LIST_DIR}/workspaceconfig_tests.cpp
${CMAKE_CURRENT_LIST_DIR}/workspacemanager_tests.cpp
)

Expand All @@ -36,8 +39,30 @@ set(MODULE_TEST_INCLUDE
${MUSE_FRAMEWORK_SRC_PATH}/multiwindows
)

# Paths injected as compile-time defines for use by the test environment:
# BUILTIN_WORKSPACES_DIR - path to directory containing builtin .mws files (always tested)
# WORKSPACE_CONFIG_FILE - framework-level workspace config (always tested)
# APP_BUILTIN_WORKSPACES_DIR - optional app-level workspaces dir (tested additionally if set)
# e.g. set(APP_BUILTIN_WORKSPACES_DIR "${CMAKE_SOURCE_DIR}/share/workspaces")
# APP_WORKSPACE_CONFIG_FILE - optional app-level config (tested additionally if set)
# e.g. set(APP_WORKSPACE_CONFIG_FILE "${CMAKE_SOURCE_DIR}/src/app/configs/workspaces.cfg")
set(MODULE_TEST_DEF
BUILTIN_WORKSPACES_DIR="${CMAKE_SOURCE_DIR}/share/workspaces"
BUILTIN_WORKSPACES_DIR="${CMAKE_CURRENT_LIST_DIR}/testdata/workspaces"
WORKSPACE_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/testdata/workspaces.cfg"
)

message(STATUS " [workspace tests] Framework config: ${CMAKE_CURRENT_LIST_DIR}/testdata/workspaces.cfg")
message(STATUS " [workspace tests] Framework workspaces: ${CMAKE_CURRENT_LIST_DIR}/testdata/workspaces")

if (APP_WORKSPACE_CONFIG_FILE AND APP_BUILTIN_WORKSPACES_DIR)
list(APPEND MODULE_TEST_DEF
APP_WORKSPACE_CONFIG_FILE="${APP_WORKSPACE_CONFIG_FILE}"
APP_BUILTIN_WORKSPACES_DIR="${APP_BUILTIN_WORKSPACES_DIR}"
)
message(STATUS " [workspace tests] App config: ${APP_WORKSPACE_CONFIG_FILE}")
message(STATUS " [workspace tests] App workspaces: ${APP_BUILTIN_WORKSPACES_DIR}")
elseif (APP_WORKSPACE_CONFIG_FILE OR APP_BUILTIN_WORKSPACES_DIR)
message(FATAL_ERROR "APP_WORKSPACE_CONFIG_FILE and APP_BUILTIN_WORKSPACES_DIR must both be set or both be unset")
endif()

include(SetupGTest)
16 changes: 12 additions & 4 deletions framework/workspace/tests/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,29 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <gtest/gtest.h>

#include "testing/environment.h"

#include "workspace/tests/workspace_test_helpers.h"
#include "workspace/tests/mocks/workspaceconfigurationmock.h"

using namespace ::testing;

static muse::testing::SuiteEnvironment workspace_se
= muse::testing::SuiteEnvironment()
.setPreInit([](){
auto workspaceConfig = std::make_shared<::testing::NiceMock<muse::workspace::WorkspaceConfigurationMock> >();
auto& testCfg = muse::workspace::WorkspaceTestConfig::instance();
if (!testCfg.load(muse::io::path_t(WORKSPACE_CONFIG_FILE), BUILTIN_WORKSPACES_DIR)) {
FAIL() << "Failed to load workspace config from: " << WORKSPACE_CONFIG_FILE;
}

auto workspaceConfigMock = std::make_shared<::testing::NiceMock<muse::workspace::WorkspaceConfigurationMock> >();

ON_CALL(*workspaceConfig, defaultWorkspaceName())
.WillByDefault(Return("Default"));
ON_CALL(*workspaceConfigMock, defaultWorkspaceName())
.WillByDefault(Return(testCfg.defaultWorkspaceName()));

muse::modularity::globalIoc()->registerExport<muse::workspace::IWorkspaceConfiguration>("utests", workspaceConfig);
muse::modularity::globalIoc()->registerExport<muse::workspace::IWorkspaceConfiguration>("utests", workspaceConfigMock);
}).setDeInit([](){
muse::modularity::globalIoc()->unregister<muse::workspace::IWorkspaceConfiguration>("utests");
});
6 changes: 6 additions & 0 deletions framework/workspace/tests/testdata/workspaces.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"default_workspace_name": "Default",
"builtin_workspace_files": [
"Default.mws"
]
}
Binary file not shown.
75 changes: 75 additions & 0 deletions framework/workspace/tests/workspace_test_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2026 MuseScore Limited and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 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, see <https://www.gnu.org/licenses/>.
*/

#include "workspace_test_helpers.h"

#include "global/configreader.h"

using namespace muse;
using namespace muse::workspace;

WorkspaceTestConfig& WorkspaceTestConfig::instance()
{
static WorkspaceTestConfig s;
return s;
}

bool WorkspaceTestConfig::load(const io::path_t& configPath, const std::string& builtinWorkspacesDir)
{
m_defaultWorkspaceName.clear();
m_builtinFiles.clear();

m_builtinWorkspacesDir = builtinWorkspacesDir;
m_config = ConfigReader::read(configPath);

m_defaultWorkspaceName = m_config.value("default_workspace_name").toString();
if (m_defaultWorkspaceName.empty()) {
return false;
}

ValList files = m_config.value("builtin_workspace_files").toList();
for (const Val& v : files) {
m_builtinFiles.push_back(v.toString());
}

return !m_builtinFiles.empty();
}

const Config& WorkspaceTestConfig::config() const
{
return m_config;
}

const std::string& WorkspaceTestConfig::defaultWorkspaceName() const
{
return m_defaultWorkspaceName;
}

const std::vector<std::string>& WorkspaceTestConfig::builtinFiles() const
{
return m_builtinFiles;
}

const std::string& WorkspaceTestConfig::builtinWorkspacesDir() const
{
return m_builtinWorkspacesDir;
}
56 changes: 56 additions & 0 deletions framework/workspace/tests/workspace_test_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2026 MuseScore Limited and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 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, see <https://www.gnu.org/licenses/>.
*/
#pragma once

#include <string>
#include <vector>

#include "global/types/config.h"
#include "io/path.h"

namespace muse::workspace {
class WorkspaceTestConfig
{
public:
WorkspaceTestConfig() = default;

WorkspaceTestConfig(const WorkspaceTestConfig&) = delete;
WorkspaceTestConfig& operator=(const WorkspaceTestConfig&) = delete;
WorkspaceTestConfig(WorkspaceTestConfig&&) = delete;
WorkspaceTestConfig& operator=(WorkspaceTestConfig&&) = delete;

static WorkspaceTestConfig& instance();

bool load(const io::path_t& configPath, const std::string& builtinWorkspacesDir);

const Config& config() const;
const std::string& defaultWorkspaceName() const;
const std::vector<std::string>& builtinFiles() const;
const std::string& builtinWorkspacesDir() const;

private:
Config m_config;
std::string m_defaultWorkspaceName;
std::vector<std::string> m_builtinFiles;
std::string m_builtinWorkspacesDir;
};
}
113 changes: 113 additions & 0 deletions framework/workspace/tests/workspaceconfig_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2026 MuseScore Limited and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 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, see <https://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>

#include <set>

#include "io/fileinfo.h"
#include "workspace/tests/workspace_test_helpers.h"

using namespace muse;
using namespace muse::workspace;

struct ConfigTestParam {
std::string configFile;
std::string workspacesDir;
};

static void PrintTo(const ConfigTestParam& param, std::ostream* os)
{
*os << param.configFile;
}

static std::vector<ConfigTestParam> configTestParams()
{
std::vector<ConfigTestParam> params = {
{ WORKSPACE_CONFIG_FILE, BUILTIN_WORKSPACES_DIR },
};
#if defined(APP_WORKSPACE_CONFIG_FILE) && defined(APP_BUILTIN_WORKSPACES_DIR)
params.push_back({ APP_WORKSPACE_CONFIG_FILE, APP_BUILTIN_WORKSPACES_DIR });
#endif
return params;
}

class Workspace_ConfigTests : public ::testing::TestWithParam<ConfigTestParam>
{
};

TEST_P(Workspace_ConfigTests, ConfigIsValid)
{
const auto& param = GetParam();
WorkspaceTestConfig cfg;
ASSERT_TRUE(cfg.load(io::path_t(param.configFile), param.workspacesDir))
<< "failed to load: " << param.configFile;

//! [THEN] default_workspace_name is a non-empty string
EXPECT_FALSE(cfg.defaultWorkspaceName().empty());

//! [THEN] builtin_workspace_files is a non-empty list
EXPECT_FALSE(cfg.builtinFiles().empty());

//! [THEN] Each builtin file exists on disk
bool defaultFoundInBuiltins = false;
for (const auto& filename : cfg.builtinFiles()) {
io::path_t fullPath = io::path_t(cfg.builtinWorkspacesDir() + "/" + filename);
EXPECT_TRUE(io::FileInfo::exists(fullPath)) << "missing: " << fullPath.toStdString();

std::string baseName = io::completeBasename(fullPath).toStdString();
if (baseName == cfg.defaultWorkspaceName()) {
defaultFoundInBuiltins = true;
}
}

EXPECT_TRUE(defaultFoundInBuiltins)
<< "default workspace \"" << cfg.defaultWorkspaceName() << "\" not found in builtin files";
}

//! If this test fails, a new field was added to the config.
//! Please add validation for it in ConfigIsValid above, then update EXPECTED_KEYS.
TEST_P(Workspace_ConfigTests, NoUntestedConfigKeys)
{
const auto& param = GetParam();
WorkspaceTestConfig cfg;
ASSERT_TRUE(cfg.load(io::path_t(param.configFile), param.workspacesDir))
<< "failed to load: " << param.configFile;

const std::set<std::string> EXPECTED_KEYS = {
"default_workspace_name",
"builtin_workspace_files",
};

std::set<std::string> actualKeys;
for (const auto& [key, val] : cfg.config().data()) {
actualKeys.insert(key);
}

EXPECT_EQ(actualKeys, EXPECTED_KEYS)
<< "config has changed — add validation in ConfigIsValid and update EXPECTED_KEYS";
}

INSTANTIATE_TEST_SUITE_P(
Configs,
Workspace_ConfigTests,
::testing::ValuesIn(configTestParams())
);
Loading