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 | |
16 | namespace BluezQt |
17 | { |
18 | extern void bluezqt_initFakeBluezTestRun(); |
19 | } |
20 | |
21 | using namespace BluezQt; |
22 | |
23 | Q_DECLARE_METATYPE(MediaPlayer::Equalizer) |
24 | Q_DECLARE_METATYPE(MediaPlayer::Repeat) |
25 | Q_DECLARE_METATYPE(MediaPlayer::Shuffle) |
26 | Q_DECLARE_METATYPE(MediaPlayer::Status) |
27 | |
28 | MediaPlayerTest::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 | |
40 | void 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 | |
119 | void 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 | |
131 | void 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 | |
145 | void 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 | |
158 | void 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 | |
183 | void 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 | |
196 | void 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 | |
211 | void 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 | |
226 | void 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 | |
241 | void 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 | |
287 | void 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 | |
306 | void 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 | |
319 | void 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 | |
344 | QString 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 | |
354 | QString 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 | |
368 | QString 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 | |
380 | QString 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 | |
398 | QVariantMap 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 | |
417 | QTEST_MAIN(MediaPlayerTest) |
418 | |
419 | #include "moc_mediaplayertest.cpp" |
420 | |