diff --git a/tests/openlp_plugins/media/forms/test_streamselectorform.py b/tests/openlp_plugins/media/forms/test_streamselectorform.py new file mode 100644 index 000000000..3b205abed --- /dev/null +++ b/tests/openlp_plugins/media/forms/test_streamselectorform.py @@ -0,0 +1,340 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# OpenLP - Open Source Lyrics Projection # +# ---------------------------------------------------------------------- # +# Copyright (c) 2008-2021 OpenLP Developers # +# ---------------------------------------------------------------------- # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +########################################################################## +""" +Module to test the StreamSelectorForm. +""" +import pytest + +from unittest.mock import MagicMock, patch + +from PyQt5 import QtCore, QtTest, QtWidgets + +from openlp.plugins.media.forms.streamselectorform import StreamSelectorForm +from openlp.plugins.media.forms.streamselectordialog import CaptureVideoDirectShowWidget, CaptureDigitalTVWidget, \ + CaptureVideoLinuxWidget, JackAudioKitWidget, CaptureAnalogTVWidget, MacInputWidget +from openlp.plugins.media.forms import VLCOptionsWidget + + +# This mocks the callback function BackgroundPage.set_stream() in core/pages/background.py +# This function is used to set the device stream text in the theme wizard +setstream = MagicMock() + + +@pytest.fixture() +def stream_selector_form_win(settings): + ''' + Fixture for setting up a StreamSelectorForm on a windows PC with dummy video and audio devices + ''' + main_window = QtWidgets.QMainWindow() + + camera1 = MagicMock() + camera1.description.return_value = "Camera 1" + camera1.deviceName.return_value = "Camera 1 device" + camera2 = MagicMock() + camera2.description.return_value = "Camera 2" + camera2.deviceName.return_value = "Camera 2 device" + + audio1 = MagicMock() + audio1.deviceName.return_value = "Audio 1" + audio2 = MagicMock() + audio2.deviceName.return_value = "Audio 2" + + with patch('openlp.plugins.media.forms.streamselectordialog.is_win', return_value=True), \ + patch('openlp.plugins.media.forms.streamselectordialog.is_linux', return_value=False), \ + patch('openlp.plugins.media.forms.streamselectordialog.is_macosx', return_value=False), \ + patch('openlp.plugins.media.forms.streamselectordialog.QCameraInfo.availableCameras', + return_value=[camera1, camera2]), \ + patch('openlp.plugins.media.forms.streamselectordialog.QAudioDeviceInfo.availableDevices', + return_value=[audio1, audio2]): + form = StreamSelectorForm(main_window, setstream) + + yield form + del form + del main_window + + +# This fixture is parameterized as per +# https://docs.pytest.org/en/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources +# The parameter is passed to StreamSelectorForm param3 (defining whether it's for a theme or not) +# This is because on linux the JackAudioKitWidget is not included if it's for a theme +@pytest.fixture() +def stream_selector_form_linux(request, settings): + ''' + Fixture for setting up a StreamSelectorForm on a linux computer with dummy video and audio devices + ''' + main_window = QtWidgets.QMainWindow() + + def return_dummy_devices(*args, **kwargs): + if isinstance(args[0], str): + if args[0].startswith('/dev/video'): + return ['/dev/video1', '/dev/video2'] + if args[0].startswith('/dev/snd'): + return ['/dev/snd/pcmC0D0p', '/dev/snd/pcmC0D1p'] + return [] + + with patch('openlp.plugins.media.forms.streamselectordialog.is_win', return_value=False), \ + patch('openlp.plugins.media.forms.streamselectordialog.is_linux', return_value=True), \ + patch('openlp.plugins.media.forms.streamselectordialog.is_macosx', return_value=False), \ + patch('openlp.plugins.media.forms.streamselectordialog.glob') as patched_glob: + patched_glob.glob.side_effect = return_dummy_devices + form = StreamSelectorForm(main_window, setstream, request.param) + + yield form + del form + del main_window + + +@pytest.fixture() +def stream_selector_form_mac(settings): + ''' + Fixture for setting up a StreamSelectorForm on a mac with dummy video and audio devices + ''' + main_window = QtWidgets.QMainWindow() + + camera1 = MagicMock() + camera1.description.return_value = "Camera 1" + camera1.deviceName.return_value = "Camera 1 device" + camera2 = MagicMock() + camera2.description.return_value = "Camera 2" + camera2.deviceName.return_value = "Camera 2 device" + + audio1 = MagicMock() + audio1.deviceName.return_value = "Audio 1" + audio2 = MagicMock() + audio2.deviceName.return_value = "Audio 2" + + with patch('openlp.plugins.media.forms.streamselectordialog.is_win', return_value=False), \ + patch('openlp.plugins.media.forms.streamselectordialog.is_linux', return_value=False), \ + patch('openlp.plugins.media.forms.streamselectordialog.is_macosx', return_value=True), \ + patch('openlp.plugins.media.forms.streamselectordialog.QCameraInfo.availableCameras', + return_value=[camera1, camera2]), \ + patch('openlp.plugins.media.forms.streamselectordialog.QAudioDeviceInfo.availableDevices', + return_value=[audio1, audio2]): + form = StreamSelectorForm(main_window, setstream) + + yield form + del form + del main_window + + +def test_win_setup(stream_selector_form_win): + ''' + Test that the UI is set up ok on windows + ''' + # GIVEN: A fixture for a StreamSelectorForm on a windows pc with dummy devices + + # THEN: The UI elements should display the dummy devices correctly + assert stream_selector_form_win.objectName() == 'stream_selector' + assert stream_selector_form_win.stacked_modes_layout.objectName() == 'stacked_modes_layout' + assert stream_selector_form_win.stacked_modes_layout.count() == 2 + assert isinstance(stream_selector_form_win.stacked_modes_layout.widget(0), CaptureVideoDirectShowWidget) + + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.count() == 3 + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(0) == "" + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(1) == "Camera 1" + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(2) == "Camera 2" + + assert stream_selector_form_win.stacked_modes_layout.widget(0).audio_devices_combo_box.count() == 3 + assert stream_selector_form_win.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(0) == "" + assert stream_selector_form_win.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(1) == "Audio 1" + assert stream_selector_form_win.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(2) == "Audio 2" + + assert isinstance(stream_selector_form_win.stacked_modes_layout.widget(1), CaptureDigitalTVWidget) + assert isinstance(stream_selector_form_win.more_options_group, VLCOptionsWidget) + + +@pytest.mark.parametrize("stream_selector_form_linux", [True], indirect=True) +def test_linux_setup_for_theme(stream_selector_form_linux): + ''' + Test that the UI is set up ok on linux for theme (param3 of StreamSelectorForm is True) + ''' + # GIVEN: A fixture for a StreamSelectorForm on a linux computer with dummy devices + + # THEN: The UI elements should display the dummy devices correctly + assert stream_selector_form_linux.objectName() == 'stream_selector' + assert stream_selector_form_linux.stacked_modes_layout.objectName() == 'stacked_modes_layout' + assert stream_selector_form_linux.stacked_modes_layout.count() == 3 + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(0), CaptureVideoLinuxWidget) + + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.count() == 3 + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(0) == "" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(1) ==\ + "/dev/video1" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(2) ==\ + "/dev/video2" + + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.count() == 3 + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(0) == "" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(1) ==\ + "hw:0,0p" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(2) ==\ + "hw:0,1p" + + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(1), CaptureAnalogTVWidget) + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(2), CaptureDigitalTVWidget) + assert isinstance(stream_selector_form_linux.more_options_group, VLCOptionsWidget) + + +@pytest.mark.parametrize("stream_selector_form_linux", [False], indirect=True) +def test_linux_setup_general(stream_selector_form_linux): + ''' + Test that the UI is set up ok on linux, not just for themes (param3 of StreamSelectorForm is False) + ''' + # GIVEN: A fixture for a StreamSelectorForm on a linux computer with dummy devices + + # THEN: The UI elements should display the dummy devices correctly + assert stream_selector_form_linux.objectName() == 'stream_selector' + assert stream_selector_form_linux.stacked_modes_layout.objectName() == 'stacked_modes_layout' + assert stream_selector_form_linux.stacked_modes_layout.count() == 4 + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(0), CaptureVideoLinuxWidget) + + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.count() == 3 + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(0) == "" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(1) ==\ + "/dev/video1" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(2) ==\ + "/dev/video2" + + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.count() == 3 + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(0) == "" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(1) ==\ + "hw:0,0p" + assert stream_selector_form_linux.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(2) ==\ + "hw:0,1p" + + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(1), CaptureAnalogTVWidget) + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(2), JackAudioKitWidget) + assert isinstance(stream_selector_form_linux.stacked_modes_layout.widget(3), CaptureDigitalTVWidget) + assert isinstance(stream_selector_form_linux.more_options_group, VLCOptionsWidget) + + +def test_mac_setup(stream_selector_form_mac): + ''' + Test that the UI is set up ok on mac + ''' + # GIVEN: A fixture for a StreamSelectorForm on a mac with dummy devices + + # THEN: The UI elements should display the dummy devices correctly + assert stream_selector_form_mac.objectName() == 'stream_selector' + assert stream_selector_form_mac.stacked_modes_layout.objectName() == 'stacked_modes_layout' + assert stream_selector_form_mac.stacked_modes_layout.count() == 1 + assert isinstance(stream_selector_form_mac.stacked_modes_layout.widget(0), MacInputWidget) + + assert stream_selector_form_mac.stacked_modes_layout.widget(0).video_devices_combo_box.count() == 3 + assert stream_selector_form_mac.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(0) == "" + assert stream_selector_form_mac.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(1) == "Camera 1" + assert stream_selector_form_mac.stacked_modes_layout.widget(0).video_devices_combo_box.itemText(2) == "Camera 2" + + assert stream_selector_form_mac.stacked_modes_layout.widget(0).audio_devices_combo_box.count() == 3 + assert stream_selector_form_mac.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(0) == "" + assert stream_selector_form_mac.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(1) == "Audio 1" + assert stream_selector_form_mac.stacked_modes_layout.widget(0).audio_devices_combo_box.itemText(2) == "Audio 2" + + assert isinstance(stream_selector_form_mac.more_options_group, VLCOptionsWidget) + + +def test_set_mrl_win(stream_selector_form_win): + ''' + Test that the UI components are prefilled correctly on a windows PC + ''' + # GIVEN: A fixture for a StreamSelectorForm on a windows computer with dummy devices + + # WHEN: The stream selector form is prefilled + + live_stream_text = 'devicestream:wintest&&dshow://&&:"dshow-vdev=Camera 2" :dshow-size=25 :live-caching=400' + stream_selector_form_win.set_mrl(live_stream_text) + + # THEN: The form should contain the prefilled values + stream_selector_form_win.stream_name_edit.text() == "wintest" + assert stream_selector_form_win.stacked_modes_layout.currentIndex() == 0 + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.currentIndex() == 2 + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.currentText() == "Camera 2" + assert stream_selector_form_win.stacked_modes_layout.widget(0).video_size_lineedit.text() == '25' + assert stream_selector_form_win.more_options_group.caching.text() == '400 ms' + + +@pytest.mark.parametrize("stream_selector_form_linux", [False], indirect=True) +def test_set_mrl_linux(stream_selector_form_linux): + ''' + Test that the UI components are prefilled correctly on a linux computer + ''' + # GIVEN: A fixture for a StreamSelectorForm on a linux computer with dummy devices + + # WHEN: The stream selector form is prefilled + + live_stream_text = 'devicestream:linuxtest&&v4l2://&&:v4l2-standard=PAL :v4l2-tuner-frequency=1 :live-caching=300' + stream_selector_form_linux.set_mrl(live_stream_text) + + # THEN: The form should contain the prefilled values + stream_selector_form_linux.stream_name_edit.text() == "linuxtest" + assert stream_selector_form_linux.stacked_modes_layout.currentIndex() == 1 + assert stream_selector_form_linux.stacked_modes_layout.widget(1).freq.text() == "1 kHz" + assert stream_selector_form_linux.stacked_modes_layout.widget(1).video_std_combobox.currentText() == "PAL" + assert stream_selector_form_linux.more_options_group.caching.text() == '300 ms' + + +def test_win_set_stream_call(stream_selector_form_win): + ''' + Test that when a stream selector form on windows is run and filled in then set_stream() is called correctly + ''' + # GIVEN: A fixture for a StreamSelectorForm on a windows computer with dummy devices + + # WHEN: The form is executed and filled in with values + + stream_selector_form_win.stream_name_edit.setText('test') + # choose direct show + stream_selector_form_win.stacked_modes_layout.setCurrentIndex(0) + # choose camera 2 + stream_selector_form_win.stacked_modes_layout.widget(0).video_devices_combo_box.setCurrentIndex(2) + # increment caching value + QtTest.QTest.keyClick(stream_selector_form_win.more_options_group.caching, QtCore.Qt.Key_Up) + # click on Save + QtTest.QTest.mouseClick(stream_selector_form_win.save_button, QtCore.Qt.LeftButton) + + # THEN: The callback function should be called with the correct values + + setstream.assert_called_with('devicestream:test&&dshow://&&:"dshow-vdev=Camera 2" :live-caching=400') + + +@pytest.mark.parametrize("stream_selector_form_linux", [False], indirect=True) +def test_linux_set_stream_call(stream_selector_form_linux): + ''' + Test that when a stream selector form on linux is run and filled in then set_stream() is called correctly + ''' + # GIVEN: A fixture for a StreamSelectorForm on a linux computer with dummy devices + + # WHEN: The form is executed and filled in with values + + stream_selector_form_linux.stream_name_edit.setText('test') + + # choose digital TV + stream_selector_form_linux.stacked_modes_layout.setCurrentIndex(3) + # choose ATSC delivery system + stream_selector_form_linux.stacked_modes_layout.widget(3).delivery_system_combo_box.setCurrentIndex( + stream_selector_form_linux.stacked_modes_layout.widget(3).delivery_system_combo_box.findText('ATSC')) + # increment transponder / multiplexer frequency + QtTest.QTest.keyClick(stream_selector_form_linux.stacked_modes_layout.widget(3).dvb_freq, QtCore.Qt.Key_Up) + # click on Save + QtTest.QTest.mouseClick(stream_selector_form_linux.save_button, QtCore.Qt.LeftButton) + + # THEN: The callback function should be called with the correct values + + setstream.assert_called_with('devicestream:test&&atsc://frequency=1000000&&:dvb-adapter=0 :live-caching=300')