1 #include <gtest/gtest.h>
2
3 #include <QDir>
4 #include <QUrl>
5 #include <QScopedPointer>
6 #include <QtDebug>
7
8 #include "controllers/controller.h"
9 #include "controllers/controllerpresetfilehandler.h"
10 #include "controllers/controllerpresetinfoenumerator.h"
11 #include "controllers/midi/midicontrollerpreset.h"
12 #include "controllers/hid/hidcontrollerpreset.h"
13 #include "controllers/defs_controllers.h"
14 #include "test/mixxxtest.h"
15
16 class FakeController : public Controller {
17 public:
18 explicit FakeController(UserSettingsPointer pConfig);
19 ~FakeController() override;
20
presetExtension()21 QString presetExtension() override {
22 // Doesn't affect anything at the moment.
23 return ".test.xml";
24 }
25
getPreset() const26 ControllerPresetPointer getPreset() const override {
27 if (m_bHidPreset) {
28 HidControllerPreset* pClone = new HidControllerPreset();
29 *pClone = m_hidPreset;
30 return ControllerPresetPointer(pClone);
31 } else {
32 MidiControllerPreset* pClone = new MidiControllerPreset();
33 *pClone = m_midiPreset;
34 return ControllerPresetPointer(pClone);
35 }
36 }
37
visit(const MidiControllerPreset * preset)38 void visit(const MidiControllerPreset* preset) override {
39 m_bMidiPreset = true;
40 m_bHidPreset = false;
41 m_midiPreset = *preset;
42 m_hidPreset = HidControllerPreset();
43 }
visit(const HidControllerPreset * preset)44 void visit(const HidControllerPreset* preset) override {
45 m_bMidiPreset = false;
46 m_bHidPreset = true;
47 m_midiPreset = MidiControllerPreset();
48 m_hidPreset = *preset;
49 }
50
accept(ControllerVisitor * visitor)51 void accept(ControllerVisitor* visitor) override {
52 // Do nothing since we aren't a normal controller.
53 Q_UNUSED(visitor);
54 }
55
isMappable() const56 bool isMappable() const override {
57 if (m_bMidiPreset) {
58 return m_midiPreset.isMappable();
59 } else if (m_bHidPreset) {
60 return m_hidPreset.isMappable();
61 }
62 return false;
63 }
64
matchPreset(const PresetInfo & preset)65 bool matchPreset(const PresetInfo& preset) override {
66 // We're not testing product info matching in this test.
67 Q_UNUSED(preset);
68 return false;
69 }
70
71 protected:
send(const QList<int> & data,unsigned int length,unsigned int reportID)72 Q_INVOKABLE void send(const QList<int>& data, unsigned int length, unsigned int reportID) {
73 Q_UNUSED(data);
74 Q_UNUSED(length);
75 Q_UNUSED(reportID);
76 }
77
78 private slots:
open()79 int open() override {
80 return 0;
81 }
close()82 int close() override {
83 return 0;
84 }
85
86 private:
send(const QByteArray & data)87 void send(const QByteArray& data) override {
88 Q_UNUSED(data);
89 }
send(const QByteArray & data,unsigned int reportID)90 virtual void send(const QByteArray& data, unsigned int reportID) {
91 Q_UNUSED(data);
92 Q_UNUSED(reportID);
93 }
94
preset()95 ControllerPreset* preset() override {
96 if (m_bHidPreset) {
97 return &m_hidPreset;
98 } else {
99 // Default to MIDI.
100 return &m_midiPreset;
101 }
102 }
103
104 bool m_bMidiPreset;
105 bool m_bHidPreset;
106 MidiControllerPreset m_midiPreset;
107 HidControllerPreset m_hidPreset;
108 };
109
FakeController(UserSettingsPointer pConfig)110 FakeController::FakeController(UserSettingsPointer pConfig)
111 : Controller(pConfig), m_bMidiPreset(false), m_bHidPreset(false) {
112 }
113
~FakeController()114 FakeController::~FakeController() {
115 }
116
117 class ControllerPresetValidationTest : public MixxxTest {
118 protected:
SetUp()119 void SetUp() override {
120 m_presetPath = QDir::current();
121 m_presetPath.cd("res/controllers");
122 m_pEnumerator.reset(new PresetInfoEnumerator(QList<QString>{m_presetPath.absolutePath()}));
123 }
124
testLoadPreset(const PresetInfo & preset)125 bool testLoadPreset(const PresetInfo& preset) {
126 ControllerPresetPointer pPreset =
127 ControllerPresetFileHandler::loadPreset(
128 preset.getPath(),
129 m_presetPath);
130 if (pPreset.isNull()) {
131 return false;
132 }
133
134 FakeController controller(config());
135 controller.setDeviceName("Test Controller");
136 controller.startEngine();
137 controller.setPreset(*pPreset);
138 // Do not initialize the scripts.
139 bool result = controller.applyPreset(false);
140 controller.stopEngine();
141 return result;
142 }
143
144 QDir m_presetPath;
145 QScopedPointer<PresetInfoEnumerator> m_pEnumerator;
146 };
147
checkUrl(const QString & url)148 bool checkUrl(const QString& url) {
149 return QUrl(url).isValid();
150 }
151
lintPresetInfo(const PresetInfo & preset)152 bool lintPresetInfo(const PresetInfo& preset) {
153 bool result = true;
154 if (preset.getName().trimmed().isEmpty()) {
155 qWarning() << "LINT:" << preset.getPath() << "has no name.";
156 result = false;
157 }
158
159 if (preset.getAuthor().trimmed().isEmpty()) {
160 qWarning() << "LINT:" << preset.getPath() << "has no author.";
161 }
162
163 if (preset.getDescription().trimmed().isEmpty()) {
164 qWarning() << "LINT:" << preset.getPath() << "has no description.";
165 }
166
167 if (preset.getForumLink().trimmed().isEmpty()) {
168 qWarning() << "LINT:" << preset.getPath() << "has no forum link.";
169 } else if (!checkUrl(preset.getForumLink())) {
170 qWarning() << "LINT:" << preset.getPath() << "has invalid forum link";
171 result = false;
172 }
173
174 if (preset.getWikiLink().trimmed().isEmpty()) {
175 qWarning() << "LINT:" << preset.getPath() << "has no wiki link.";
176 } else if (!checkUrl(preset.getWikiLink())) {
177 qWarning() << "LINT:" << preset.getPath() << "has invalid wiki link";
178 result = false;
179 }
180 return result;
181 }
182
TEST_F(ControllerPresetValidationTest,MidiPresetsValid)183 TEST_F(ControllerPresetValidationTest, MidiPresetsValid) {
184 foreach (const PresetInfo& preset,
185 m_pEnumerator->getPresetsByExtension(MIDI_PRESET_EXTENSION)) {
186 qDebug() << "Validating" << preset.getPath();
187 EXPECT_TRUE(preset.isValid());
188 EXPECT_TRUE(lintPresetInfo(preset));
189 EXPECT_TRUE(testLoadPreset(preset));
190 }
191 }
192
TEST_F(ControllerPresetValidationTest,HidPresetsValid)193 TEST_F(ControllerPresetValidationTest, HidPresetsValid) {
194 foreach (const PresetInfo& preset,
195 m_pEnumerator->getPresetsByExtension(HID_PRESET_EXTENSION)) {
196 qDebug() << "Validating" << preset.getPath();
197 EXPECT_TRUE(preset.isValid());
198 EXPECT_TRUE(lintPresetInfo(preset));
199 EXPECT_TRUE(testLoadPreset(preset));
200 }
201 }
202
TEST_F(ControllerPresetValidationTest,BulkPresetsValid)203 TEST_F(ControllerPresetValidationTest, BulkPresetsValid) {
204 foreach (const PresetInfo& preset,
205 m_pEnumerator->getPresetsByExtension(BULK_PRESET_EXTENSION)) {
206 qDebug() << "Validating" << preset.getPath();
207 EXPECT_TRUE(preset.isValid());
208 EXPECT_TRUE(lintPresetInfo(preset));
209 EXPECT_TRUE(testLoadPreset(preset));
210 }
211 }
212