Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b428c43
Fixed wrong and duplicated mapping name
JoergAtGithub May 25, 2024
2dc1f20
Use parametric GTest for mapping validation, instead of one test for …
JoergAtGithub May 25, 2024
2a0789b
Improved output by suppressing the hex dump of MappingInfo as parameter
JoergAtGithub May 25, 2024
c85d371
Use gtest_discover_tests instead of gtest_add to resolve the parametr…
JoergAtGithub May 25, 2024
ad6201d
Fixed QT_QPA_PLATFORM setting, which was not defined in build-check m…
JoergAtGithub May 26, 2024
a2de90e
Merge remote-tracking branch 'upstream/main' into parametricGTestForM…
JoergAtGithub May 26, 2024
207a818
Merge remote-tracking branch 'upstream/main' into parametricGTestForM…
JoergAtGithub Dec 21, 2024
71c5cbe
Removed code that tdepends on mixxxdb mixxxtest. Builds again but run…
JoergAtGithub Dec 21, 2024
914c31d
Fixed wrong and duplicated mapping name
JoergAtGithub May 25, 2024
2416567
Use parametric GTest for mapping validation, instead of one test for …
JoergAtGithub May 25, 2024
cfe169f
Improved output by suppressing the hex dump of MappingInfo as parameter
JoergAtGithub May 25, 2024
88796cd
Use gtest_discover_tests instead of gtest_add to resolve the parametr…
JoergAtGithub May 25, 2024
017bac8
Fixed QT_QPA_PLATFORM setting, which was not defined in build-check m…
JoergAtGithub May 26, 2024
9f99d01
Improve naming for parametrised mapping tests
acolombier Nov 22, 2025
13611c3
WIP: compute mapping list in CMake
acolombier Nov 23, 2025
fe03493
Merge remote-tracking branch 'upstream/2.6' into parametricGTestForMa…
JoergAtGithub Feb 8, 2026
5827d47
Set RESOURCE_FOLDER path as compile definition for mixxx-test in CMake
JoergAtGithub Feb 8, 2026
9049618
Re-add accidentally deleted setup code for QML
JoergAtGithub Feb 8, 2026
02cdcba
Fix clazy
JoergAtGithub Feb 8, 2026
e6a06d4
Fix Uncaught exception: file:///home/runner/work/mixxx/mixxx/res/cont…
JoergAtGithub Feb 8, 2026
4d55f55
Remove commented code section
JoergAtGithub Feb 9, 2026
df61ae9
Use Qt include aliases
JoergAtGithub Feb 9, 2026
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
28 changes: 28 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2823,6 +2823,10 @@ if(BUILD_TESTING)
endif()

add_executable(mixxx-test ${src-mixxx-test})
target_compile_definitions(
mixxx-test
PUBLIC RESOURCE_FOLDER="${CMAKE_CURRENT_SOURCE_DIR}/res"
)

if(QML)
target_sources(
Expand All @@ -2848,6 +2852,30 @@ if(BUILD_TESTING)
include(CTest)
include(GoogleTest)
enable_testing()

file(
GLOB_RECURSE CONTROLLER_BULK_MAPPING_LIST
"${CMAKE_CURRENT_SOURCE_DIR}/res/controllers/*.bulk.xml"
)
file(
GLOB_RECURSE CONTROLLER_HID_MAPPING_LIST
"${CMAKE_CURRENT_SOURCE_DIR}/res/controllers/*.hid.xml"
)
file(
GLOB_RECURSE CONTROLLER_MIDI_MAPPING_LIST
"${CMAKE_CURRENT_SOURCE_DIR}/res/controllers/*.midi.xml"
)
list(JOIN CONTROLLER_BULK_MAPPING_LIST "\",\"" CONTROLLER_BULK_MAPPINGS)
list(JOIN CONTROLLER_HID_MAPPING_LIST "\",\"" CONTROLLER_HID_MAPPINGS)
list(JOIN CONTROLLER_MIDI_MAPPING_LIST "\",\"" CONTROLLER_MIDI_MAPPINGS)

target_compile_definitions(
mixxx-test
PUBLIC CONTROLLER_BULK_MAPPINGS="${CONTROLLER_BULK_MAPPINGS}"
PUBLIC CONTROLLER_HID_MAPPINGS="${CONTROLLER_HID_MAPPINGS}"
PUBLIC CONTROLLER_MIDI_MAPPINGS="${CONTROLLER_MIDI_MAPPINGS}"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DO we need to make the above conditional to HID, and BULK?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the simplicity of the code is of more value than skiping 1 or 2 regular expressions during CMake configuration.

gtest_discover_tests(
mixxx-test
EXTRA_ARGS --logLevel info
Expand Down
8 changes: 6 additions & 2 deletions res/controllers/midi-components-0.0.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,18 @@
disconnect: function() {
if (this.connections[0] !== undefined) {
this.connections.forEach(function(conn) {
conn.disconnect();
if (conn !== undefined) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an expected usecase? It does makes sense in the case of testing due to missing CO, but I assume that connections should only contain valid connections, else it would indicate a problem.
Should we add a console.warn to flag potentially failed connection?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detailed warnings are already implemented in engine.makeConnection:

if (coScript == nullptr) {
// The test setups do not run all of Mixxx, so ControlObjects not
// existing during tests is okay.
if (!m_pScriptEngineLegacy->isTesting()) {
m_pScriptEngineLegacy->logOrThrowError(
QStringLiteral("script tried to connect to ControlObject "
"(%1, %2) which is non-existent.")
.arg(group, name));
}
return QJSValue();
}
if (!callback.isCallable()) {
m_pScriptEngineLegacy->logOrThrowError(QStringLiteral(
"Tried to connect (%1, %2) to an invalid callback. Make sure "

But after the warning engine.makeConnection returns undefined and the script continues.

conn.disconnect();
}
});
}
},
trigger: function() {
if (this.connections[0] !== undefined) {
this.connections.forEach(function(conn) {
conn.trigger();
if (conn !== undefined) {
conn.trigger();
}
});
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class Controller : public QObject {
// accesses lots of our stuff, but in the same thread
friend class ControllerManager;
// For testing
friend class LegacyControllerMappingValidationTest;
friend class MappingTestFixture;
friend class MidiControllerTest;
};

Expand Down
89 changes: 51 additions & 38 deletions src/test/controller_mapping_validation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <QApplication>
#include <QRegularExpression>
#include <QUrl>

#include "controllers/defs_controllers.h"
Expand All @@ -20,6 +22,10 @@
#endif
#include "moc_controller_mapping_validation_test.cpp"

namespace {
const QRegularExpression kNonWordPattern(QStringLiteral("[^\\w]+"));
}

FakeMidiControllerJSProxy::FakeMidiControllerJSProxy()
: ControllerJSProxy(nullptr) {
}
Expand Down Expand Up @@ -115,9 +121,12 @@ FakeController::~FakeController() {
bool FakeController::isMappable() const {
if (m_bMidiMapping) {
return m_pMidiMapping->isMappable();
} else if (m_bHidMapping) {
}
#ifdef __HID__
else if (m_bHidMapping) {
return m_pHidMapping->isMappable();
}
#endif
return false;
}

Expand All @@ -129,9 +138,7 @@ void deleteTrack(Track* pTrack) {
};
#endif

void LegacyControllerMappingValidationTest::SetUp() {
m_mappingPath = getTestDir().filePath(QStringLiteral("../../res/controllers/"));
m_pEnumerator.reset(new MappingInfoEnumerator(QList<QString>{m_mappingPath.absolutePath()}));
void MappingTestFixture::SetUp() {
#ifdef MIXXX_USE_QML
// This setup mirrors coreservices -- it would be nice if we could use coreservices instead
// but it does a lot of local disk / settings setup.
Expand Down Expand Up @@ -179,27 +186,30 @@ void LegacyControllerMappingValidationTest::SetUp() {
m_pPlayerManager->bindToLibrary(m_pLibrary.get());
mixxx::qml::QmlPlayerManagerProxy::registerPlayerManager(m_pPlayerManager);
ControllerScriptEngineBase::registerTrackCollectionManager(m_pTrackCollectionManager);
#endif
}

void LegacyControllerMappingValidationTest::TearDown() {
void MappingTestFixture::TearDown() {
#ifdef MIXXX_USE_QML
// Clean up in reverse order of initialization
PlayerInfo::destroy();
CoverArtCache::destroy();
mixxx::qml::QmlPlayerManagerProxy::registerPlayerManager(nullptr);
ControllerScriptEngineBase::registerTrackCollectionManager(nullptr);
#endif
}

bool LegacyControllerMappingValidationTest::testLoadMapping(const MappingInfo& mapping) {
bool MappingTestFixture::testLoadMapping(const QString& mappingPath) {
std::shared_ptr<LegacyControllerMapping> pMapping =
LegacyControllerMappingFileHandler::loadMapping(
QFileInfo(mapping.getPath()), m_mappingPath);
QFileInfo(mappingPath), QDir(RESOURCE_FOLDER "/controllers"));
if (!pMapping) {
return false;
}

FakeController controller;
controller.setMapping(pMapping);
bool result = controller.applyMapping(getTestDir().filePath(QStringLiteral("../../res")));
bool result = controller.applyMapping(getTestDir().filePath(RESOURCE_FOLDER));
controller.stopEngine();
return result;
}
Expand Down Expand Up @@ -239,39 +249,42 @@ bool lintMappingInfo(const MappingInfo& mapping) {
return result;
}

TEST_F(LegacyControllerMappingValidationTest, MidiMappingsValid) {
foreach (const MappingInfo& mapping,
m_pEnumerator->getMappingsByExtension(MIDI_MAPPING_EXTENSION)) {
qDebug() << "Validating " << mapping.getPath();
std::string errorDescription = "Error while validating " + mapping.getPath().toStdString();
EXPECT_TRUE(mapping.isValid()) << errorDescription;
EXPECT_TRUE(lintMappingInfo(mapping)) << errorDescription;
EXPECT_TRUE(testLoadMapping(mapping)) << errorDescription;
}
std::string PrintMappingName(const ::testing::TestParamInfo<std::string>& info) {
auto name = QFileInfo(QString::fromStdString(info.param));
return name.fileName().replace(kNonWordPattern, "_").toStdString();
}

#ifdef __HID__
TEST_F(LegacyControllerMappingValidationTest, HidMappingsValid) {
foreach (const MappingInfo& mapping,
m_pEnumerator->getMappingsByExtension(HID_MAPPING_EXTENSION)) {
qDebug() << "Validating" << mapping.getPath();
std::string errorDescription = "Error while validating " + mapping.getPath().toStdString();
EXPECT_TRUE(mapping.isValid()) << errorDescription;
EXPECT_TRUE(lintMappingInfo(mapping)) << errorDescription;
EXPECT_TRUE(testLoadMapping(mapping)) << errorDescription;
}
TEST_P(MappingTestFixture, ValidateMappingXML) {
QString mappingPath = QString::fromStdString(GetParam());
qDebug() << "ValidateMappingXML" << mappingPath;

MappingInfo mapping(mappingPath);
EXPECT_TRUE(mapping.isValid()) << "Error while validating XML file " << GetParam();
EXPECT_TRUE(lintMappingInfo(mapping)) << "Error while validating XML file " << GetParam();
}
#endif

#ifdef __BULK__
TEST_F(LegacyControllerMappingValidationTest, BulkMappingsValid) {
foreach (const MappingInfo& mapping,
m_pEnumerator->getMappingsByExtension(BULK_MAPPING_EXTENSION)) {
qDebug() << "Validating" << mapping.getPath();
std::string errorDescription = "Error while validating " + mapping.getPath().toStdString();
EXPECT_TRUE(mapping.isValid()) << errorDescription;
EXPECT_TRUE(lintMappingInfo(mapping)) << errorDescription;
EXPECT_TRUE(testLoadMapping(mapping)) << errorDescription;
}
TEST_P(MappingTestFixture, LoadMapping) {
QString mappingPath = QString::fromStdString(GetParam());
qDebug() << "LoadMapping" << mappingPath;

EXPECT_TRUE(testLoadMapping(mappingPath)) << "Error while loading " << GetParam();
}

#ifdef __BULK__
INSTANTIATE_TEST_SUITE_P(BulkMappings,
MappingTestFixture,
::testing::Values(CONTROLLER_BULK_MAPPINGS),
PrintMappingName);
#endif

#ifdef __HID__
INSTANTIATE_TEST_SUITE_P(HidMappings,
MappingTestFixture,
::testing::Values(CONTROLLER_HID_MAPPINGS),
PrintMappingName);
#endif

INSTANTIATE_TEST_SUITE_P(MidiMappings,
MappingTestFixture,
::testing::Values(CONTROLLER_MIDI_MAPPINGS),
PrintMappingName);
15 changes: 8 additions & 7 deletions src/test/controller_mapping_validation_test.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <QObject>
#include <QtGlobal>

#include "control/controlindicatortimer.h"
#include "controllers/controller.h"
Expand Down Expand Up @@ -214,16 +215,19 @@ class PlayerManager;

// We can't inherit from LibraryTest because that creates a key_notation control object that is also
// created by the Library object itself. The duplicated CO creation causes a debug assert.
class LegacyControllerMappingValidationTest : public MixxxDbTest, SoundSourceProviderRegistration {
class MappingTestFixture
: public MixxxDbTest,
SoundSourceProviderRegistration,
public ::testing::WithParamInterface<std::string> {
public:
LegacyControllerMappingValidationTest()
MappingTestFixture()
: MixxxDbTest(true) {
}

protected:
void SetUp() override;
#ifdef MIXXX_USE_QML
void TearDown() override;
#ifdef MIXXX_USE_QML

TrackPointer getOrAddTrackByLocation(
const QString& trackLocation) const {
Expand All @@ -241,8 +245,5 @@ class LegacyControllerMappingValidationTest : public MixxxDbTest, SoundSourcePro
std::shared_ptr<Library> m_pLibrary;
#endif

bool testLoadMapping(const MappingInfo& mapping);

QDir m_mappingPath;
QScopedPointer<MappingInfoEnumerator> m_pEnumerator;
bool testLoadMapping(const QString& mapping);
};
Loading