Merge lp:~raoul-snyman/openlp/disconnect-slots-2.4 into lp:openlp/2.4
- disconnect-slots-2.4
- Merge into 2.4
Proposed by
Raoul Snyman
Status: | Merged |
---|---|
Merged at revision: | 2651 |
Proposed branch: | lp:~raoul-snyman/openlp/disconnect-slots-2.4 |
Merge into: | lp:openlp/2.4 |
Diff against target: |
579 lines (+507/-14) 2 files modified
openlp/core/ui/media/systemplayer.py (+29/-14) tests/functional/openlp_core_ui_media/test_systemplayer.py (+478/-0) |
To merge this branch: | bzr merge lp:~raoul-snyman/openlp/disconnect-slots-2.4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Bentley | Approve | ||
Review via email: mp+302879@code.launchpad.net |
This proposal supersedes a proposal from 2016-08-14.
Commit message
Description of the change
Fix bug #1547964 by ignoring the exception (it's harmless)
Add this to your merge proposal:
-------
lp:~raoul-snyman/openlp/disconnect-slots-2.4 (revision 2652)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'openlp/core/ui/media/systemplayer.py' |
2 | --- openlp/core/ui/media/systemplayer.py 2015-12-10 19:03:57 +0000 |
3 | +++ openlp/core/ui/media/systemplayer.py 2016-08-14 07:41:09 +0000 |
4 | @@ -100,7 +100,7 @@ |
5 | ext = '*%s' % extension |
6 | if ext not in mime_type_list: |
7 | mime_type_list.append(ext) |
8 | - log.info('MediaPlugin: %s extensions: %s' % (mimetype, ' '.join(extensions))) |
9 | + log.info('MediaPlugin: %s extensions: %s', mimetype, ' '.join(extensions)) |
10 | |
11 | def setup(self, display): |
12 | """ |
13 | @@ -160,6 +160,13 @@ |
14 | if start_time > 0: |
15 | self.seek(display, controller.media_info.start_time * 1000) |
16 | self.volume(display, controller.media_info.volume) |
17 | + display.media_player.blockSignals(True) |
18 | + try: |
19 | + display.media_player.durationChanged.disconnect() |
20 | + except TypeError: |
21 | + # We get a type error if there are no slots attached to this signal, so ignore it |
22 | + pass |
23 | + display.media_player.blockSignals(False) |
24 | display.media_player.durationChanged.connect(functools.partial(self.set_duration, controller)) |
25 | self.state = MediaState.Playing |
26 | display.video_widget.raise_() |
27 | @@ -178,7 +185,11 @@ |
28 | Stop the current media item |
29 | """ |
30 | display.media_player.blockSignals(True) |
31 | - display.media_player.durationChanged.disconnect() |
32 | + try: |
33 | + display.media_player.durationChanged.disconnect() |
34 | + except TypeError: |
35 | + # We get a type error if there are no slots attached to this signal, so ignore it |
36 | + pass |
37 | display.media_player.blockSignals(False) |
38 | display.media_player.stop() |
39 | self.set_visible(display, False) |
40 | @@ -216,6 +227,9 @@ |
41 | |
42 | @staticmethod |
43 | def set_duration(controller, duration): |
44 | + """ |
45 | + Set the length of the seek slider |
46 | + """ |
47 | controller.media_info.length = int(duration / 1000) |
48 | controller.seek_slider.setMaximum(controller.media_info.length * 1000) |
49 | |
50 | @@ -261,33 +275,34 @@ |
51 | :return: True if file can be played otherwise False |
52 | """ |
53 | thread = QtCore.QThread() |
54 | - check_media_player = CheckMedia(path) |
55 | - check_media_player.setVolume(0) |
56 | - check_media_player.moveToThread(thread) |
57 | - check_media_player.finished.connect(thread.quit) |
58 | - thread.started.connect(check_media_player.play) |
59 | + check_media_worker = CheckMediaWorker(path) |
60 | + check_media_worker.setVolume(0) |
61 | + check_media_worker.moveToThread(thread) |
62 | + check_media_worker.finished.connect(thread.quit) |
63 | + thread.started.connect(check_media_worker.play) |
64 | thread.start() |
65 | while thread.isRunning(): |
66 | self.application.processEvents() |
67 | - return check_media_player.result |
68 | - |
69 | - |
70 | -class CheckMedia(QtMultimedia.QMediaPlayer): |
71 | + return check_media_worker.result |
72 | + |
73 | + |
74 | +class CheckMediaWorker(QtMultimedia.QMediaPlayer): |
75 | """ |
76 | Class used to check if a media file is playable |
77 | """ |
78 | finished = QtCore.pyqtSignal() |
79 | |
80 | def __init__(self, path): |
81 | - super(CheckMedia, self).__init__(None, QtMultimedia.QMediaPlayer.VideoSurface) |
82 | + super(CheckMediaWorker, self).__init__(None, QtMultimedia.QMediaPlayer.VideoSurface) |
83 | self.result = None |
84 | - |
85 | self.error.connect(functools.partial(self.signals, 'error')) |
86 | self.mediaStatusChanged.connect(functools.partial(self.signals, 'media')) |
87 | - |
88 | self.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(path))) |
89 | |
90 | def signals(self, origin, status): |
91 | + """ |
92 | + Exit the worker and stop the thread when either an error or a media change is encountered |
93 | + """ |
94 | if origin == 'media' and status == self.BufferedMedia: |
95 | self.result = True |
96 | self.stop() |
97 | |
98 | === added file 'tests/functional/openlp_core_ui_media/test_systemplayer.py' |
99 | --- tests/functional/openlp_core_ui_media/test_systemplayer.py 1970-01-01 00:00:00 +0000 |
100 | +++ tests/functional/openlp_core_ui_media/test_systemplayer.py 2016-08-14 07:41:09 +0000 |
101 | @@ -0,0 +1,478 @@ |
102 | +# -*- coding: utf-8 -*- |
103 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
104 | + |
105 | +############################################################################### |
106 | +# OpenLP - Open Source Lyrics Projection # |
107 | +# --------------------------------------------------------------------------- # |
108 | +# Copyright (c) 2008-2016 OpenLP Developers # |
109 | +# --------------------------------------------------------------------------- # |
110 | +# This program is free software; you can redistribute it and/or modify it # |
111 | +# under the terms of the GNU General Public License as published by the Free # |
112 | +# Software Foundation; version 2 of the License. # |
113 | +# # |
114 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
115 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
116 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
117 | +# more details. # |
118 | +# # |
119 | +# You should have received a copy of the GNU General Public License along # |
120 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
121 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
122 | +############################################################################### |
123 | +""" |
124 | +Package to test the openlp.core.ui.media.systemplayer package. |
125 | +""" |
126 | +from unittest import TestCase |
127 | + |
128 | +from PyQt5 import QtCore, QtMultimedia |
129 | + |
130 | +from openlp.core.common import Registry |
131 | +from openlp.core.ui.media import MediaState |
132 | +from openlp.core.ui.media.systemplayer import SystemPlayer, CheckMediaWorker, ADDITIONAL_EXT |
133 | + |
134 | +from tests.functional import MagicMock, call, patch |
135 | + |
136 | + |
137 | +class TestSystemPlayer(TestCase): |
138 | + """ |
139 | + Test the system media player |
140 | + """ |
141 | + @patch('openlp.core.ui.media.systemplayer.mimetypes') |
142 | + @patch('openlp.core.ui.media.systemplayer.QtMultimedia.QMediaPlayer') |
143 | + def test_constructor(self, MockQMediaPlayer, mocked_mimetypes): |
144 | + """ |
145 | + Test the SystemPlayer constructor |
146 | + """ |
147 | + # GIVEN: The SystemPlayer class and a mockedQMediaPlayer |
148 | + mocked_media_player = MagicMock() |
149 | + mocked_media_player.supportedMimeTypes.return_value = [ |
150 | + 'application/postscript', |
151 | + 'audio/aiff', |
152 | + 'audio/x-aiff', |
153 | + 'text/html', |
154 | + 'video/animaflex', |
155 | + 'video/x-ms-asf' |
156 | + ] |
157 | + mocked_mimetypes.guess_all_extensions.side_effect = [ |
158 | + ['.aiff'], |
159 | + ['.aiff'], |
160 | + ['.afl'], |
161 | + ['.asf'] |
162 | + ] |
163 | + MockQMediaPlayer.return_value = mocked_media_player |
164 | + |
165 | + # WHEN: An object is created from it |
166 | + player = SystemPlayer(self) |
167 | + |
168 | + # THEN: The correct initial values should be set up |
169 | + self.assertEqual('system', player.name) |
170 | + self.assertEqual('System', player.original_name) |
171 | + self.assertEqual('&System', player.display_name) |
172 | + self.assertEqual(self, player.parent) |
173 | + self.assertEqual(ADDITIONAL_EXT, player.additional_extensions) |
174 | + MockQMediaPlayer.assert_called_once_with(None, QtMultimedia.QMediaPlayer.VideoSurface) |
175 | + mocked_mimetypes.init.assert_called_once_with() |
176 | + mocked_media_player.service.assert_called_once_with() |
177 | + mocked_media_player.supportedMimeTypes.assert_called_once_with() |
178 | + self.assertEqual(['*.aiff'], player.audio_extensions_list) |
179 | + self.assertEqual(['*.afl', '*.asf'], player.video_extensions_list) |
180 | + |
181 | + @patch('openlp.core.ui.media.systemplayer.QtMultimediaWidgets.QVideoWidget') |
182 | + @patch('openlp.core.ui.media.systemplayer.QtMultimedia.QMediaPlayer') |
183 | + def test_setup(self, MockQMediaPlayer, MockQVideoWidget): |
184 | + """ |
185 | + Test the setup() method of SystemPlayer |
186 | + """ |
187 | + # GIVEN: A SystemPlayer instance and a mock display |
188 | + player = SystemPlayer(self) |
189 | + mocked_display = MagicMock() |
190 | + mocked_display.size.return_value = [1, 2, 3, 4] |
191 | + mocked_video_widget = MagicMock() |
192 | + mocked_media_player = MagicMock() |
193 | + MockQVideoWidget.return_value = mocked_video_widget |
194 | + MockQMediaPlayer.return_value = mocked_media_player |
195 | + |
196 | + # WHEN: setup() is run |
197 | + player.setup(mocked_display) |
198 | + |
199 | + # THEN: The player should have a display widget |
200 | + MockQVideoWidget.assert_called_once_with(mocked_display) |
201 | + self.assertEqual(mocked_video_widget, mocked_display.video_widget) |
202 | + mocked_display.size.assert_called_once_with() |
203 | + mocked_video_widget.resize.assert_called_once_with([1, 2, 3, 4]) |
204 | + MockQMediaPlayer.assert_called_with(mocked_display) |
205 | + self.assertEqual(mocked_media_player, mocked_display.media_player) |
206 | + mocked_media_player.setVideoOutput.assert_called_once_with(mocked_video_widget) |
207 | + mocked_video_widget.raise_.assert_called_once_with() |
208 | + mocked_video_widget.hide.assert_called_once_with() |
209 | + self.assertTrue(player.has_own_widget) |
210 | + |
211 | + def test_check_available(self): |
212 | + """ |
213 | + Test the check_available() method on SystemPlayer |
214 | + """ |
215 | + # GIVEN: A SystemPlayer instance |
216 | + player = SystemPlayer(self) |
217 | + |
218 | + # WHEN: check_available is run |
219 | + result = player.check_available() |
220 | + |
221 | + # THEN: it should be available |
222 | + self.assertTrue(result) |
223 | + |
224 | + def test_load_valid_media(self): |
225 | + """ |
226 | + Test the load() method of SystemPlayer with a valid media file |
227 | + """ |
228 | + # GIVEN: A SystemPlayer instance and a mocked display |
229 | + player = SystemPlayer(self) |
230 | + mocked_display = MagicMock() |
231 | + mocked_display.controller.media_info.volume = 1 |
232 | + mocked_display.controller.media_info.file_info.absoluteFilePath.return_value = '/path/to/file' |
233 | + |
234 | + # WHEN: The load() method is run |
235 | + with patch.object(player, 'check_media') as mocked_check_media, \ |
236 | + patch.object(player, 'volume') as mocked_volume: |
237 | + mocked_check_media.return_value = True |
238 | + result = player.load(mocked_display) |
239 | + |
240 | + # THEN: the file is sent to the video widget |
241 | + mocked_display.controller.media_info.file_info.absoluteFilePath.assert_called_once_with() |
242 | + mocked_check_media.assert_called_once_with('/path/to/file') |
243 | + mocked_display.media_player.setMedia.assert_called_once_with( |
244 | + QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile('/path/to/file'))) |
245 | + mocked_volume.assert_called_once_with(mocked_display, 1) |
246 | + self.assertTrue(result) |
247 | + |
248 | + def test_load_invalid_media(self): |
249 | + """ |
250 | + Test the load() method of SystemPlayer with an invalid media file |
251 | + """ |
252 | + # GIVEN: A SystemPlayer instance and a mocked display |
253 | + player = SystemPlayer(self) |
254 | + mocked_display = MagicMock() |
255 | + mocked_display.controller.media_info.volume = 1 |
256 | + mocked_display.controller.media_info.file_info.absoluteFilePath.return_value = '/path/to/file' |
257 | + |
258 | + # WHEN: The load() method is run |
259 | + with patch.object(player, 'check_media') as mocked_check_media, \ |
260 | + patch.object(player, 'volume') as mocked_volume: |
261 | + mocked_check_media.return_value = False |
262 | + result = player.load(mocked_display) |
263 | + |
264 | + # THEN: stuff |
265 | + mocked_display.controller.media_info.file_info.absoluteFilePath.assert_called_once_with() |
266 | + mocked_check_media.assert_called_once_with('/path/to/file') |
267 | + self.assertFalse(result) |
268 | + |
269 | + def test_resize(self): |
270 | + """ |
271 | + Test the resize() method of the SystemPlayer |
272 | + """ |
273 | + # GIVEN: A SystemPlayer instance and a mocked display |
274 | + player = SystemPlayer(self) |
275 | + mocked_display = MagicMock() |
276 | + mocked_display.size.return_value = [1, 2, 3, 4] |
277 | + |
278 | + # WHEN: The resize() method is called |
279 | + player.resize(mocked_display) |
280 | + |
281 | + # THEN: The player is resized |
282 | + mocked_display.size.assert_called_once_with() |
283 | + mocked_display.video_widget.resize.assert_called_once_with([1, 2, 3, 4]) |
284 | + |
285 | + @patch('openlp.core.ui.media.systemplayer.functools') |
286 | + def test_play(self, mocked_functools): |
287 | + """ |
288 | + Test the play() method of the SystemPlayer |
289 | + """ |
290 | + # GIVEN: A SystemPlayer instance and a mocked display |
291 | + mocked_functools.partial.return_value = 'function' |
292 | + player = SystemPlayer(self) |
293 | + mocked_display = MagicMock() |
294 | + mocked_display.controller.media_info.start_time = 1 |
295 | + mocked_display.controller.media_info.volume = 1 |
296 | + mocked_display.media_player.state.return_value = QtMultimedia.QMediaPlayer.PlayingState |
297 | + mocked_display.media_player.durationChanged.disconnect.side_effect = \ |
298 | + TypeError('disconnect() failed between \'durationChanged\' and all its connections') |
299 | + |
300 | + # WHEN: play() is called |
301 | + with patch.object(player, 'seek') as mocked_seek, \ |
302 | + patch.object(player, 'volume') as mocked_volume: |
303 | + result = player.play(mocked_display) |
304 | + |
305 | + # THEN: the media file is played |
306 | + mocked_display.media_player.state.assert_called_once_with() |
307 | + mocked_display.media_player.play.assert_called_once_with() |
308 | + mocked_seek.assert_called_once_with(mocked_display, 1000) |
309 | + mocked_volume.assert_called_once_with(mocked_display, 1) |
310 | + expected_block_signals_calls = [call(True), call(False)] |
311 | + self.assertEqual(expected_block_signals_calls, mocked_display.media_player.blockSignals.call_args_list) |
312 | + mocked_display.media_player.durationChanged.disconnect.assert_called_once_with() |
313 | + mocked_display.media_player.durationChanged.connect.assert_called_once_with('function') |
314 | + self.assertEqual(MediaState.Playing, player.state) |
315 | + mocked_display.video_widget.raise_.assert_called_once_with() |
316 | + self.assertTrue(result) |
317 | + |
318 | + def test_pause(self): |
319 | + """ |
320 | + Test the pause() method of the SystemPlayer |
321 | + """ |
322 | + # GIVEN: A SystemPlayer instance |
323 | + player = SystemPlayer(self) |
324 | + mocked_display = MagicMock() |
325 | + mocked_display.media_player.state.return_value = QtMultimedia.QMediaPlayer.PausedState |
326 | + |
327 | + # WHEN: The pause method is called |
328 | + player.pause(mocked_display) |
329 | + |
330 | + # THEN: The video is paused |
331 | + mocked_display.media_player.pause.assert_called_once_with() |
332 | + mocked_display.media_player.state.assert_called_once_with() |
333 | + self.assertEqual(MediaState.Paused, player.state) |
334 | + |
335 | + def test_stop(self): |
336 | + """ |
337 | + Test the stop() method of the SystemPlayer |
338 | + """ |
339 | + # GIVEN: A SystemPlayer instance |
340 | + player = SystemPlayer(self) |
341 | + mocked_display = MagicMock() |
342 | + |
343 | + # WHEN: The stop method is called |
344 | + with patch.object(player, 'set_visible') as mocked_set_visible: |
345 | + player.stop(mocked_display) |
346 | + |
347 | + # THEN: The video is stopped |
348 | + expected_block_signals_calls = [call(True), call(False)] |
349 | + self.assertEqual(expected_block_signals_calls, mocked_display.media_player.blockSignals.call_args_list) |
350 | + mocked_display.media_player.durationChanged.disconnect.assert_called_once_with() |
351 | + mocked_display.media_player.stop.assert_called_once_with() |
352 | + mocked_set_visible.assert_called_once_with(mocked_display, False) |
353 | + self.assertEqual(MediaState.Stopped, player.state) |
354 | + |
355 | + def test_volume(self): |
356 | + """ |
357 | + Test the volume() method of the SystemPlayer |
358 | + """ |
359 | + # GIVEN: A SystemPlayer instance |
360 | + player = SystemPlayer(self) |
361 | + mocked_display = MagicMock() |
362 | + mocked_display.has_audio = True |
363 | + |
364 | + # WHEN: The stop method is called |
365 | + player.volume(mocked_display, 2) |
366 | + |
367 | + # THEN: The video is stopped |
368 | + mocked_display.media_player.setVolume.assert_called_once_with(2) |
369 | + |
370 | + def test_seek(self): |
371 | + """ |
372 | + Test the seek() method of the SystemPlayer |
373 | + """ |
374 | + # GIVEN: A SystemPlayer instance |
375 | + player = SystemPlayer(self) |
376 | + mocked_display = MagicMock() |
377 | + |
378 | + # WHEN: The stop method is called |
379 | + player.seek(mocked_display, 2) |
380 | + |
381 | + # THEN: The video is stopped |
382 | + mocked_display.media_player.setPosition.assert_called_once_with(2) |
383 | + |
384 | + def test_reset(self): |
385 | + """ |
386 | + Test the reset() method of the SystemPlayer |
387 | + """ |
388 | + # GIVEN: A SystemPlayer instance |
389 | + player = SystemPlayer(self) |
390 | + mocked_display = MagicMock() |
391 | + |
392 | + # WHEN: reset() is called |
393 | + with patch.object(player, 'set_visible') as mocked_set_visible: |
394 | + player.reset(mocked_display) |
395 | + |
396 | + # THEN: The media player is reset |
397 | + mocked_display.media_player.stop() |
398 | + mocked_display.media_player.setMedia.assert_called_once_with(QtMultimedia.QMediaContent()) |
399 | + mocked_set_visible.assert_called_once_with(mocked_display, False) |
400 | + mocked_display.video_widget.setVisible.assert_called_once_with(False) |
401 | + self.assertEqual(MediaState.Off, player.state) |
402 | + |
403 | + def test_set_visible(self): |
404 | + """ |
405 | + Test the set_visible() method on the SystemPlayer |
406 | + """ |
407 | + # GIVEN: A SystemPlayer instance and a mocked display |
408 | + player = SystemPlayer(self) |
409 | + player.has_own_widget = True |
410 | + mocked_display = MagicMock() |
411 | + |
412 | + # WHEN: set_visible() is called |
413 | + player.set_visible(mocked_display, True) |
414 | + |
415 | + # THEN: The widget should be visible |
416 | + mocked_display.video_widget.setVisible.assert_called_once_with(True) |
417 | + |
418 | + def test_set_duration(self): |
419 | + """ |
420 | + Test the set_duration() method of the SystemPlayer |
421 | + """ |
422 | + # GIVEN: a mocked controller |
423 | + mocked_controller = MagicMock() |
424 | + |
425 | + # WHEN: The set_duration() is called. NB: the 10 here is ignored by the code |
426 | + SystemPlayer.set_duration(mocked_controller, 1000) |
427 | + |
428 | + # THEN: The maximum length of the slider should be set |
429 | + self.assertEqual(1, mocked_controller.media_info.length) |
430 | + mocked_controller.seek_slider.setMaximum.assert_called_once_with(1000) |
431 | + |
432 | + def test_update_ui(self): |
433 | + """ |
434 | + Test the update_ui() method on the SystemPlayer |
435 | + """ |
436 | + # GIVEN: A SystemPlayer instance |
437 | + player = SystemPlayer(self) |
438 | + player.state = MediaState.Playing |
439 | + mocked_display = MagicMock() |
440 | + mocked_display.media_player.state.return_value = QtMultimedia.QMediaPlayer.PausedState |
441 | + mocked_display.controller.media_info.end_time = 1 |
442 | + mocked_display.media_player.position.return_value = 2000 |
443 | + mocked_display.controller.seek_slider.isSliderDown.return_value = False |
444 | + |
445 | + # WHEN: update_ui() is called |
446 | + with patch.object(player, 'stop') as mocked_stop, \ |
447 | + patch.object(player, 'set_visible') as mocked_set_visible: |
448 | + player.update_ui(mocked_display) |
449 | + |
450 | + # THEN: The UI is updated |
451 | + expected_stop_calls = [call(mocked_display), call(mocked_display)] |
452 | + expected_position_calls = [call(), call()] |
453 | + expected_block_signals_calls = [call(True), call(False)] |
454 | + mocked_display.media_player.state.assert_called_once_with() |
455 | + self.assertEqual(2, mocked_stop.call_count) |
456 | + self.assertEqual(expected_stop_calls, mocked_stop.call_args_list) |
457 | + self.assertEqual(2, mocked_display.media_player.position.call_count) |
458 | + self.assertEqual(expected_position_calls, mocked_display.media_player.position.call_args_list) |
459 | + mocked_set_visible.assert_called_once_with(mocked_display, False) |
460 | + mocked_display.controller.seek_slider.isSliderDown.assert_called_once_with() |
461 | + self.assertEqual(expected_block_signals_calls, |
462 | + mocked_display.controller.seek_slider.blockSignals.call_args_list) |
463 | + mocked_display.controller.seek_slider.setSliderPosition.assert_called_once_with(2000) |
464 | + |
465 | + def test_get_media_display_css(self): |
466 | + """ |
467 | + Test the get_media_display_css() method of the SystemPlayer |
468 | + """ |
469 | + # GIVEN: A SystemPlayer instance |
470 | + player = SystemPlayer(self) |
471 | + |
472 | + # WHEN: get_media_display_css() is called |
473 | + result = player.get_media_display_css() |
474 | + |
475 | + # THEN: The css should be empty |
476 | + self.assertEqual('', result) |
477 | + |
478 | + def test_get_info(self): |
479 | + """ |
480 | + Test the get_info() method of the SystemPlayer |
481 | + """ |
482 | + # GIVEN: A SystemPlayer instance |
483 | + player = SystemPlayer(self) |
484 | + |
485 | + # WHEN: get_info() is called |
486 | + result = player.get_info() |
487 | + |
488 | + # THEN: The info should be correct |
489 | + expected_info = 'This media player uses your operating system to provide media capabilities.<br/> ' \ |
490 | + '<strong>Audio</strong><br/>[]<br/><strong>Video</strong><br/>[]<br/>' |
491 | + self.assertEqual(expected_info, result) |
492 | + |
493 | + @patch('openlp.core.ui.media.systemplayer.CheckMediaWorker') |
494 | + @patch('openlp.core.ui.media.systemplayer.QtCore.QThread') |
495 | + def test_check_media(self, MockQThread, MockCheckMediaWorker): |
496 | + """ |
497 | + Test the check_media() method of the SystemPlayer |
498 | + """ |
499 | + # GIVEN: A SystemPlayer instance and a mocked thread |
500 | + valid_file = '/path/to/video.ogv' |
501 | + mocked_application = MagicMock() |
502 | + Registry().create() |
503 | + Registry().register('application', mocked_application) |
504 | + player = SystemPlayer(self) |
505 | + mocked_thread = MagicMock() |
506 | + mocked_thread.isRunning.side_effect = [True, False] |
507 | + mocked_thread.quit = 'quit' # actually supposed to be a slot, but it's all mocked out anyway |
508 | + MockQThread.return_value = mocked_thread |
509 | + mocked_check_media_worker = MagicMock() |
510 | + mocked_check_media_worker.play = 'play' |
511 | + mocked_check_media_worker.result = True |
512 | + MockCheckMediaWorker.return_value = mocked_check_media_worker |
513 | + |
514 | + # WHEN: check_media() is called with a valid media file |
515 | + result = player.check_media(valid_file) |
516 | + |
517 | + # THEN: It should return True |
518 | + MockQThread.assert_called_once_with() |
519 | + MockCheckMediaWorker.assert_called_once_with(valid_file) |
520 | + mocked_check_media_worker.setVolume.assert_called_once_with(0) |
521 | + mocked_check_media_worker.moveToThread.assert_called_once_with(mocked_thread) |
522 | + mocked_check_media_worker.finished.connect.assert_called_once_with('quit') |
523 | + mocked_thread.started.connect.assert_called_once_with('play') |
524 | + mocked_thread.start.assert_called_once_with() |
525 | + self.assertEqual(2, mocked_thread.isRunning.call_count) |
526 | + mocked_application.processEvents.assert_called_once_with() |
527 | + self.assertTrue(result) |
528 | + |
529 | + |
530 | +class TestCheckMediaWorker(TestCase): |
531 | + """ |
532 | + Test the CheckMediaWorker class |
533 | + """ |
534 | + def test_constructor(self): |
535 | + """ |
536 | + Test the constructor of the CheckMediaWorker class |
537 | + """ |
538 | + # GIVEN: A file path |
539 | + path = 'file.ogv' |
540 | + |
541 | + # WHEN: The CheckMediaWorker object is instantiated |
542 | + worker = CheckMediaWorker(path) |
543 | + |
544 | + # THEN: The correct values should be set up |
545 | + self.assertIsNotNone(worker) |
546 | + |
547 | + def test_signals_media(self): |
548 | + """ |
549 | + Test the signals() signal of the CheckMediaWorker class with a "media" origin |
550 | + """ |
551 | + # GIVEN: A CheckMediaWorker instance |
552 | + worker = CheckMediaWorker('file.ogv') |
553 | + |
554 | + # WHEN: signals() is called with media and BufferedMedia |
555 | + with patch.object(worker, 'stop') as mocked_stop, \ |
556 | + patch.object(worker, 'finished') as mocked_finished: |
557 | + worker.signals('media', worker.BufferedMedia) |
558 | + |
559 | + # THEN: The worker should exit and the result should be True |
560 | + mocked_stop.assert_called_once_with() |
561 | + mocked_finished.emit.assert_called_once_with() |
562 | + self.assertTrue(worker.result) |
563 | + |
564 | + def test_signals_error(self): |
565 | + """ |
566 | + Test the signals() signal of the CheckMediaWorker class with a "error" origin |
567 | + """ |
568 | + # GIVEN: A CheckMediaWorker instance |
569 | + worker = CheckMediaWorker('file.ogv') |
570 | + |
571 | + # WHEN: signals() is called with error and BufferedMedia |
572 | + with patch.object(worker, 'stop') as mocked_stop, \ |
573 | + patch.object(worker, 'finished') as mocked_finished: |
574 | + worker.signals('error', None) |
575 | + |
576 | + # THEN: The worker should exit and the result should be True |
577 | + mocked_stop.assert_called_once_with() |
578 | + mocked_finished.emit.assert_called_once_with() |
579 | + self.assertFalse(worker.result) |