diff --git a/openlp/core/common/enum.py b/openlp/core/common/enum.py index b31842e93..6384b4fde 100644 --- a/openlp/core/common/enum.py +++ b/openlp/core/common/enum.py @@ -93,6 +93,16 @@ class LanguageSelection(IntEnum): English = 2 +@unique +class ServiceItemType(IntEnum): + """ + Defines the type of service item + """ + Text = 1 + Image = 2 + Command = 3 + + @unique class PluginStatus(IntEnum): """ diff --git a/openlp/core/common/mixins.py b/openlp/core/common/mixins.py index cbd6650ce..feed2b481 100644 --- a/openlp/core/common/mixins.py +++ b/openlp/core/common/mixins.py @@ -29,7 +29,7 @@ from openlp.core.common.registry import Registry DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event', 'on_controller_size_changed', - 'preview_size_changed', 'resizeEvent'] + 'preview_size_changed', 'resizeEvent', 'eventFilter'] class LogMixin(object): diff --git a/openlp/core/display/window.py b/openlp/core/display/window.py index 1378d3c57..02fcfdcbc 100644 --- a/openlp/core/display/window.py +++ b/openlp/core/display/window.py @@ -29,15 +29,16 @@ import copy from PyQt5 import QtCore, QtWebChannel, QtWidgets from openlp.core.common.applocation import AppLocation +from openlp.core.common.enum import ServiceItemType from openlp.core.common.i18n import translate from openlp.core.common.mixins import RegistryProperties from openlp.core.common.path import path_to_str from openlp.core.common.registry import Registry -from openlp.core.common.settings import Settings from openlp.core.common.utils import wait_for from openlp.core.display.screens import ScreenList from openlp.core.ui import HideMode + log = logging.getLogger(__name__) @@ -128,7 +129,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): super(DisplayWindow, self).__init__(parent) # Gather all flags for the display window flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint - if Settings().value('advanced/x11 bypass wm'): + if self.settings.value('advanced/x11 bypass wm'): flags |= QtCore.Qt.X11BypassWindowManagerHint # Need to import this inline to get around a QtWebEngine issue from openlp.core.display.webengine import WebEngineView @@ -170,7 +171,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): self.update_from_screen(screen) self.is_display = True # Only make visible on single monitor setup if setting enabled. - if len(ScreenList()) > 1 or Settings().value('core/display on monitor'): + if len(ScreenList()) > 1 or self.settings.value('core/display on monitor'): self.show() def deregister_display(self): @@ -214,8 +215,8 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): '"{image_data}");'.format(bg_color=bg_color, image_data=image_data)) def set_startup_screen(self): - bg_color = Settings().value('core/logo background color') - image = Settings().value('core/logo file') + bg_color = self.settings.value('core/logo background color') + image = self.settings.value('core/logo file') if path_to_str(image).startswith(':'): image = self.openlp_splash_screen_path image_uri = image.as_uri() @@ -260,9 +261,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): log.debug(script) # Wait for previous scripts to finish wait_for(lambda: self.__script_done) - if not is_sync: - self.webview.page().runJavaScript(script) - else: + if is_sync: self.__script_done = False self.__script_result = None @@ -278,6 +277,9 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): if not wait_for(lambda: self.__script_done): self.__script_done = True return self.__script_result + else: + self.webview.page().runJavaScript(script) + self.raise_() def go_to_slide(self, verse): """ @@ -372,18 +374,31 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): else: return pixmap - def set_theme(self, theme, is_sync=False): + def set_theme(self, theme, is_sync=False, service_item_type=False): """ Set the theme of the display """ - # If background is transparent and this is not a display, inject checkerboard background image instead - if theme.background_type == 'transparent' and not self.is_display: - theme_copy = copy.deepcopy(theme) - theme_copy.background_type = 'image' - theme_copy.background_filename = self.checkerboard_path - exported_theme = theme_copy.export_theme(is_js=True) + theme_copy = copy.deepcopy(theme) + if self.is_display: + if service_item_type == ServiceItemType.Text: + if theme.background_type == 'video' or theme.background_type == 'stream': + theme_copy.background_type = 'transparent' else: - exported_theme = theme.export_theme(is_js=True) + # If review Display for media so we need to display black box. + if theme.background_type == 'stream': + theme_copy.background_type = 'transparent' + elif service_item_type == ServiceItemType.Command or theme.background_type == 'video' or \ + theme.background_type == 'live': + theme_copy.background_type = 'solid' + theme_copy.background_start_color = '#590909' + theme_copy.background_end_color = '#590909' + theme_copy.background_main_color = '#090909' + theme_copy.background_footer_color = '#090909' + # If background is transparent and this is not a display, inject checkerboard background image instead + elif theme.background_type == 'transparent': + theme_copy.background_type = 'image' + theme_copy.background_filename = self.checkerboard_path + exported_theme = theme_copy.export_theme(is_js=True) self.run_javascript('Display.setTheme({theme});'.format(theme=exported_theme), is_sync=is_sync) def get_video_types(self): @@ -398,12 +413,12 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): """ if self.is_display: # Only make visible on single monitor setup if setting enabled. - if len(ScreenList()) == 1 and not Settings().value('core/display on monitor'): + if len(ScreenList()) == 1 and not self.settings.value('core/display on monitor'): return self.run_javascript('Display.show();') # Check if setting for hiding logo on startup is enabled. # If it is, display should remain hidden, otherwise logo is shown. (from def setup) - if self.isHidden() and not Settings().value('core/logo hide on startup'): + if self.isHidden() and not self.settings.value('core/logo hide on startup'): self.setVisible(True) self.hide_mode = None # Trigger actions when display is active again. @@ -425,7 +440,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties): log.debug('hide_display mode = {mode:d}'.format(mode=mode)) if self.is_display: # Only make visible on single monitor setup if setting enabled. - if len(ScreenList()) == 1 and not Settings().value('core/display on monitor'): + if len(ScreenList()) == 1 and not self.settings.value('core/display on monitor'): return if mode == HideMode.Screen: self.setVisible(False) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index a48199671..2bac98530 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -157,6 +157,12 @@ class ItemCapabilities(object): ``HasMetaData`` The item has Meta Data about item + + ``CanStream`` + The item requires to process a VLC Stream + + ``HasBackgroundVideo`` + That a video file is present with the text """ CanPreview = 1 CanEdit = 2 @@ -181,6 +187,7 @@ class ItemCapabilities(object): HasThumbnails = 21 HasMetaData = 22 CanStream = 23 + HasBackgroundVideo = 24 def get_text_file_string(text_file_path): diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index c4019960b..042d7394a 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -35,27 +35,19 @@ from PyQt5 import QtGui from openlp.core.state import State from openlp.core.common import ThemeLevel, md5_hash from openlp.core.common.applocation import AppLocation +from openlp.core.common.enum import ServiceItemType from openlp.core.common.i18n import translate from openlp.core.common.mixins import RegistryProperties -from openlp.core.common.settings import Settings from openlp.core.common.registry import Registry from openlp.core.display.render import remove_tags, render_tags, render_chords_for_printing from openlp.core.lib import ItemCapabilities +from openlp.core.lib.theme import BackgroundType from openlp.core.ui.icons import UiIcons log = logging.getLogger(__name__) -class ServiceItemType(object): - """ - Defines the type of service item - """ - Text = 1 - Image = 2 - Command = 3 - - class ServiceItem(RegistryProperties): """ The service item is a base class for the plugins to use to interact with @@ -123,12 +115,12 @@ class ServiceItem(RegistryProperties): the value in Settings is used when this value is missinig """ if theme_level is None: - theme_level = Settings().value('themes/theme level') + theme_level = self.settings.value('themes/theme level') theme_manager = Registry().get('theme_manager') # Just assume we use the global theme. theme = theme_manager.global_theme if theme_level != ThemeLevel.Global: - service_theme = Settings().value('servicemanager/service theme') + service_theme = self.settings.value('servicemanager/service theme') # Service or Song level, so assume service theme (if it exists and item in service) # but use song theme if level is song (and it exists) if service_theme and self.from_service: @@ -136,6 +128,17 @@ class ServiceItem(RegistryProperties): if theme_level == ThemeLevel.Song and self.theme: theme = self.theme theme = theme_manager.get_theme_data(theme) + # Clean up capabilities and reload from the theme. + if self.is_text(): + if self.is_capable(ItemCapabilities.CanStream): + self.remove_capability(ItemCapabilities.CanStream) + if self.is_capable(ItemCapabilities.HasBackgroundVideo): + self.remove_capability(ItemCapabilities.HasBackgroundVideo) + if theme.background_type == BackgroundType.to_string(BackgroundType.Stream): + self.add_capability(ItemCapabilities.CanStream) + if theme.background_type == BackgroundType.to_string(BackgroundType.Video): + self.video_file_name = theme.background_filename + self.add_capability(ItemCapabilities.HasBackgroundVideo) return theme def _new_item(self): @@ -153,6 +156,14 @@ class ServiceItem(RegistryProperties): """ self.capabilities.append(capability) + def remove_capability(self, capability): + """ + Remove an ItemCapability from a ServiceItem + + :param capability: The capability to remove + """ + self.capabilities.remove(capability) + def is_capable(self, capability): """ Tell the caller if a ServiceItem has a capability @@ -433,7 +444,7 @@ class ServiceItem(RegistryProperties): self._create_slides() elif self.service_item_type == ServiceItemType.Image: settings_section = service_item['serviceitem']['header']['name'] - background = QtGui.QColor(Settings().value(settings_section + '/background color')) + background = QtGui.QColor(self.settings.value(settings_section + '/background color')) if path: self.has_original_files = False for text_image in service_item['serviceitem']['data']: @@ -649,6 +660,11 @@ class ServiceItem(RegistryProperties): if self.get_frame_path(frame=frame) in invalid_paths: self.remove_frame(frame) + def requires_media(self): + return self.is_capable(ItemCapabilities.HasBackgroundAudio) or \ + self.is_capable(ItemCapabilities.HasBackgroundVideo) or \ + self.is_capable(ItemCapabilities.CanStream) + def missing_frames(self): """ Returns if there are any frames in the service item diff --git a/openlp/core/pages/background.py b/openlp/core/pages/background.py index 82d528f0d..a0b8b8ed6 100644 --- a/openlp/core/pages/background.py +++ b/openlp/core/pages/background.py @@ -51,7 +51,7 @@ class BackgroundPage(GridLayoutPage): self.background_label.setObjectName('background_label') self.layout.addWidget(self.background_label, 0, 0) self.background_combo_box = QtWidgets.QComboBox(self) - self.background_combo_box.addItems(['', '', '', '']) + self.background_combo_box.addItems(['', '', '', '', '', '']) self.background_combo_box.setObjectName('background_combo_box') self.layout.addWidget(self.background_combo_box, 0, 1, 1, 3) # color @@ -130,8 +130,11 @@ class BackgroundPage(GridLayoutPage): self.background_combo_box.setItemText(BackgroundType.Solid, translate('OpenLP.ThemeWizard', 'Solid color')) self.background_combo_box.setItemText(BackgroundType.Gradient, translate('OpenLP.ThemeWizard', 'Gradient')) self.background_combo_box.setItemText(BackgroundType.Image, UiStrings().Image) + self.background_combo_box.setItemText(BackgroundType.Video, UiStrings().Video) self.background_combo_box.setItemText(BackgroundType.Transparent, translate('OpenLP.ThemeWizard', 'Transparent')) + self.background_combo_box.setItemText(BackgroundType.Stream, + translate('OpenLP.ThemeWizard', 'Live Stream')) self.color_label.setText(translate('OpenLP.ThemeWizard', 'Color:')) self.gradient_start_label.setText(translate('OpenLP.ThemeWizard', 'Starting color:')) self.gradient_end_label.setText(translate('OpenLP.ThemeWizard', 'Ending color:')) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 31c5dba6a..297c2efba 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -118,3 +118,6 @@ def format_milliseconds(milliseconds): minutes=minutes, seconds=seconds, millis=millis) + + +media_empty_song = [{"title": "", "text": "", "verse": 0, "footer": ""}] diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 4b8c5dc10..fa3dbe03c 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -37,6 +37,7 @@ from openlp.core.api.http import register_endpoint from openlp.core.common import is_linux, is_macosx from openlp.core.common.i18n import translate from openlp.core.common.mixins import LogMixin, RegistryProperties +from openlp.core.common.path import path_to_str from openlp.core.common.registry import Registry, RegistryBase from openlp.core.lib.serviceitem import ItemCapabilities from openlp.core.lib.ui import critical_error_message_box @@ -104,7 +105,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): fedora_rpmfusion = translate('OpenLP.MediaController', 'To install these libraries, you will need to enable the RPMFusion ' 'repository: https://rpmfusion.org/') - message = '' if is_macosx(): message = translate('OpenLP.MediaController', 'macOS is missing VLC. Please download and install from the VLC web site: ' @@ -132,8 +132,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): except AttributeError: State().update_pre_conditions('media_live', False) State().missing_text('media_live', translate( - 'OpenLP.MediaController', - 'No Displays have been configured, so Live Media has been disabled')) + 'OpenLP.MediaController', 'No Displays have been configured, so Live Media has been disabled')) self.setup_display(self.preview_controller, True) def display_controllers(self, controller_type): @@ -231,7 +230,16 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): if service_item.is_capable(ItemCapabilities.HasBackgroundAudio): controller.media_info.file_info = service_item.background_audio else: - controller.media_info.file_info = [service_item.get_frame_path()] + if service_item.is_capable(ItemCapabilities.HasBackgroundVideo): + controller.media_info.file_info = [service_item.video_file_name] + service_item.media_length = self.media_length(path_to_str(service_item.video_file_name)) + controller.media_info.is_looping_playback = True + controller.media_info.is_background = True + elif service_item.is_capable(ItemCapabilities.CanStream): + controller.media_info.file_info = [] + controller.media_info.is_background = True + else: + controller.media_info.file_info = [service_item.get_frame_path()] display = self._define_display(controller) if controller.is_live: # if this is an optical device use special handling @@ -271,7 +279,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): return False log.debug('video media type: {tpe} '.format(tpe=str(controller.media_info.media_type))) autoplay = False - if service_item.is_capable(ItemCapabilities.CanStream): + if service_item.requires_media(): autoplay = True # Preview requested if not controller.is_live: @@ -437,12 +445,9 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): controller.seek_slider.blockSignals(False) controller.volume_slider.blockSignals(False) controller.media_info.is_playing = True - display = self._define_display(controller) - if controller.is_live: + if not controller.media_info.is_background: + display = self._define_display(controller) display.setVisible(False) - controller.preview_display.hide() - else: - display.setVisible(True) return True def tick(self, controller): @@ -537,7 +542,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): if controller.controller_type in self.current_media_players: self.current_media_players[controller.controller_type].stop(controller) self.current_media_players[controller.controller_type].set_visible(controller, False) - controller.preview_display.hide() controller.seek_slider.setSliderPosition(0) total_seconds = controller.media_info.length // 1000 total_minutes = total_seconds // 60 diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 40879f937..4e9cfb37a 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -32,7 +32,6 @@ from time import sleep from PyQt5 import QtCore, QtWidgets from openlp.core.common import is_linux, is_macosx, is_win -from openlp.core.common.settings import Settings from openlp.core.display.screens import ScreenList from openlp.core.ui.media import MediaState, MediaType from openlp.core.ui.media.mediaplayer import MediaPlayer @@ -114,10 +113,10 @@ class VlcPlayer(MediaPlayer): controller.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame) # creating a basic vlc instance command_line_options = '--no-video-title-show ' - if Settings().value('advanced/hide mouse') and live_display: + if self.settings.value('advanced/hide mouse') and live_display: command_line_options += '--mouse-hide-timeout=0 ' - if Settings().value('media/vlc arguments'): - command_line_options += Settings().value('media/vlc arguments') + if self.settings.value('media/vlc arguments'): + command_line_options += self.settings.value('media/vlc arguments') controller.vlc_instance = vlc.Instance(command_line_options) # creating an empty vlc media player controller.vlc_media_player = controller.vlc_instance.media_player_new() @@ -176,7 +175,7 @@ class VlcPlayer(MediaPlayer): return False controller.vlc_media_player = audio_cd_tracks.item_at_index(controller.media_info.title_track) elif controller.media_info.media_type == MediaType.Stream: - stream_cmd = Settings().value('media/stream command') + stream_cmd = self.settings.value('media/stream command') controller.vlc_media = controller.vlc_instance.media_new_location(stream_cmd) else: controller.vlc_media = controller.vlc_instance.media_new_path(path) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 0fa6c7637..61959af5b 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -37,6 +37,7 @@ from openlp.core.state import State from openlp.core.common import ThemeLevel, delete_file from openlp.core.common.actions import ActionList, CategoryOrder from openlp.core.common.applocation import AppLocation +from openlp.core.common.enum import ServiceItemType from openlp.core.common.i18n import UiStrings, format_time, translate from openlp.core.common.json import OpenLPJSONDecoder, OpenLPJSONEncoder from openlp.core.common.mixins import LogMixin, RegistryProperties @@ -45,7 +46,7 @@ from openlp.core.common.settings import Settings from openlp.core.lib import build_icon from openlp.core.lib.exceptions import ValidationError from openlp.core.lib.plugin import PluginStatus -from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem, ServiceItemType +from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem from openlp.core.lib.ui import create_widget_action, critical_error_message_box, find_and_set_in_combo_box from openlp.core.ui.icons import UiIcons from openlp.core.ui.media import AUDIO_EXT, VIDEO_EXT diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 092d12e77..d75730458 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -38,6 +38,7 @@ from openlp.core.display.screens import ScreenList from openlp.core.display.window import DisplayWindow from openlp.core.lib import ServiceItemAction, image_to_byte from openlp.core.lib.serviceitem import ItemCapabilities +from openlp.core.ui.media import media_empty_song from openlp.core.lib.ui import create_action from openlp.core.ui import DisplayControllerType, HideMode from openlp.core.ui.icons import UiIcons @@ -842,6 +843,20 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties): self.delay_spin_box.setValue(int(item.timed_slide_interval)) self.on_play_slides_once() + def _set_theme(self, service_item): + """ + Set up the theme from the service item. + + :param service_item: The current service item + """ + # Get theme + theme_data = service_item.get_theme_data() + # Set theme for preview + self.preview_display.set_theme(theme_data, service_item_type=service_item.service_item_type) + # Set theme for displays + for display in self.displays: + display.set_theme(service_item.get_theme_data(), service_item_type=service_item.service_item_type) + def _process_item(self, service_item, slide_no): """ Loads a ServiceItem into the system from ServiceManager. Display the slide number passed. @@ -861,26 +876,15 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties): '{text}_start'.format(text=service_item.name.lower()), [self.service_item, self.is_live, self.hide_mode(), slide_no]) else: - # Get theme - theme_data = service_item.get_theme_data() - # Set theme for preview - self.preview_display.set_theme(theme_data) - # Set theme for displays - for display in self.displays: - display.set_theme(theme_data) - + self._set_theme(service_item) # Reset blanking if needed if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)): self._reset_blank(self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)) self.info_label.setText(self.service_item.title) self.slide_list = {} - if old_item and old_item.is_capable(ItemCapabilities.HasBackgroundAudio): + if old_item and old_item.requires_media(): self.on_media_close() - if self.is_live: - self.song_menu.menu().clear() - if self.service_item.is_capable(ItemCapabilities.HasBackgroundAudio): - self.on_media_start(service_item) row = 0 width = self.main_window.control_splitter.sizes()[self.split] if self.service_item.is_text(): @@ -912,7 +916,10 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties): self.slide_list[str(row)] = row - 1 self.preview_widget.replace_service_item(self.service_item, width, slide_no) self.enable_tool_bar(self.service_item) - if self.service_item.is_media(): + if self.service_item.is_media() or self.service_item.requires_media(): + self._set_theme(service_item) + if self.service_item.is_command(): + self.preview_display.load_verses(media_empty_song, True) self.on_media_start(self.service_item) self.slide_selected(True) if self.service_item.from_service: diff --git a/tests/functional/openlp_core/display/test_window.py b/tests/functional/openlp_core/display/test_window.py index 6906a0342..f9e78aaf5 100644 --- a/tests/functional/openlp_core/display/test_window.py +++ b/tests/functional/openlp_core/display/test_window.py @@ -24,7 +24,6 @@ Package to test the openlp.core.display.window package. import sys import time -from unittest import TestCase from unittest.mock import MagicMock, patch from PyQt5 import QtCore @@ -33,114 +32,117 @@ from PyQt5 import QtCore sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock() from openlp.core.display.window import DisplayWindow -from tests.helpers.testmixin import TestMixin @patch('PyQt5.QtWidgets.QVBoxLayout') @patch('openlp.core.display.webengine.WebEngineView') -@patch('openlp.core.display.window.Settings') -class TestDisplayWindow(TestCase, TestMixin): +def test_x11_override_on(mocked_webengine, mocked_addWidget, mock_settings): """ - A test suite to test the functions in DisplayWindow + Test that the x11 override option bit is set """ + # GIVEN: x11 bypass is on + mock_settings.value.return_value = True - def test_x11_override_on(self, MockSettings, mocked_webengine, mocked_addWidget): - """ - Test that the x11 override option bit is set - """ - # GIVEN: x11 bypass is on - mocked_settings = MagicMock() - mocked_settings.value.return_value = True - MockSettings.return_value = mocked_settings + # WHEN: A DisplayWindow is generated + display_window = DisplayWindow() - # WHEN: A DisplayWindow is generated - display_window = DisplayWindow() + # THEN: The x11 override flag should be set + x11_bit = display_window.windowFlags() & QtCore.Qt.X11BypassWindowManagerHint + assert x11_bit == QtCore.Qt.X11BypassWindowManagerHint - # THEN: The x11 override flag should be set - x11_bit = display_window.windowFlags() & QtCore.Qt.X11BypassWindowManagerHint - assert x11_bit == QtCore.Qt.X11BypassWindowManagerHint - def test_x11_override_off(self, MockSettings, mocked_webengine, mocked_addWidget): - """ - Test that the x11 override option bit is not set when setting if off - """ - # GIVEN: x11 bypass is off - mocked_settings = MagicMock() - mocked_settings.value.return_value = False - MockSettings.return_value = mocked_settings +@patch('PyQt5.QtWidgets.QVBoxLayout') +@patch('openlp.core.display.webengine.WebEngineView') +def test_x11_override_off(mocked_webengine, mocked_addWidget, mock_settings): + """ + Test that the x11 override option bit is not set when setting if off + """ + # GIVEN: x11 bypass is off + mock_settings.value.return_value = False - # WHEN: A DisplayWindow is generated - display_window = DisplayWindow() + # WHEN: A DisplayWindow is generated + display_window = DisplayWindow() - # THEN: The x11 override flag should not be set - x11_bit = display_window.windowFlags() & QtCore.Qt.X11BypassWindowManagerHint - assert x11_bit != QtCore.Qt.X11BypassWindowManagerHint + # THEN: The x11 override flag should not be set + x11_bit = display_window.windowFlags() & QtCore.Qt.X11BypassWindowManagerHint + assert x11_bit != QtCore.Qt.X11BypassWindowManagerHint - def test_set_scale_not_initialised(self, MockSettings, mocked_webengine, mocked_addWidget): - """ - Test that the scale js is not run if the page is not initialised - """ - # GIVEN: A display window not yet initialised - display_window = DisplayWindow() - display_window._is_initialised = False - display_window.run_javascript = MagicMock() - # WHEN: set scale is run - display_window.set_scale(0.5) +@patch('PyQt5.QtWidgets.QVBoxLayout') +def test_set_scale_not_initialised(mocked_addWidget, mock_settings): + """ + Test that the scale js is not run if the page is not initialised + """ + # GIVEN: A display window not yet initialised + display_window = DisplayWindow() + display_window._is_initialised = False + display_window.run_javascript = MagicMock() - # THEN: javascript should not be run - display_window.run_javascript.assert_not_called() + # WHEN: set scale is run + display_window.set_scale(0.5) - def test_set_scale_initialised(self, MockSettings, mocked_webengine, mocked_addWidget): - """ - Test that the scale js is not run if the page is not initialised - """ - # GIVEN: A display window not yet initialised - display_window = DisplayWindow() - display_window._is_initialised = True - display_window.run_javascript = MagicMock() + # THEN: javascript should not be run + display_window.run_javascript.assert_not_called() - # WHEN: set scale is run - display_window.set_scale(0.5) - # THEN: javascript should not be run - display_window.run_javascript.assert_called_once_with('Display.setScale(50.0);') +@patch('PyQt5.QtWidgets.QVBoxLayout') +@patch('openlp.core.display.webengine.WebEngineView') +def test_set_scale_initialised(mocked_webengine, mocked_addWidget, mock_settings): + """ + Test that the scale js is not run if the page is not initialised + """ + # GIVEN: A display window not yet initialised + display_window = DisplayWindow() + display_window._is_initialised = True + display_window.run_javascript = MagicMock() - @patch.object(time, 'time') - def test_run_javascript_no_sync_no_wait(self, MockSettings, mocked_webengine, mocked_addWidget, mock_time): - """ - test a script is run on the webview - """ - # GIVEN: A (fake) webengine page - display_window = DisplayWindow() - webengine_page = MagicMock() - display_window.webview.page = MagicMock(return_value=webengine_page) + # WHEN: set scale is run + display_window.set_scale(0.5) - # WHEN: javascript is requested to run - display_window.run_javascript('javascript to execute') + # THEN: javascript should not be run + display_window.run_javascript.assert_called_once_with('Display.setScale(50.0);') - # THEN: javascript should be run with no delay - webengine_page.runJavaScript.assert_called_once_with('javascript to execute') - mock_time.sleep.assert_not_called() - @patch.object(time, 'time') - def test_run_javascript_sync_no_wait(self, MockSettings, mocked_webengine, mocked_addWidget, mock_time): - """ - test a synced script is run on the webview and immediately returns a result - """ - # GIVEN: A (fake) webengine page with a js callback fn - def save_callback(script, callback): - callback(1234) - display_window = DisplayWindow() - display_window.webview = MagicMock() - webengine_page = MagicMock() - webengine_page.runJavaScript.side_effect = save_callback - display_window.webview.page.return_value = webengine_page +@patch('PyQt5.QtWidgets.QVBoxLayout') +@patch('openlp.core.display.webengine.WebEngineView') +@patch.object(time, 'time') +def test_run_javascript_no_sync_no_wait(mock_time, mocked_webengine, mocked_addWidget, mock_settings): + """ + test a script is run on the webview + """ + # GIVEN: A (fake) webengine page + display_window = DisplayWindow() + webengine_page = MagicMock() + display_window.webview.page = MagicMock(return_value=webengine_page) - # WHEN: javascript is requested to run - result = display_window.run_javascript('javascript to execute', True) + # WHEN: javascript is requested to run + display_window.run_javascript('javascript to execute') - # THEN: javascript should be run with no delay and return with the correct result - assert result == 1234 - webengine_page.runJavaScript.assert_called_once() - mock_time.sleep.assert_not_called() + # THEN: javascript should be run with no delay + webengine_page.runJavaScript.assert_called_once_with('javascript to execute') + mock_time.sleep.assert_not_called() + + +@patch('PyQt5.QtWidgets.QVBoxLayout') +@patch('openlp.core.display.webengine.WebEngineView') +@patch.object(time, 'time') +def test_run_javascript_sync_no_wait(mock_time, mocked_webengine, mocked_addWidget, mock_settings): + """ + test a synced script is run on the webview and immediately returns a result + """ + # GIVEN: A (fake) webengine page with a js callback fn + def save_callback(script, callback): + callback(1234) + display_window = DisplayWindow() + display_window.webview = MagicMock() + webengine_page = MagicMock() + webengine_page.runJavaScript.side_effect = save_callback + display_window.webview.page.return_value = webengine_page + + # WHEN: javascript is requested to run + result = display_window.run_javascript('javascript to execute', True) + + # THEN: javascript should be run with no delay and return with the correct result + assert result == 1234 + webengine_page.runJavaScript.assert_called_once() + mock_time.sleep.assert_not_called() diff --git a/tests/functional/openlp_core/lib/test_serviceitem.py b/tests/functional/openlp_core/lib/test_serviceitem.py index afd53c951..66d187d27 100644 --- a/tests/functional/openlp_core/lib/test_serviceitem.py +++ b/tests/functional/openlp_core/lib/test_serviceitem.py @@ -28,10 +28,11 @@ from unittest.mock import Mock, MagicMock, patch from openlp.core.state import State from openlp.core.common import ThemeLevel, md5_hash +from openlp.core.common.enum import ServiceItemType from openlp.core.common.registry import Registry from openlp.core.common.settings import Settings from openlp.core.lib.formattingtags import FormattingTags -from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem, ServiceItemType +from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem from tests.helpers.testmixin import TestMixin from tests.utils import convert_file_service_item from tests.utils.constants import RESOURCE_PATH @@ -78,6 +79,7 @@ class TestServiceItem(TestCase, TestMixin): Registry.create() # Mock the renderer and its format_slide method mocked_renderer = MagicMock() + Registry().register('settings', Settings()) def side_effect_return_arg(arg1, arg2): return [arg1] diff --git a/tests/functional/openlp_core/ui/media/test_media.py b/tests/functional/openlp_core/ui/media/test_media.py index a3cfbf94f..cd9e9815d 100644 --- a/tests/functional/openlp_core/ui/media/test_media.py +++ b/tests/functional/openlp_core/ui/media/test_media.py @@ -29,7 +29,6 @@ def test_parse_optical_path_linux(): """ Test that test_parse_optical_path() parses a optical path with linux device path correctly """ - # GIVEN: An optical formatted path org_title_track = 1 org_audio_track = 2 @@ -58,7 +57,6 @@ def test_parse_optical_path_win(): """ Test that test_parse_optical_path() parses a optical path with windows device path correctly """ - # GIVEN: An optical formatted path org_title_track = 1 org_audio_track = 2 diff --git a/tests/functional/openlp_core/ui/media/test_mediacontroller.py b/tests/functional/openlp_core/ui/media/test_mediacontroller.py index 946ab6851..169d29198 100644 --- a/tests/functional/openlp_core/ui/media/test_mediacontroller.py +++ b/tests/functional/openlp_core/ui/media/test_mediacontroller.py @@ -21,14 +21,14 @@ """ Package to test the openlp.core.ui.media package. """ -from unittest import TestCase +import pytest + from unittest.mock import MagicMock, patch from openlp.core.common.registry import Registry from openlp.core.ui import DisplayControllerType from openlp.core.ui.media.mediacontroller import MediaController from openlp.core.ui.media import ItemMediaInfo -from tests.helpers.testmixin import TestMixin from tests.utils.constants import RESOURCE_PATH @@ -37,288 +37,290 @@ TEST_PATH = RESOURCE_PATH / 'media' TEST_MEDIA = [['avi_file.avi', 61495], ['mp3_file.mp3', 134426], ['mpg_file.mpg', 9404], ['mp4_file.mp4', 188336]] -class TestMediaController(TestCase, TestMixin): +@pytest.yield_fixture +def media_env(registry): + """Local test setup""" + Registry().register('service_manager', MagicMock()) + media_controller = MediaController() + yield media_controller - def setUp(self): - Registry.create() - Registry().register('service_manager', MagicMock()) - def test_resize(self): - """ - Test that the resize method is called correctly - """ - # GIVEN: A media controller, a player and a display - media_controller = MediaController() - mocked_player = MagicMock() - mocked_display = MagicMock() +def test_resize(media_env): + """ + Test that the resize method is called correctly + """ + # GIVEN: A media controller, a player and a display + mocked_player = MagicMock() + mocked_display = MagicMock() - # WHEN: resize() is called - media_controller.resize(mocked_display, mocked_player) + # WHEN: resize() is called + media_env.media_controller.resize(mocked_display, mocked_player) - # THEN: The player's resize method should be called correctly - mocked_player.resize.assert_called_with(mocked_display) + # THEN: The player's resize method should be called correctly + mocked_player.resize.assert_called_with(mocked_display) - def test_check_file_type_null(self): - """ - Test that we don't try to play media when no players available - """ - # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item - media_controller = MediaController() - mocked_controller = MagicMock() - mocked_display = MagicMock() - media_controller.media_players = MagicMock() - # WHEN: calling _check_file_type when no players exists - ret = media_controller._check_file_type(mocked_controller, mocked_display) +def test_check_file_type_null(media_env): + """ + Test that we don't try to play media when no players available + """ + # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item + mocked_controller = MagicMock() + mocked_display = MagicMock() + media_env.media_controller.media_players = MagicMock() - # THEN: it should return False - assert ret is False, '_check_file_type should return False when no media file matches.' + # WHEN: calling _check_file_type when no players exists + ret = media_env.media_controller._check_file_type(mocked_controller, mocked_display) - def test_check_file_video(self): - """ - Test that we process a file that is valid - """ - # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item - media_controller = MediaController() - mocked_controller = MagicMock() - mocked_display = MagicMock() - media_controller.media_players = MagicMock() - mocked_controller.media_info = ItemMediaInfo() - mocked_controller.media_info.file_info = [TEST_PATH / 'mp3_file.mp3'] - media_controller.current_media_players = {} - media_controller.vlc_player = MagicMock() + # THEN: it should return False + assert ret is False, '_check_file_type should return False when no media file matches.' - # WHEN: calling _check_file_type when no players exists - ret = media_controller._check_file_type(mocked_controller, mocked_display) - # THEN: it should return False - assert ret is True, '_check_file_type should return True when audio file is present and matches.' +def test_check_file_video(media_env): + """ + Test that we process a file that is valid + """ + # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item + mocked_controller = MagicMock() + mocked_display = MagicMock() + media_env.media_controller.media_players = MagicMock() + mocked_controller.media_info = ItemMediaInfo() + mocked_controller.media_info.file_info = [TEST_PATH / 'mp3_file.mp3'] + media_env.media_controller.current_media_players = {} + media_env.media_controller.vlc_player = MagicMock() - def test_check_file_audio(self): - """ - Test that we process a file that is valid - """ - # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item - media_controller = MediaController() - mocked_controller = MagicMock() - mocked_display = MagicMock() - media_controller.media_players = MagicMock() - mocked_controller.media_info = ItemMediaInfo() - mocked_controller.media_info.file_info = [TEST_PATH / 'mp4_file.mp4'] - media_controller.current_media_players = {} - media_controller.vlc_player = MagicMock() + # WHEN: calling _check_file_type when no players exists + ret = media_env.media_controller._check_file_type(mocked_controller, mocked_display) - # WHEN: calling _check_file_type when no players exists - ret = media_controller._check_file_type(mocked_controller, mocked_display) + # THEN: it should return False + assert ret is True, '_check_file_type should return True when audio file is present and matches.' - # THEN: it should return False - assert ret is True, '_check_file_type should return True when media file is present and matches.' - def test_media_play_msg(self): - """ - Test that the media controller responds to the request to play a loaded video - """ - # GIVEN: A media controller and a message with two elements - media_controller = MediaController() - message = (1, 2) +def test_check_file_audio(media_env): + """ + Test that we process a file that is valid + """ + # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item + mocked_controller = MagicMock() + mocked_display = MagicMock() + media_env.media_controller.media_players = MagicMock() + mocked_controller.media_info = ItemMediaInfo() + mocked_controller.media_info.file_info = [TEST_PATH / 'mp4_file.mp4'] + media_env.media_controller.current_media_players = {} + media_env.media_controller.vlc_player = MagicMock() - # WHEN: media_play_msg() is called - with patch.object(media_controller, u'media_play') as mocked_media_play: - media_controller.media_play_msg(message, False) + # WHEN: calling _check_file_type when no players exists + ret = media_env.media_controller._check_file_type(mocked_controller, mocked_display) - # THEN: The underlying method is called - mocked_media_play.assert_called_with(1, False) + # THEN: it should return False + assert ret is True, '_check_file_type should return True when media file is present and matches.' - def test_media_pause_msg(self): - """ - Test that the media controller responds to the request to pause a loaded video - """ - # GIVEN: A media controller and a message with two elements - media_controller = MediaController() - message = (1, 2) - # WHEN: media_play_msg() is called - with patch.object(media_controller, u'media_pause') as mocked_media_pause: - media_controller.media_pause_msg(message) +def test_media_play_msg(media_env): + """ + Test that the media controller responds to the request to play a loaded video + """ + # GIVEN: A media controller and a message with two elements + message = (1, 2) - # THEN: The underlying method is called - mocked_media_pause.assert_called_with(1) + # WHEN: media_play_msg() is called + with patch.object(media_env.media_controller, u'media_play') as mocked_media_play: + media_env.media_controller.media_play_msg(message, False) - def test_media_stop_msg(self): - """ - Test that the media controller responds to the request to stop a loaded video - """ - # GIVEN: A media controller and a message with two elements - media_controller = MediaController() - message = (1, 2) + # THEN: The underlying method is called + mocked_media_play.assert_called_with(1, False) - # WHEN: media_play_msg() is called - with patch.object(media_controller, u'media_stop') as mocked_media_stop: - media_controller.media_stop_msg(message) - # THEN: The underlying method is called - mocked_media_stop.assert_called_with(1) +def test_media_pause_msg(media_env): + """ + Test that the media controller responds to the request to pause a loaded video + """ + # GIVEN: A media controller and a message with two elements + message = (1, 2) - def test_media_volume_msg(self): - """ - Test that the media controller responds to the request to change the volume - """ - # GIVEN: A media controller and a message with two elements - media_controller = MediaController() - message = (1, [50]) + # WHEN: media_play_msg() is called + with patch.object(media_env.media_controller, u'media_pause') as mocked_media_pause: + media_env.media_controller.media_pause_msg(message) - # WHEN: media_play_msg() is called - with patch.object(media_controller, u'media_volume') as mocked_media_volume: - media_controller.media_volume_msg(message) + # THEN: The underlying method is called + mocked_media_pause.assert_called_with(1) - # THEN: The underlying method is called - mocked_media_volume.assert_called_with(1, 50) - def test_media_seek_msg(self): - """ - Test that the media controller responds to the request to seek to a particular position - """ - # GIVEN: A media controller and a message with two elements - media_controller = MediaController() - message = (1, [800]) +def test_media_stop_msg(media_env): + """ + Test that the media controller responds to the request to stop a loaded video + """ + # GIVEN: A media controller and a message with two elements + message = (1, 2) - # WHEN: media_play_msg() is called - with patch.object(media_controller, u'media_seek') as mocked_media_seek: - media_controller.media_seek_msg(message) + # WHEN: media_play_msg() is called + with patch.object(media_env.media_controller, u'media_stop') as mocked_media_stop: + media_env.media_controller.media_stop_msg(message) - # THEN: The underlying method is called - mocked_media_seek.assert_called_with(1, 800) + # THEN: The underlying method is called + mocked_media_stop.assert_called_with(1) - def test_media_length(self): - """ - Test the Media Info basic functionality - """ - media_controller = MediaController() - for test_data in TEST_MEDIA: - # GIVEN: a media file - full_path = str(TEST_PATH / test_data[0]) - # WHEN the media data is retrieved - results = media_controller.media_length(full_path) +def test_media_volume_msg(media_env): + """ + Test that the media controller responds to the request to change the volume + """ + # GIVEN: A media controller and a message with two elements + message = (1, [50]) - # THEN you can determine the run time - assert results == test_data[1], 'The correct duration is returned for ' + test_data[0] + # WHEN: media_play_msg() is called + with patch.object(media_env.media_controller, u'media_volume') as mocked_media_volume: + media_env.media_controller.media_volume_msg(message) - def test_on_media_play(self): - """ - Test the on_media_play method - """ - # GIVEN: A mocked live controller and a mocked media_play() method - mocked_live_controller = MagicMock() - Registry().register('live_controller', mocked_live_controller) - media_controller = MediaController() - media_controller.media_play = MagicMock() + # THEN: The underlying method is called + mocked_media_volume.assert_called_with(1, 50) - # WHEN: the on_media_play() method is called - media_controller.on_media_play() - # The mocked live controller should be called - media_controller.media_play.assert_called_once_with(mocked_live_controller, False) +def test_media_seek_msg(media_env): + """ + Test that the media controller responds to the request to seek to a particular position + """ + # GIVEN: A media controller and a message with two elements + message = (1, [800]) - def test_on_media_pause(self): - """ - Test the on_media_pause method - """ - # GIVEN: A mocked live controller and a mocked media_pause() method - mocked_live_controller = MagicMock() - Registry().register('live_controller', mocked_live_controller) - media_controller = MediaController() - media_controller.media_pause = MagicMock() + # WHEN: media_play_msg() is called + with patch.object(media_env.media_controller, u'media_seek') as mocked_media_seek: + media_env.media_controller.media_seek_msg(message) - # WHEN: the on_media_pause() method is called - media_controller.on_media_pause() + # THEN: The underlying method is called + mocked_media_seek.assert_called_with(1, 800) - # The mocked live controller should be called - media_controller.media_pause.assert_called_once_with(mocked_live_controller) - def test_on_media_stop(self): - """ - Test the on_media_stop method - """ - # GIVEN: A mocked live controller and a mocked media_stop() method - mocked_live_controller = MagicMock() - Registry().register('live_controller', mocked_live_controller) - media_controller = MediaController() - media_controller.media_stop = MagicMock() +def test_media_length(media_env): + """ + Test the Media Info basic functionality + """ + for test_data in TEST_MEDIA: + # GIVEN: a media file + full_path = str(TEST_PATH / test_data[0]) - # WHEN: the on_media_stop() method is called - media_controller.on_media_stop() + # WHEN the media data is retrieved + results = media_env.media_controller.media_length(full_path) - # The mocked live controller should be called - media_controller.media_stop.assert_called_once_with(mocked_live_controller) + # THEN you can determine the run time + assert results == test_data[1], 'The correct duration is returned for ' + test_data[0] - def test_display_controllers_live(self): - """ - Test that the display_controllers() method returns the live controller when requested - """ - # GIVEN: A mocked live controller - media_controller = MediaController() - mocked_live_controller = MagicMock() - mocked_preview_controller = MagicMock() - Registry().register('live_controller', mocked_live_controller) - Registry().register('preview_controller', mocked_preview_controller) - # WHEN: display_controllers() is called with DisplayControllerType.Live - controller = media_controller.display_controllers(DisplayControllerType.Live) +def test_on_media_play(media_env): + """ + Test the on_media_play method + """ + # GIVEN: A mocked live controller and a mocked media_play() method + mocked_live_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + media_env.media_controller.media_play = MagicMock() - # THEN: the controller should be the live controller - assert controller is mocked_live_controller + # WHEN: the on_media_play() method is called + media_env.media_controller.on_media_play() - def test_display_controllers_preview(self): - """ - Test that the display_controllers() method returns the preview controller when requested - """ - # GIVEN: A mocked live controller - media_controller = MediaController() - mocked_live_controller = MagicMock() - mocked_preview_controller = MagicMock() - Registry().register('live_controller', mocked_live_controller) - Registry().register('preview_controller', mocked_preview_controller) + # The mocked live controller should be called + media_env.media_controller.media_play.assert_called_once_with(mocked_live_controller, False) - # WHEN: display_controllers() is called with DisplayControllerType.Preview - controller = media_controller.display_controllers(DisplayControllerType.Preview) - # THEN: the controller should be the live controller - assert controller is mocked_preview_controller +def test_on_media_pause(media_env): + """ + Test the on_media_pause method + """ + # GIVEN: A mocked live controller and a mocked media_pause() method + mocked_live_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + media_env.media_controller.media_pause = MagicMock() - def test_set_controls_visible(self): - """ - Test that "set_controls_visible" sets the media controls on the controller to be visible or not - """ - # GIVEN: A mocked controller - mocked_controller = MagicMock() + # WHEN: the on_media_pause() method is called + media_env.media_controller.on_media_pause() - # WHEN: Set to visible - MediaController.set_controls_visible(mocked_controller, True) + # The mocked live controller should be called + media_env.media_controller.media_pause.assert_called_once_with(mocked_live_controller) - # THEN: The media controls should have been set to visible - mocked_controller.mediabar.setVisible.assert_called_once_with(True) - @patch('openlp.core.ui.media.mediacontroller.ItemMediaInfo') - def test_setup_display(self, MockItemMediaInfo): - """ - Test that the display/controllers are set up correctly - """ - # GIVEN: A media controller object and some mocks - mocked_media_info = MagicMock() - MockItemMediaInfo.return_value = mocked_media_info - media_controller = MediaController() - media_controller.vlc_player = MagicMock() - mocked_display = MagicMock() - media_controller._define_display = MagicMock(return_value=mocked_display) - media_controller.vlc_player = MagicMock() - controller = MagicMock() +def test_on_media_stop(media_env): + """ + Test the on_media_stop method + """ + # GIVEN: A mocked live controller and a mocked media_stop() method + mocked_live_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + media_env.media_controller.media_stop = MagicMock() - # WHEN: setup_display() is called - media_controller.setup_display(controller, True) + # WHEN: the on_media_stop() method is called + media_env.media_controller.on_media_stop() - # THEN: The right calls should have been made - assert controller.media_info == mocked_media_info - assert controller.has_audio is False - media_controller._define_display.assert_called_once_with(controller) - media_controller.vlc_player.setup(controller, mocked_display, False) + # The mocked live controller should be called + media_env.media_controller.media_stop.assert_called_once_with(mocked_live_controller) + + +def test_display_controllers_live(media_env): + """ + Test that the display_controllers() method returns the live controller when requested + """ + # GIVEN: A mocked live controller + mocked_live_controller = MagicMock() + mocked_preview_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + Registry().register('preview_controller', mocked_preview_controller) + + # WHEN: display_controllers() is called with DisplayControllerType.Live + controller = media_env.media_controller.display_controllers(DisplayControllerType.Live) + + # THEN: the controller should be the live controller + assert controller is mocked_live_controller + + +def test_display_controllers_preview(media_env): + """ + Test that the display_controllers() method returns the preview controller when requested + """ + # GIVEN: A mocked live controller + mocked_live_controller = MagicMock() + mocked_preview_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + Registry().register('preview_controller', mocked_preview_controller) + + # WHEN: display_controllers() is called with DisplayControllerType.Preview + controller = media_env.media_controller.display_controllers(DisplayControllerType.Preview) + + # THEN: the controller should be the live controller + assert controller is mocked_preview_controller + + +def test_set_controls_visible(media_env): + """ + Test that "set_controls_visible" sets the media controls on the controller to be visible or not + """ + # GIVEN: A mocked controller + mocked_controller = MagicMock() + + # WHEN: Set to visible + MediaController.set_controls_visible(mocked_controller, True) + + # THEN: The media controls should have been set to visible + mocked_controller.mediabar.setVisible.assert_called_once_with(True) + + +@patch('openlp.core.ui.media.mediacontroller.ItemMediaInfo') +def test_setup_display(MockItemMediaInfo, media_env): + """ + Test that the display/controllers are set up correctly + """ + # GIVEN: A media controller object and some mocks + mocked_media_info = MagicMock() + MockItemMediaInfo.return_value = mocked_media_info + media_env.media_controller.vlc_player = MagicMock() + mocked_display = MagicMock() + media_env.media_controller._define_display = MagicMock(return_value=mocked_display) + media_env.media_controller.vlc_player = MagicMock() + controller = MagicMock() + + # WHEN: setup_display() is called + media_env.media_controller.setup_display(controller, True) + + # THEN: The right calls should have been made + assert controller.media_info == mocked_media_info + assert controller.has_audio is False + media_env.media_controller._define_display.assert_called_once_with(controller) + media_env.media_controller.vlc_player.setup(controller, mocked_display, False) diff --git a/tests/functional/openlp_core/ui/media/test_vlcplayer.py b/tests/functional/openlp_core/ui/media/test_vlcplayer.py index e2c5e7883..6705ac637 100644 --- a/tests/functional/openlp_core/ui/media/test_vlcplayer.py +++ b/tests/functional/openlp_core/ui/media/test_vlcplayer.py @@ -35,7 +35,7 @@ from tests.helpers import MockDateTime @pytest.yield_fixture def vlc_env(): - """An instance of OpenLP""" + """Local test setup""" if 'VLC_PLUGIN_PATH' in os.environ: del os.environ['VLC_PLUGIN_PATH'] if 'openlp.core.ui.media.vendor.vlc' in sys.modules: @@ -60,7 +60,7 @@ def test_not_osx_fix_vlc_22_plugin_path(mocked_is_macosx): assert 'VLC_PLUGIN_PATH' not in os.environ, 'The plugin path should NOT be in the environment variables' -def test_init(): +def test_init(mock_settings): """ Test that the VLC player class initialises correctly """ @@ -81,17 +81,14 @@ def test_init(): @patch('openlp.core.ui.media.vlcplayer.is_macosx') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') -@patch('openlp.core.ui.media.vlcplayer.Settings') -def test_setup(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): +def test_setup(MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win, mock_settings): """ Test the setup method """ # GIVEN: A bunch of mocked out stuff and a VlcPlayer object mocked_is_macosx.return_value = False mocked_is_win.return_value = False - mocked_settings = MagicMock() - mocked_settings.value.return_value = '' - MockedSettings.return_value = mocked_settings + mock_settings.value.return_value = '' mocked_qframe = MagicMock() mocked_qframe.winId.return_value = 2 MockedQtWidgets.QFrame.NoFrame = 1 @@ -114,8 +111,8 @@ def test_setup(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx # THEN: The VLC widget should be set up correctly assert mocked_output_display.vlc_widget == mocked_qframe mocked_qframe.setFrameStyle.assert_called_with(1) - mocked_settings.value.assert_any_call('advanced/hide mouse') - mocked_settings.value.assert_any_call('media/vlc arguments') + mock_settings.value.assert_any_call('advanced/hide mouse') + mock_settings.value.assert_any_call('media/vlc arguments') mocked_vlc.Instance.assert_called_with('--no-video-title-show ') assert mocked_output_display.vlc_instance == mocked_instance mocked_instance.media_player_new.assert_called_with() @@ -132,17 +129,14 @@ def test_setup(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx @patch('openlp.core.ui.media.vlcplayer.is_macosx') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') -@patch('openlp.core.ui.media.vlcplayer.Settings') -def test_setup_has_audio(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): +def test_setup_has_audio(MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win, mock_settings): """ Test the setup method when has_audio is True """ # GIVEN: A bunch of mocked out stuff and a VlcPlayer object mocked_is_macosx.return_value = False mocked_is_win.return_value = False - mocked_settings = MagicMock() - mocked_settings.value.return_value = '' - MockedSettings.return_value = mocked_settings + mock_settings.value.return_value = '' mocked_qframe = MagicMock() mocked_qframe.winId.return_value = 2 MockedQtWidgets.QFrame.NoFrame = 1 @@ -170,17 +164,14 @@ def test_setup_has_audio(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked @patch('openlp.core.ui.media.vlcplayer.is_macosx') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') -@patch('openlp.core.ui.media.vlcplayer.Settings') -def test_setup_visible_mouse(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): +def test_setup_visible_mouse(MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win, mock_settings): """ Test the setup method when Settings().value("hide mouse") is False """ # GIVEN: A bunch of mocked out stuff and a VlcPlayer object mocked_is_macosx.return_value = False mocked_is_win.return_value = False - mocked_settings = MagicMock() - mocked_settings.value.return_value = '' - MockedSettings.return_value = mocked_settings + mock_settings.value.return_value = '' mocked_qframe = MagicMock() mocked_qframe.winId.return_value = 2 MockedQtWidgets.QFrame.NoFrame = 1 @@ -208,17 +199,14 @@ def test_setup_visible_mouse(MockedSettings, MockedQtWidgets, mocked_get_vlc, mo @patch('openlp.core.ui.media.vlcplayer.is_macosx') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') -@patch('openlp.core.ui.media.vlcplayer.Settings') -def test_setup_windows(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): +def test_setup_windows(MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win, mock_settings): """ Test the setup method when running on Windows """ # GIVEN: A bunch of mocked out stuff and a VlcPlayer object mocked_is_macosx.return_value = False mocked_is_win.return_value = True - mocked_settings = MagicMock() - mocked_settings.value.return_value = False - MockedSettings.return_value = mocked_settings + mock_settings.value.return_value = False mocked_qframe = MagicMock() mocked_qframe.winId.return_value = 2 MockedQtWidgets.QFrame.NoFrame = 1 @@ -246,17 +234,14 @@ def test_setup_windows(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_i @patch('openlp.core.ui.media.vlcplayer.is_macosx') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') -@patch('openlp.core.ui.media.vlcplayer.Settings') -def test_setup_osx(MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): +def test_setup_osx(MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win, mock_settings): """ Test the setup method when running on OS X """ # GIVEN: A bunch of mocked out stuff and a VlcPlayer object mocked_is_macosx.return_value = True mocked_is_win.return_value = False - mocked_settings = MagicMock() - mocked_settings.value.return_value = False - MockedSettings.return_value = mocked_settings + mock_settings.value.return_value = False mocked_qframe = MagicMock() mocked_qframe.winId.return_value = 2 MockedQtWidgets.QFrame.NoFrame = 1 diff --git a/tests/functional/openlp_core/ui/test_servicemanager.py b/tests/functional/openlp_core/ui/test_servicemanager.py index 237a7668d..8402eeff0 100644 --- a/tests/functional/openlp_core/ui/test_servicemanager.py +++ b/tests/functional/openlp_core/ui/test_servicemanager.py @@ -28,7 +28,8 @@ import PyQt5 from openlp.core.common import ThemeLevel from openlp.core.common.registry import Registry -from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem, ServiceItemType +from openlp.core.common.enum import ServiceItemType +from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem from openlp.core.ui.servicemanager import ServiceManager from openlp.core.widgets.toolbar import OpenLPToolbar diff --git a/tests/interfaces/openlp_core/widgets/test_views.py b/tests/interfaces/openlp_core/widgets/test_views.py index 1ef009714..b1a8980b8 100644 --- a/tests/interfaces/openlp_core/widgets/test_views.py +++ b/tests/interfaces/openlp_core/widgets/test_views.py @@ -27,6 +27,7 @@ from unittest.mock import MagicMock, patch from PyQt5 import QtGui, QtWidgets from openlp.core.common.registry import Registry +from openlp.core.common.settings import Settings from openlp.core.lib.serviceitem import ServiceItem from openlp.core.state import State from openlp.core.widgets.views import ListPreviewWidget @@ -52,6 +53,7 @@ class TestListPreviewWidget(TestCase, TestMixin): self.image_manager.get_image.return_value = self.image Registry().register('image_manager', self.image_manager) self.preview_widget = ListPreviewWidget(self.main_window, 2) + Registry().register('settings', Settings()) def tearDown(self): """