1/*
2 * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#include "mediaplayertest.h"
8#include "autotests.h"
9#include "initmanagerjob.h"
10#include "pendingcall.h"
11#include "services.h"
12
13#include <QSignalSpy>
14#include <QTest>
15
16namespace BluezQt
17{
18extern void bluezqt_initFakeBluezTestRun();
19}
20
21using namespace BluezQt;
22
23Q_DECLARE_METATYPE(MediaPlayer::Equalizer)
24Q_DECLARE_METATYPE(MediaPlayer::Repeat)
25Q_DECLARE_METATYPE(MediaPlayer::Shuffle)
26Q_DECLARE_METATYPE(MediaPlayer::Status)
27
28MediaPlayerTest::MediaPlayerTest()
29 : m_manager(nullptr)
30{
31 Autotests::registerMetatypes();
32
33 qRegisterMetaType<MediaPlayer::Equalizer>("Equalizer");
34 qRegisterMetaType<MediaPlayer::Repeat>("Repeat");
35 qRegisterMetaType<MediaPlayer::Shuffle>("Shuffle");
36 qRegisterMetaType<MediaPlayer::Status>("Status");
37 qRegisterMetaType<MediaPlayerTrack>("MediaPlayerTrack");
38}
39
40void MediaPlayerTest::initTestCase()
41{
42 bluezqt_initFakeBluezTestRun();
43
44 FakeBluez::start();
45 FakeBluez::runTest(QStringLiteral("bluez-standard"));
46
47 // Create adapter
48 QString adapter = QStringLiteral("/org/bluez/hci0");
49 QVariantMap adapterProps;
50 adapterProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(adapter));
51 adapterProps[QStringLiteral("Address")] = QStringLiteral("1C:E5:C3:BC:94:7E");
52 adapterProps[QStringLiteral("Name")] = QStringLiteral("TestAdapter");
53 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-adapter"), adapterProps);
54
55 // Create devices
56 QVariantMap deviceProps;
57 QVariantMap mediaPlayerProps;
58 QVariantMap trackProps;
59
60 QString device1 = adapter + QLatin1String("/dev_40_79_6A_0C_39_75");
61 deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device1));
62 deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(QDBusObjectPath(adapter));
63 deviceProps[QStringLiteral("Address")] = QStringLiteral("40:79:6A:0C:39:75");
64 deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice");
65 deviceProps[QStringLiteral("UUIDs")] = QStringList(QStringLiteral("0000110E-0000-1000-8000-00805F9B34FB"));
66 mediaPlayerProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device1 + QLatin1String("/player0")));
67 mediaPlayerProps[QStringLiteral("Name")] = QStringLiteral("Player1");
68 mediaPlayerProps[QStringLiteral("Equalizer")] = QStringLiteral("on");
69 mediaPlayerProps[QStringLiteral("Repeat")] = QStringLiteral("singletrack");
70 mediaPlayerProps[QStringLiteral("Shuffle")] = QStringLiteral("group");
71 mediaPlayerProps[QStringLiteral("Status")] = QStringLiteral("stopped");
72 mediaPlayerProps[QStringLiteral("Position")] = QVariant::fromValue(quint32(150));
73 mediaPlayerProps[QStringLiteral("Device")] = QVariant::fromValue(QDBusObjectPath(device1));
74 trackProps[QStringLiteral("Title")] = QStringLiteral("Song1");
75 trackProps[QStringLiteral("Artist")] = QStringLiteral("Band1");
76 trackProps[QStringLiteral("Album")] = QStringLiteral("First Album");
77 trackProps[QStringLiteral("Genre")] = QStringLiteral("Rock");
78 trackProps[QStringLiteral("NumberOfTracks")] = 24;
79 trackProps[QStringLiteral("TrackNumber")] = 4;
80 trackProps[QStringLiteral("Duration")] = 12403;
81 mediaPlayerProps[QStringLiteral("Track")] = trackProps;
82 deviceProps[QStringLiteral("MediaPlayer")] = mediaPlayerProps;
83 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
84
85 QString device2 = adapter + QLatin1String("/dev_50_79_6A_0C_39_75");
86 deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device2));
87 deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(QDBusObjectPath(adapter));
88 deviceProps[QStringLiteral("Address")] = QStringLiteral("50:79:6A:0C:39:75");
89 deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice2");
90 deviceProps[QStringLiteral("UUIDs")] = QStringList(QStringLiteral("0000110E-0000-1000-8000-00805F9B34FB"));
91 mediaPlayerProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device2 + QLatin1String("/player0")));
92 mediaPlayerProps[QStringLiteral("Name")] = QStringLiteral("Player2");
93 mediaPlayerProps[QStringLiteral("Equalizer")] = QStringLiteral("off");
94 mediaPlayerProps[QStringLiteral("Repeat")] = QStringLiteral("alltracks");
95 mediaPlayerProps[QStringLiteral("Shuffle")] = QStringLiteral("off");
96 mediaPlayerProps[QStringLiteral("Status")] = QStringLiteral("paused");
97 mediaPlayerProps[QStringLiteral("Position")] = QVariant::fromValue(quint32(2500));
98 mediaPlayerProps[QStringLiteral("Device")] = QVariant::fromValue(QDBusObjectPath(device2));
99 trackProps[QStringLiteral("Title")] = QStringLiteral("Song2");
100 trackProps[QStringLiteral("Artist")] = QStringLiteral("Band2");
101 trackProps[QStringLiteral("Album")] = QStringLiteral("Second Album");
102 trackProps[QStringLiteral("Genre")] = QStringLiteral("Heavy Metal");
103 trackProps[QStringLiteral("NumberOfTracks")] = 666;
104 trackProps[QStringLiteral("TrackNumber")] = 22;
105 trackProps[QStringLiteral("Duration")] = 22403;
106 mediaPlayerProps[QStringLiteral("Track")] = trackProps;
107 deviceProps[QStringLiteral("MediaPlayer")] = mediaPlayerProps;
108 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
109
110 m_manager = new Manager();
111 InitManagerJob *initJob = m_manager->init();
112 initJob->exec();
113 QVERIFY(!initJob->error());
114
115 QCOMPARE(m_manager->adapters().count(), 1);
116 QCOMPARE(m_manager->devices().count(), 2);
117}
118
119void MediaPlayerTest::cleanupTestCase()
120{
121 for (const MediaPlayerUnit &unit : m_units) {
122 delete unit.dbusMediaPlayer;
123 delete unit.dbusProperties;
124 }
125
126 delete m_manager;
127
128 FakeBluez::stop();
129}
130
131void MediaPlayerTest::connectTest()
132{
133 for (DevicePtr device : m_manager->devices()) {
134 QVERIFY(!device->ubi().isEmpty());
135 QVERIFY(!device->mediaPlayer());
136
137 QSignalSpy deviceSpy(device.data(), SIGNAL(mediaPlayerChanged(MediaPlayerPtr)));
138
139 device->connectToDevice();
140 QTRY_COMPARE(deviceSpy.count(), 1);
141 QVERIFY(device->mediaPlayer());
142 }
143}
144
145void MediaPlayerTest::disconnectTest()
146{
147 for (DevicePtr device : m_manager->devices()) {
148 QVERIFY(device->mediaPlayer());
149
150 QSignalSpy deviceSpy(device.data(), SIGNAL(mediaPlayerChanged(MediaPlayerPtr)));
151
152 device->disconnectFromDevice();
153 QTRY_COMPARE(deviceSpy.count(), 1);
154 QVERIFY(!device->mediaPlayer());
155 }
156}
157
158void MediaPlayerTest::connectProfileTest()
159{
160 QDBusConnection connection = QDBusConnection::sessionBus();
161 QString service = QStringLiteral("org.kde.bluezqt.fakebluez");
162
163 for (DevicePtr device : m_manager->devices()) {
164 QVERIFY(!device->ubi().isEmpty());
165 QVERIFY(!device->mediaPlayer());
166
167 QSignalSpy deviceSpy(device.data(), SIGNAL(mediaPlayerChanged(MediaPlayerPtr)));
168
169 device->connectProfile(Services::AudioVideoRemoteControl);
170 QTRY_COMPARE(deviceSpy.count(), 1);
171 QVERIFY(device->mediaPlayer());
172
173 QString path = device->ubi() + QLatin1String("/player0");
174
175 MediaPlayerUnit u;
176 u.device = device;
177 u.dbusMediaPlayer = new org::bluez::MediaPlayer1(service, path, connection, this);
178 u.dbusProperties = new org::freedesktop::DBus::Properties(service, path, connection, this);
179 m_units.append(u);
180 }
181}
182
183void MediaPlayerTest::getPropertiesTest()
184{
185 for (const MediaPlayerUnit &unit : m_units) {
186 QCOMPARE(unit.device->mediaPlayer()->name(), unit.dbusMediaPlayer->name());
187 QCOMPARE(equalizerString(unit.device->mediaPlayer()), unit.dbusMediaPlayer->equalizer());
188 QCOMPARE(repeatString(unit.device->mediaPlayer()), unit.dbusMediaPlayer->repeat());
189 QCOMPARE(shuffleString(unit.device->mediaPlayer()), unit.dbusMediaPlayer->shuffle());
190 QCOMPARE(statusString(unit.device->mediaPlayer()), unit.dbusMediaPlayer->status());
191 QCOMPARE(trackMap(unit.device->mediaPlayer()), unit.dbusMediaPlayer->track());
192 QCOMPARE(unit.device->mediaPlayer()->position(), unit.dbusMediaPlayer->position());
193 }
194}
195
196void MediaPlayerTest::setEqualizerTest()
197{
198 for (const MediaPlayerUnit &unit : m_units) {
199 MediaPlayerPtr mediaPlayer = unit.device->mediaPlayer();
200 MediaPlayer::Equalizer value = mediaPlayer->equalizer() == MediaPlayer::EqualizerOff ? MediaPlayer::EqualizerOn : MediaPlayer::EqualizerOff;
201
202 QSignalSpy equalizerSpy(mediaPlayer.data(), SIGNAL(equalizerChanged(Equalizer)));
203
204 mediaPlayer->setEqualizer(value);
205 QTRY_COMPARE(equalizerSpy.count(), 1);
206 QCOMPARE(equalizerSpy.at(0).at(0).value<MediaPlayer::Equalizer>(), value);
207 QCOMPARE(mediaPlayer->equalizer(), value);
208 }
209}
210
211void MediaPlayerTest::setRepeatTest()
212{
213 for (const MediaPlayerUnit &unit : m_units) {
214 MediaPlayerPtr mediaPlayer = unit.device->mediaPlayer();
215 MediaPlayer::Repeat value = mediaPlayer->repeat() == MediaPlayer::RepeatGroup ? MediaPlayer::RepeatSingleTrack : MediaPlayer::RepeatGroup;
216
217 QSignalSpy equalizerSpy(mediaPlayer.data(), SIGNAL(repeatChanged(Repeat)));
218
219 mediaPlayer->setRepeat(value);
220 QTRY_COMPARE(equalizerSpy.count(), 1);
221 QCOMPARE(equalizerSpy.at(0).at(0).value<MediaPlayer::Repeat>(), value);
222 QCOMPARE(mediaPlayer->repeat(), value);
223 }
224}
225
226void MediaPlayerTest::setShuffleTest()
227{
228 for (const MediaPlayerUnit &unit : m_units) {
229 MediaPlayerPtr mediaPlayer = unit.device->mediaPlayer();
230 MediaPlayer::Shuffle value = mediaPlayer->shuffle() == MediaPlayer::ShuffleAllTracks ? MediaPlayer::ShuffleOff : MediaPlayer::ShuffleAllTracks;
231
232 QSignalSpy equalizerSpy(mediaPlayer.data(), SIGNAL(shuffleChanged(Shuffle)));
233
234 mediaPlayer->setShuffle(value);
235 QTRY_COMPARE(equalizerSpy.count(), 1);
236 QCOMPARE(equalizerSpy.at(0).at(0).value<MediaPlayer::Shuffle>(), value);
237 QCOMPARE(mediaPlayer->shuffle(), value);
238 }
239}
240
241void MediaPlayerTest::changeStatusTest()
242{
243 for (const MediaPlayerUnit &unit : m_units) {
244 MediaPlayerPtr mediaPlayer = unit.device->mediaPlayer();
245
246 QSignalSpy statusSpy(mediaPlayer.data(), SIGNAL(statusChanged(Status)));
247
248 if (mediaPlayer->status() != MediaPlayer::Stopped) {
249 mediaPlayer->stop();
250 QTRY_COMPARE(statusSpy.count(), 1);
251 QCOMPARE(statusSpy.at(0).at(0).value<MediaPlayer::Status>(), MediaPlayer::Stopped);
252 QCOMPARE(mediaPlayer->status(), MediaPlayer::Stopped);
253 }
254
255 statusSpy.clear();
256 mediaPlayer->play();
257 QTRY_COMPARE(statusSpy.count(), 1);
258 QCOMPARE(statusSpy.at(0).at(0).value<MediaPlayer::Status>(), MediaPlayer::Playing);
259 QCOMPARE(mediaPlayer->status(), MediaPlayer::Playing);
260
261 statusSpy.clear();
262 mediaPlayer->pause();
263 QTRY_COMPARE(statusSpy.count(), 1);
264 QCOMPARE(statusSpy.at(0).at(0).value<MediaPlayer::Status>(), MediaPlayer::Paused);
265 QCOMPARE(mediaPlayer->status(), MediaPlayer::Paused);
266
267 statusSpy.clear();
268 mediaPlayer->fastForward();
269 QTRY_COMPARE(statusSpy.count(), 1);
270 QCOMPARE(statusSpy.at(0).at(0).value<MediaPlayer::Status>(), MediaPlayer::ForwardSeek);
271 QCOMPARE(mediaPlayer->status(), MediaPlayer::ForwardSeek);
272
273 statusSpy.clear();
274 mediaPlayer->rewind();
275 QTRY_COMPARE(statusSpy.count(), 1);
276 QCOMPARE(statusSpy.at(0).at(0).value<MediaPlayer::Status>(), MediaPlayer::ReverseSeek);
277 QCOMPARE(mediaPlayer->status(), MediaPlayer::ReverseSeek);
278
279 statusSpy.clear();
280 mediaPlayer->stop();
281 QTRY_COMPARE(statusSpy.count(), 1);
282 QCOMPARE(statusSpy.at(0).at(0).value<MediaPlayer::Status>(), MediaPlayer::Stopped);
283 QCOMPARE(mediaPlayer->status(), MediaPlayer::Stopped);
284 }
285}
286
287void MediaPlayerTest::changeTrackTest()
288{
289 for (const MediaPlayerUnit &unit : m_units) {
290 MediaPlayerPtr mediaPlayer = unit.device->mediaPlayer();
291
292 QSignalSpy trackSpy(mediaPlayer.data(), SIGNAL(trackChanged(MediaPlayerTrack)));
293
294 trackSpy.clear();
295 mediaPlayer->next();
296 QTRY_COMPARE(trackSpy.count(), 1);
297 QCOMPARE(mediaPlayer->track().isValid(), true);
298
299 trackSpy.clear();
300 mediaPlayer->previous();
301 QTRY_COMPARE(trackSpy.count(), 1);
302 QCOMPARE(mediaPlayer->track().isValid(), true);
303 }
304}
305
306void MediaPlayerTest::disconnectProfileTest()
307{
308 for (const MediaPlayerUnit &unit : m_units) {
309 QVERIFY(unit.device->mediaPlayer());
310
311 QSignalSpy deviceSpy(unit.device.data(), SIGNAL(mediaPlayerChanged(MediaPlayerPtr)));
312
313 unit.device->disconnectProfile(Services::AudioVideoRemoteControl);
314 QTRY_COMPARE(deviceSpy.count(), 1);
315 QVERIFY(!unit.device->mediaPlayer());
316 }
317}
318
319void MediaPlayerTest::bug403289()
320{
321 // Bug 403289: MediaPlayer interface path is not checked in InterfacesRemoved signal
322
323 QDBusConnection connection = QDBusConnection::sessionBus();
324 QString service = QStringLiteral("org.kde.bluezqt.fakebluez");
325
326 for (DevicePtr device : m_manager->devices()) {
327 QVERIFY(!device->mediaPlayer());
328
329 QSignalSpy deviceSpy(device.data(), SIGNAL(mediaPlayerChanged(MediaPlayerPtr)));
330
331 const QVariantMap props = {{QStringLiteral("DevicePath"), QVariant::fromValue(QDBusObjectPath(device->ubi()))}};
332 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("bug403289"), props);
333
334 QTRY_COMPARE(deviceSpy.count(), 1);
335 QVERIFY(deviceSpy.at(0).at(0).value<MediaPlayerPtr>());
336 QTest::qWait(100);
337 QCOMPARE(deviceSpy.count(), 1);
338 device->disconnectProfile(Services::AudioVideoRemoteControl);
339 QTRY_COMPARE(deviceSpy.count(), 2);
340 QVERIFY(!deviceSpy.at(1).at(0).value<MediaPlayerPtr>());
341 }
342}
343
344QString MediaPlayerTest::equalizerString(const MediaPlayerPtr &mediaPlayer) const
345{
346 switch (mediaPlayer->equalizer()) {
347 case MediaPlayer::EqualizerOn:
348 return QStringLiteral("on");
349 default:
350 return QStringLiteral("off");
351 }
352}
353
354QString MediaPlayerTest::repeatString(const MediaPlayerPtr &mediaPlayer) const
355{
356 switch (mediaPlayer->repeat()) {
357 case MediaPlayer::RepeatSingleTrack:
358 return QStringLiteral("singletrack");
359 case MediaPlayer::RepeatAllTracks:
360 return QStringLiteral("alltracks");
361 case MediaPlayer::RepeatGroup:
362 return QStringLiteral("group");
363 default:
364 return QStringLiteral("off");
365 }
366}
367
368QString MediaPlayerTest::shuffleString(const MediaPlayerPtr &mediaPlayer) const
369{
370 switch (mediaPlayer->shuffle()) {
371 case MediaPlayer::ShuffleAllTracks:
372 return QStringLiteral("alltracks");
373 case MediaPlayer::ShuffleGroup:
374 return QStringLiteral("group");
375 default:
376 return QStringLiteral("off");
377 }
378}
379
380QString MediaPlayerTest::statusString(const MediaPlayerPtr &mediaPlayer) const
381{
382 switch (mediaPlayer->status()) {
383 case MediaPlayer::Playing:
384 return QStringLiteral("playing");
385 case MediaPlayer::Stopped:
386 return QStringLiteral("stopped");
387 case MediaPlayer::Paused:
388 return QStringLiteral("paused");
389 case MediaPlayer::ForwardSeek:
390 return QStringLiteral("forward-seek");
391 case MediaPlayer::ReverseSeek:
392 return QStringLiteral("reverse-seek");
393 default:
394 return QStringLiteral("error");
395 }
396}
397
398QVariantMap MediaPlayerTest::trackMap(const MediaPlayerPtr &mediaPlayer) const
399{
400 QVariantMap out;
401
402 if (!mediaPlayer->track().isValid()) {
403 return out;
404 }
405
406 out[QStringLiteral("Title")] = mediaPlayer->track().title();
407 out[QStringLiteral("Artist")] = mediaPlayer->track().artist();
408 out[QStringLiteral("Album")] = mediaPlayer->track().album();
409 out[QStringLiteral("Genre")] = mediaPlayer->track().genre();
410 out[QStringLiteral("NumberOfTracks")] = mediaPlayer->track().numberOfTracks();
411 out[QStringLiteral("TrackNumber")] = mediaPlayer->track().trackNumber();
412 out[QStringLiteral("Duration")] = mediaPlayer->track().duration();
413
414 return out;
415}
416
417QTEST_MAIN(MediaPlayerTest)
418
419#include "moc_mediaplayertest.cpp"
420

source code of bluez-qt/autotests/mediaplayertest.cpp