Merge branch 'settings_plugins_1' into 'master'

Migrate Plugins and media item

See merge request openlp/openlp!122
This commit is contained in:
Tomas Groth 2020-01-18 21:00:13 +00:00
commit 9dd8f51773
24 changed files with 237 additions and 219 deletions

View File

@ -105,7 +105,7 @@ class Plugin(RegistryBase, RegistryProperties):
"""
log.info('loaded')
def __init__(self, name, default_settings, media_item_class=None, settings_tab_class=None, version=None):
def __init__(self, name, media_item_class=None, settings_tab_class=None, version=None):
"""
This is the constructor for the plugin object. This provides an easy way for descendant plugins to populate
common data. This method *must*
@ -117,8 +117,6 @@ class Plugin(RegistryBase, RegistryProperties):
super(MyPlugin, self).__init__('MyPlugin', version='0.1')
:param name: Defaults to *None*. The name of the plugin.
:param default_settings: A dict containing the plugin's settings. The value to each key is the default value
to be used.
:param media_item_class: The class name of the plugin's media item.
:param settings_tab_class: The class name of the plugin's settings tab.
:param version: Defaults to *None*, which means that the same version number is used as OpenLP's version number.
@ -137,17 +135,6 @@ class Plugin(RegistryBase, RegistryProperties):
self.media_item = None
self.weight = 0
self.status = PluginStatus.Inactive
if default_settings:
# Add the default status to the default settings.
default_settings[name + '/status'] = PluginStatus.Inactive
default_settings[name + '/last directory'] = None
# Add settings to the dict of all settings.
Settings.extend_default_settings(default_settings)
# Append a setting for files in the mediamanager (note not all plugins
# which have a mediamanager need this).
if media_item_class is not None:
default_settings['{name}/{name} files'.format(name=name)] = []
Registry().register_function('{name}_add_service_item'.format(name=self.name), self.process_add_service_event)
Registry().register_function('{name}_config_updated'.format(name=self.name), self.config_update)
self._setup(version)

View File

@ -122,7 +122,7 @@ class AlertsPlugin(Plugin):
"""
Class __init__ method
"""
super(AlertsPlugin, self).__init__('alerts', None, settings_tab_class=AlertsTab)
super(AlertsPlugin, self).__init__('alerts', settings_tab_class=AlertsTab)
self.weight = -3
self.icon_path = UiIcons().alert
self.icon = self.icon_path

View File

@ -29,7 +29,6 @@ from PyQt5 import QtCore, QtGui
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import LogMixin, RegistryProperties
from openlp.core.common.registry import Registry, RegistryBase
from openlp.core.common.settings import Settings
from openlp.core.display.screens import ScreenList
@ -81,24 +80,24 @@ class AlertsManager(QtCore.QObject, RegistryBase, LogMixin, RegistryProperties):
Format and request the Alert and start the timer.
"""
if not self.alert_list or (len(ScreenList()) == 1 and
not Settings().value('core/display on monitor')):
not self.settings.value('core/display on monitor')):
return
text = self.alert_list.pop(0)
# Get the rgb color format of the font & background hex colors from settings
rgb_font_color = self.hex_to_rgb(QtGui.QColor(Settings().value('alerts/font color')))
rgb_background_color = self.hex_to_rgb(QtGui.QColor(Settings().value('alerts/background color')))
rgb_font_color = self.hex_to_rgb(QtGui.QColor(self.settings.value('alerts/font color')))
rgb_background_color = self.hex_to_rgb(QtGui.QColor(self.settings.value('alerts/background color')))
# Put alert settings together in dict that will be passed to Display in Javascript
alert_settings = {
'backgroundColor': rgb_background_color,
'location': Settings().value('alerts/location'),
'fontFace': Settings().value('alerts/font face'),
'fontSize': Settings().value('alerts/font size'),
'location': self.settings.value('alerts/location'),
'fontFace': self.settings.value('alerts/font face'),
'fontSize': self.settings.value('alerts/font size'),
'fontColor': rgb_font_color,
'timeout': Settings().value('alerts/timeout'),
'repeat': Settings().value('alerts/repeat'),
'scroll': Settings().value('alerts/scroll')
'timeout': self.settings.value('alerts/timeout'),
'repeat': self.settings.value('alerts/repeat'),
'scroll': self.settings.value('alerts/scroll')
}
self.live_controller.displays[0].alert(text, json.dumps(alert_settings))

View File

@ -44,7 +44,7 @@ class BiblePlugin(Plugin):
log.info('Bible Plugin loaded')
def __init__(self):
super(BiblePlugin, self).__init__('bibles', None, BibleMediaItem, BiblesTab)
super(BiblePlugin, self).__init__('bibles', BibleMediaItem, BiblesTab)
self.weight = -9
self.icon_path = UiIcons().bible
self.icon = UiIcons().bible

View File

@ -28,7 +28,6 @@ from PyQt5 import QtCore, QtWidgets
from openlp.core.common.enum import BibleSearch, DisplayStyle, LayoutStyle
from openlp.core.common.i18n import UiStrings, get_locale_key, translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ServiceItemContext
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.serviceitem import ItemCapabilities
@ -293,7 +292,7 @@ class BibleMediaItem(MediaManagerItem):
:return: None
"""
log.debug('config_update')
visible = Settings().value('{settings_section}/second bibles'.format(settings_section=self.settings_section))
visible = self.settings.value('{settings_section}/second bibles'.format(settings_section=self.settings_section))
self.general_bible_layout.labelForField(self.second_combo_box).setVisible(visible)
self.second_combo_box.setVisible(visible)
@ -317,7 +316,7 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'Text Search'),
translate('BiblesPlugin.MediaItem', 'Search Text...'))
])
if Settings().value(
if self.settings.value(
'{settings_section}/reset to combined quick search'.format(settings_section=self.settings_section)):
self.search_edit.set_current_search_type(BibleSearch.Combined)
self.config_update()
@ -341,7 +340,7 @@ class BibleMediaItem(MediaManagerItem):
self.version_combo_box.addItem(bible[0], bible[1])
self.second_combo_box.addItem(bible[0], bible[1])
# set the default value
bible = Settings().value('{settings_section}/primary bible'.format(settings_section=self.settings_section))
bible = self.settings.value('{settings_section}/primary bible'.format(settings_section=self.settings_section))
find_and_set_in_combo_box(self.version_combo_box, bible)
def reload_bibles(self):
@ -549,7 +548,7 @@ class BibleMediaItem(MediaManagerItem):
# TODO: Change layout_style to a property
self.settings_tab.layout_style = index
self.settings_tab.layout_style_combo_box.setCurrentIndex(index)
Settings().setValue('{section}/verse layout style'.format(section=self.settings_section), index)
self.settings.setValue('{section}/verse layout style'.format(section=self.settings_section), index)
def on_version_combo_box_index_changed(self):
"""
@ -559,7 +558,7 @@ class BibleMediaItem(MediaManagerItem):
"""
self.bible = self.version_combo_box.currentData()
if self.bible is not None:
Settings().setValue('{section}/primary bible'.format(section=self.settings_section), self.bible.name)
self.settings.setValue('{section}/primary bible'.format(section=self.settings_section), self.bible.name)
self.initialise_advanced_bible(self.select_book_combo_box.currentData())
def on_second_combo_box_index_changed(self, selection):
@ -805,7 +804,7 @@ class BibleMediaItem(MediaManagerItem):
:return: None
"""
if not Settings().value('bibles/is search while typing enabled') or \
if not self.settings.value('bibles/is search while typing enabled') or \
not self.bible or self.bible.is_web_bible or \
(self.second_bible and self.bible.is_web_bible):
return

View File

@ -51,7 +51,7 @@ class CustomPlugin(Plugin):
log.info('Custom Plugin loaded')
def __init__(self):
super(CustomPlugin, self).__init__('custom', None, CustomMediaItem, CustomTab)
super(CustomPlugin, self).__init__('custom', CustomMediaItem, CustomTab)
self.weight = -5
self.db_manager = Manager('custom', init_schema)
self.icon_path = UiIcons().clone

View File

@ -27,7 +27,6 @@ from sqlalchemy.sql import and_, func, or_
from openlp.core.common.enum import CustomSearch
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import check_item_selected
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.plugin import PluginStatus
@ -92,8 +91,8 @@ class CustomMediaItem(MediaManagerItem):
Config has been updated so reload values
"""
log.debug('Config loaded')
self.add_custom_from_service = Settings().value(self.settings_section + '/add custom from service')
self.is_search_as_you_type_enabled = Settings().value('advanced/search as type')
self.add_custom_from_service = self.settings.value(self.settings_section + '/add custom from service')
self.is_search_as_you_type_enabled = self.settings.value('advanced/search as type')
def retranslate_ui(self):
"""
@ -238,7 +237,7 @@ class CustomMediaItem(MediaManagerItem):
service_item.title = title
for slide in raw_slides:
service_item.add_from_text(slide)
if Settings().value(self.settings_section + '/display footer') or credit:
if self.settings.value(self.settings_section + '/display footer') or credit:
service_item.raw_footer.append(' '.join([title, credit]))
else:
service_item.raw_footer.append('')

View File

@ -45,7 +45,7 @@ class ImagePlugin(Plugin):
log.info('Image Plugin loaded')
def __init__(self):
super(ImagePlugin, self).__init__('images', None, ImageMediaItem, ImageTab)
super(ImagePlugin, self).__init__('images', ImageMediaItem, ImageTab)
self.manager = Manager('images', init_schema, upgrade_mod=upgrade)
self.weight = -7
self.icon_path = UiIcons().picture

View File

@ -29,7 +29,6 @@ from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, get_natural_key, translate
from openlp.core.common.path import create_paths
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ServiceItemContext, build_icon, check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.plugin import StringContent
@ -407,7 +406,7 @@ class ImageMediaItem(MediaManagerItem):
self.application.set_normal_cursor()
self.load_list(file_paths, target_group)
last_dir = file_paths[0].parent
Settings().setValue(self.settings_section + '/last directory', last_dir)
self.settings.setValue(self.settings_section + '/last directory', last_dir)
def load_list(self, image_paths, target_group=None, initial_load=False):
"""
@ -552,7 +551,7 @@ class ImageMediaItem(MediaManagerItem):
:param context: Why is it being generated
:param kwargs: Consume other unused args specified by the base implementation, but not use by this one.
"""
background = QtGui.QColor(Settings().value(self.settings_section + '/background color'))
background = QtGui.QColor(self.settings.value(self.settings_section + '/background color'))
if item:
items = [item]
else:
@ -679,7 +678,7 @@ class ImageMediaItem(MediaManagerItem):
if check_item_selected(
self.list_view,
translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')):
background = QtGui.QColor(Settings().value(self.settings_section + '/background color'))
background = QtGui.QColor(self.settings.value(self.settings_section + '/background color'))
bitem = self.list_view.selectedItems()[0]
if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
# Only continue when an image is selected.

View File

@ -45,7 +45,7 @@ class MediaPlugin(Plugin):
log.info('{name} MediaPlugin loaded'.format(name=__name__))
def __init__(self):
super(MediaPlugin, self).__init__('media', None, MediaMediaItem)
super(MediaPlugin, self).__init__('media', MediaMediaItem)
self.weight = -6
self.icon_path = UiIcons().video
self.icon = build_icon(self.icon_path)

View File

@ -47,7 +47,7 @@ class PlanningCenterPlugin(Plugin):
"""
Create and set up the PlanningCenter plugin.
"""
super(PlanningCenterPlugin, self).__init__('planningcenter', None, settings_tab_class=PlanningCenterTab)
super(PlanningCenterPlugin, self).__init__('planningcenter', settings_tab_class=PlanningCenterTab)
self.planningcenter_form = None
self.icon = UiIcons().planning_center
self.icon_path = self.icon

View File

@ -25,7 +25,6 @@ from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings, get_natural_key, translate
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.lib import ServiceItemContext, build_icon, check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.serviceitem import ItemCapabilities
@ -125,7 +124,7 @@ class PresentationMediaItem(MediaManagerItem):
Populate the media manager tab
"""
self.list_view.setIconSize(QtCore.QSize(88, 50))
file_paths = Settings().value(self.settings_section + '/presentations files')
file_paths = self.settings.value(self.settings_section + '/presentations files')
self.load_list(file_paths, initial_load=True)
self.populate_display_types()
@ -145,7 +144,7 @@ class PresentationMediaItem(MediaManagerItem):
if self.display_type_combo_box.count() > 1:
self.display_type_combo_box.insertItem(0, self.automatic, userData='automatic')
self.display_type_combo_box.setCurrentIndex(0)
if Settings().value(self.settings_section + '/override app') == QtCore.Qt.Checked:
if self.settings.value(self.settings_section + '/override app') == QtCore.Qt.Checked:
self.presentation_widget.show()
else:
self.presentation_widget.hide()
@ -233,7 +232,7 @@ class PresentationMediaItem(MediaManagerItem):
self.main_window.finished_progress_bar()
for row in row_list:
self.list_view.takeItem(row)
Settings().setValue(self.settings_section + '/presentations files', self.get_file_list())
self.settings.setValue(self.settings_section + '/presentations files', self.get_file_list())
self.application.set_normal_cursor()
def clean_up_thumbnails(self, file_path, clean_for_update=False):
@ -412,7 +411,7 @@ class PresentationMediaItem(MediaManagerItem):
:param show_error: not used
:return:
"""
file_paths = Settings().value(self.settings_section + '/presentations files')
file_paths = self.settings.value(self.settings_section + '/presentations files')
results = []
string = string.lower()
for file_path in file_paths:

View File

@ -55,7 +55,7 @@ class PresentationPlugin(Plugin):
"""
log.debug('Initialised')
self.controllers = {}
Plugin.__init__(self, 'presentations', None, None)
Plugin.__init__(self, 'presentations', None)
self.weight = -8
self.icon_path = UiIcons().presentation
self.icon = build_icon(self.icon_path)

View File

@ -32,7 +32,6 @@ from openlp.core.common.enum import SongSearch
from openlp.core.common.i18n import UiStrings, get_natural_key, translate
from openlp.core.common.path import create_paths
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ServiceItemContext, check_item_selected, create_separated_list
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.plugin import PluginStatus
@ -115,9 +114,9 @@ class SongMediaItem(MediaManagerItem):
Is triggered when the songs config is updated
"""
log.debug('config_updated')
self.is_search_as_you_type_enabled = Settings().value('advanced/search as type')
self.update_service_on_edit = Settings().value(self.settings_section + '/update service on edit')
self.add_song_from_service = Settings().value(self.settings_section + '/add song from service')
self.is_search_as_you_type_enabled = self.settings.value('advanced/search as type')
self.update_service_on_edit = self.settings.value(self.settings_section + '/update service on edit')
self.add_song_from_service = self.settings.value(self.settings_section + '/add song from service')
def retranslate_ui(self):
self.search_text_label.setText('{text}:'.format(text=UiStrings().Search))
@ -564,7 +563,7 @@ class SongMediaItem(MediaManagerItem):
service_item.theme = song.theme_name
service_item.edit_id = item_id
verse_list = SongXML().get_verses(song.lyrics)
if Settings().value('songs/add songbook slide') and song.songbook_entries:
if self.settings.value('songs/add songbook slide') and song.songbook_entries:
first_slide = '\n'
for songbook_entry in song.songbook_entries:
first_slide += '{book} #{num}'.format(book=songbook_entry.songbook.name,
@ -681,10 +680,10 @@ class SongMediaItem(MediaManagerItem):
songbooks = [str(songbook_entry) for songbook_entry in song.songbook_entries]
if song.songbook_entries:
item.raw_footer.append(", ".join(songbooks))
if Settings().value('core/ccli number'):
if self.settings.value('core/ccli number'):
item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
Settings().value('core/ccli number'))
footer_template = Settings().value('songs/footer template')
self.settings.value('core/ccli number'))
footer_template = self.settings.value('songs/footer template')
# Keep this in sync with the list in songstab.py
vars = {
'title': song.title,
@ -703,7 +702,7 @@ class SongMediaItem(MediaManagerItem):
'authors_music_all': authors_music + authors_words_music,
'copyright': song.copyright,
'songbook_entries': songbooks,
'ccli_license': Settings().value('core/ccli number'),
'ccli_license': self.settings.value('core/ccli number'),
'ccli_license_label': translate('SongsPlugin.MediaItem', 'CCLI License'),
'ccli_number': song.ccli_number,
'topics': [topic.name for topic in song.topics]

View File

@ -53,7 +53,7 @@ from openlp.plugins.songs.lib.songstab import SongsTab
log = logging.getLogger(__name__)
__default_settings__ = {
song_footer = {
'songs/footer template': """\
${title}<br/>
@ -121,12 +121,13 @@ class SongsPlugin(Plugin):
"""
Create and set up the Songs plugin.
"""
super(SongsPlugin, self).__init__('songs', __default_settings__, SongMediaItem, SongsTab)
super(SongsPlugin, self).__init__('songs', SongMediaItem, SongsTab)
self.manager = Manager('songs', init_schema, upgrade_mod=upgrade)
self.weight = -10
self.icon_path = UiIcons().music
self.icon = build_icon(self.icon_path)
self.songselect_form = None
self.settings.extend_default_settings(song_footer)
register_endpoint(songs_endpoint)
register_endpoint(api_songs_endpoint)
State().add_service(self.name, self.weight, is_plugin=True)

View File

@ -26,7 +26,6 @@ from sqlalchemy.sql import and_
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.path import create_paths
from openlp.core.common.settings import Settings
from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.songusage.lib.db import SongUsageItem
@ -55,15 +54,15 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
"""
We need to set up the screen
"""
to_date = Settings().value(self.plugin.settings_section + '/to date')
to_date = self.settings.value(self.plugin.settings_section + '/to date')
if not (isinstance(to_date, QtCore.QDate) and to_date.isValid()):
to_date = QtCore.QDate.currentDate()
from_date = Settings().value(self.plugin.settings_section + '/from date')
from_date = self.settings.value(self.plugin.settings_section + '/from date')
if not (isinstance(from_date, QtCore.QDate) and from_date.isValid()):
from_date = to_date.addYears(-1)
self.from_date_calendar.setSelectedDate(from_date)
self.to_date_calendar.setSelectedDate(to_date)
self.report_path_edit.path = Settings().value(self.plugin.settings_section + '/last directory export')
self.report_path_edit.path = self.settings.value(self.plugin.settings_section + '/last directory export')
def on_report_path_edit_path_changed(self, file_path):
"""
@ -72,7 +71,7 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
:param pathlib.Path file_path: The new path.
:rtype: None
"""
Settings().setValue(self.plugin.settings_section + '/last directory export', file_path)
self.settings.setValue(self.plugin.settings_section + '/last directory export', file_path)
def accept(self):
"""
@ -92,8 +91,8 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
'usage_detail_{old}_{new}.txt'
).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
new=self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
Settings().setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate())
Settings().setValue(self.plugin.settings_section + '/to date', self.to_date_calendar.selectedDate())
self.settings.setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate())
self.settings.setValue(self.plugin.settings_section + '/to date', self.to_date_calendar.selectedDate())
usage = self.plugin.manager.get_all_objects(
SongUsageItem, and_(SongUsageItem.usagedate >= self.from_date_calendar.selectedDate().toPyDate(),
SongUsageItem.usagedate < self.to_date_calendar.selectedDate().toPyDate()),

View File

@ -28,7 +28,6 @@ from openlp.core.state import State
from openlp.core.common.actions import ActionList
from openlp.core.common.i18n import translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib.db import Manager
from openlp.core.lib.plugin import Plugin, StringContent
from openlp.core.lib.ui import create_action
@ -51,7 +50,7 @@ class SongUsagePlugin(Plugin):
log.info('SongUsage Plugin loaded')
def __init__(self):
super(SongUsagePlugin, self).__init__('songusage', None)
super(SongUsagePlugin, self).__init__('songusage')
self.manager = Manager('songusage', init_schema, upgrade_mod=upgrade)
self.weight = -4
self.icon = UiIcons().song_usage
@ -116,7 +115,7 @@ class SongUsagePlugin(Plugin):
super(SongUsagePlugin, self).initialise()
Registry().register_function('slidecontroller_live_started', self.display_song_usage)
Registry().register_function('print_service_started', self.print_song_usage)
self.song_usage_active = Settings().value(self.settings_section + '/active')
self.song_usage_active = self.settings.value(self.settings_section + '/active')
# Set the button and checkbox state
self.set_button_state()
action_list = ActionList.get_instance()
@ -150,7 +149,7 @@ class SongUsagePlugin(Plugin):
the UI when necessary,
"""
self.song_usage_active = not self.song_usage_active
Settings().setValue(self.settings_section + '/active', self.song_usage_active)
self.settings.setValue(self.settings_section + '/active', self.song_usage_active)
self.set_button_state()
def set_button_state(self):

View File

@ -31,6 +31,7 @@ from PyQt5 import QtCore, QtWidgets # noqa
sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
from openlp.core.app import OpenLP
from openlp.core.state import State
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
@ -82,3 +83,8 @@ def mock_settings(registry):
yield mock_settings
Registry().remove('settings')
del mock_settings
@pytest.fixture(scope='function')
def state():
State().load_settings()

View File

@ -122,12 +122,9 @@ class TestMediaItem(TestCase, TestMixin):
self.mocked_settings_instance = MagicMock()
self.mocked_settings_instance.value.side_effect = lambda key: self.setting_values[key]
settings_patcher = patch(
'openlp.plugins.bibles.lib.mediaitem.Settings', return_value=self.mocked_settings_instance)
self.addCleanup(settings_patcher.stop)
self.mocked_settings = settings_patcher.start()
Registry.create()
Registry().register('settings', self.mocked_settings_instance)
# self.setup_application()
self.mocked_application = MagicMock()

View File

@ -21,6 +21,7 @@
"""
This module contains tests for the lib submodule of the Images plugin.
"""
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import ANY, MagicMock, patch
@ -32,6 +33,22 @@ from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
from openlp.plugins.images.lib.mediaitem import ImageMediaItem
@pytest.yield_fixture
def mocked_media_item(mock_settings):
"""Local test setup"""
mocked_main_window = MagicMock()
Registry().register('application', MagicMock())
Registry().register('service_list', MagicMock())
Registry().register('main_window', mocked_main_window)
Registry().register('live_controller', MagicMock())
mocked_plugin = MagicMock()
with patch('openlp.plugins.images.lib.mediaitem.MediaManagerItem._setup'), \
patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.setup_item'):
media_item = ImageMediaItem(None, mocked_plugin)
media_item.settings_section = 'images'
yield media_item
class TestImageMediaItem(TestCase):
"""
This is a test case to test various methods in the ImageMediaItem class.
@ -50,40 +67,6 @@ class TestImageMediaItem(TestCase):
self.media_item = ImageMediaItem(None, mocked_plugin)
self.media_item.settings_section = 'images'
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list')
@patch('openlp.plugins.images.lib.mediaitem.Settings')
def test_validate_and_load(self, mocked_settings, mocked_load_list):
"""
Test that the validate_and_load_test() method when called without a group
"""
# GIVEN: A list of files
file_list = [Path('path1', 'image1.jpg'), Path('path2', 'image2.jpg')]
# WHEN: Calling validate_and_load with the list of files
self.media_item.validate_and_load(file_list)
# THEN: load_list should have been called with the file list and None,
# the directory should have been saved to the settings
mocked_load_list.assert_called_once_with(file_list, None)
mocked_settings().setValue.assert_called_once_with(ANY, Path('path1'))
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list')
@patch('openlp.plugins.images.lib.mediaitem.Settings')
def test_validate_and_load_group(self, mocked_settings, mocked_load_list):
"""
Test that the validate_and_load_test() method when called with a group
"""
# GIVEN: A list of files
file_list = [Path('path1', 'image1.jpg'), Path('path2', 'image2.jpg')]
# WHEN: Calling validate_and_load with the list of files and a group
self.media_item.validate_and_load(file_list, 'group')
# THEN: load_list should have been called with the file list and the group name,
# the directory should have been saved to the settings
mocked_load_list.assert_called_once_with(file_list, 'group')
mocked_settings().setValue.assert_called_once_with(ANY, Path('path1'))
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list')
def test_save_new_images_list_empty_list(self, mocked_load_full_list):
"""
@ -280,3 +263,37 @@ class TestImageMediaItem(TestCase):
assert isinstance(item_data, ImageFilenames)
assert 1 == item_data.id
assert Path('/', 'tmp', 'test_file_1.jpg') == item_data.file_path
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list')
def test_validate_and_load(mocked_load_list, mocked_media_item):
"""
Test that the validate_and_load_test() method when called without a group
"""
# GIVEN: A list of files
file_list = [Path('path1', 'image1.jpg'), Path('path2', 'image2.jpg')]
# WHEN: Calling validate_and_load with the list of files
mocked_media_item.validate_and_load(file_list)
# THEN: load_list should have been called with the file list and None,
# the directory should have been saved to the settings
mocked_load_list.assert_called_once_with(file_list, None)
Registry().get('settings').setValue.assert_called_once_with(ANY, Path('path1'))
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list')
def test_validate_and_load_group(mocked_load_list, mocked_media_item):
"""
Test that the validate_and_load_test() method when called with a group
"""
# GIVEN: A list of files
file_list = [Path('path1', 'image1.jpg'), Path('path2', 'image2.jpg')]
# WHEN: Calling validate_and_load with the list of files and a group
mocked_media_item.validate_and_load(file_list, 'group')
# THEN: load_list should have been called with the file list and the group name,
# the directory should have been saved to the settings
mocked_load_list.assert_called_once_with(file_list, 'group')
Registry().get('settings').setValue.assert_called_once_with(ANY, Path('path1'))

View File

@ -29,7 +29,7 @@ from openlp.plugins.media.mediaplugin import MediaPlugin
from tests.helpers.testmixin import TestMixin
class MediaPluginTest(TestCase, TestMixin):
class TestMediaPlugin(TestCase, TestMixin):
"""
Test the media plugin
"""

View File

@ -144,8 +144,7 @@ class TestMediaItem(TestCase, TestMixin):
@patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup')
@patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item')
@patch('openlp.plugins.presentations.lib.mediaitem.Settings')
def test_search(self, mocked_settings, *unreferenced_mocks):
def test_search(self, *unreferenced_mocks):
"""
Test that the search method finds the correct results
"""
@ -156,7 +155,7 @@ class TestMediaItem(TestCase, TestMixin):
path_3 = Path('another_dir', 'ppt_file')
mocked_returned_settings = MagicMock()
mocked_returned_settings.value.return_value = [path_1, path_2, path_3]
mocked_settings.return_value = mocked_returned_settings
Registry().register('settings', mocked_returned_settings)
media_item = PresentationMediaItem(None, MagicMock(), None)
media_item.settings_section = ''

View File

@ -21,6 +21,7 @@
"""
This module contains tests for the lib submodule of the Songs plugin.
"""
import pytest
from unittest import TestCase
from unittest.mock import MagicMock, patch
@ -90,6 +91,29 @@ ${title}<br/>
}
@pytest.yield_fixture
def mocked_media_item(mock_settings):
Registry().register('service_list', MagicMock())
Registry().register('main_window', MagicMock())
mocked_plugin = MagicMock()
with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \
patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'):
media_item = SongMediaItem(None, mocked_plugin)
media_item.save_auto_select_id = MagicMock()
media_item.list_view = MagicMock()
media_item.list_view.save_auto_select_id = MagicMock()
media_item.list_view.clear = MagicMock()
media_item.list_view.addItem = MagicMock()
media_item.list_view.setCurrentItem = MagicMock()
media_item.auto_select_id = -1
media_item.display_songbook = False
media_item.display_copyright_symbol = False
settings = Registry().get('settings')
settings.extend_default_settings(__default_settings__)
QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))
yield media_item
class TestMediaItem(TestCase, TestMixin):
"""
Test the functions in the :mod:`lib` module.
@ -117,6 +141,8 @@ class TestMediaItem(TestCase, TestMixin):
self.setup_application()
self.build_settings()
Settings().extend_default_settings(__default_settings__)
self.settings = self.setting
Registry().register('settings', self.settings)
QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))
def tearDown(self):
@ -348,51 +374,6 @@ class TestMediaItem(TestCase, TestMixin):
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
@patch(u'openlp.plugins.songs.lib.mediaitem.Settings')
def test_build_song_footer_one_author_show_written_by(self, MockedSettings):
"""
Test build songs footer with basic song and one author
"""
# GIVEN: A Song and a Service Item, mocked settings
mocked_settings = MagicMock()
mocked_settings.value.side_effect = [False, "", "0"]
MockedSettings.return_value = mocked_settings
with patch('mako.template.Template.render_unicode') as MockedRenderer:
mock_song = MagicMock()
mock_song.title = 'My Song'
mock_song.alternate_title = ''
mock_song.ccli_number = ''
mock_song.authors_songs = []
mock_author = MagicMock()
mock_author.display_name = 'my author'
mock_author_song = MagicMock()
mock_author_song.author = mock_author
mock_song.authors_songs.append(mock_author_song)
mock_song.copyright = 'My copyright'
mock_song.songbook_entries = []
service_item = ServiceItem(None)
# WHEN: I generate the Footer with default settings
author_list = self.media_item.generate_footer(service_item, mock_song)
# THEN: The mako function was called with the following arguments
args = {'authors_translation': [], 'authors_music_label': 'Music',
'copyright': 'My copyright', 'songbook_entries': [],
'alternate_title': '', 'topics': [], 'authors_music_all': [],
'authors_words_label': 'Words', 'authors_music': [],
'authors_words_music': [], 'ccli_number': '',
'authors_none_label': 'Written by', 'title': 'My Song',
'authors_words_music_label': 'Words and Music',
'authors_none': ['my author'],
'ccli_license_label': 'CCLI License', 'authors_words': [],
'ccli_license': '0', 'authors_translation_label': 'Translation',
'authors_words_all': []}
MockedRenderer.assert_called_once_with(**args)
self.assertEqual(author_list, ['my author'],
'The author list should be returned correctly with one author')
def test_build_song_footer_two_authors(self):
"""
Test build songs footer with basic song and two authors
@ -443,7 +424,7 @@ class TestMediaItem(TestCase, TestMixin):
mock_song.copyright = 'My copyright'
mock_song.songbook_entries = []
service_item = ServiceItem(None)
Settings().setValue('core/ccli number', '1234')
self.settings.setValue('core/ccli number', '1234')
# WHEN: I generate the Footer with default settings
self.media_item.generate_footer(service_item, mock_song)
@ -453,7 +434,7 @@ class TestMediaItem(TestCase, TestMixin):
'The array should be returned correctly with a song, an author, copyright and ccli'
# WHEN: I amend the CCLI value
Settings().setValue('core/ccli number', '4321')
self.settings.setValue('core/ccli number', '4321')
self.media_item.generate_footer(service_item, mock_song)
# THEN: I would get an amended footer string
@ -622,3 +603,45 @@ class TestMediaItem(TestCase, TestMixin):
self.mocked_plugin.manager.session.query.assert_called_once_with(MockedSong)
assert self.mocked_plugin.manager.session.query.mock_calls[4][0] == '().join().join().filter().all'
def test_build_song_footer_one_author_show_written_by(mocked_media_item):
"""
Test build songs footer with basic song and one author
"""
# GIVEN: A Song and a Service Item, mocked settings
mocked_media_item.settings.value.side_effect = [False, "", "0"]
with patch('mako.template.Template.render_unicode') as MockedRenderer:
mock_song = MagicMock()
mock_song.title = 'My Song'
mock_song.alternate_title = ''
mock_song.ccli_number = ''
mock_song.authors_songs = []
mock_author = MagicMock()
mock_author.display_name = 'my author'
mock_author_song = MagicMock()
mock_author_song.author = mock_author
mock_song.authors_songs.append(mock_author_song)
mock_song.copyright = 'My copyright'
mock_song.songbook_entries = []
service_item = ServiceItem(None)
# WHEN: I generate the Footer with default settings
author_list = mocked_media_item.generate_footer(service_item, mock_song)
# THEN: The mako function was called with the following arguments
args = {'authors_translation': [], 'authors_music_label': 'Music',
'copyright': 'My copyright', 'songbook_entries': [],
'alternate_title': '', 'topics': [], 'authors_music_all': [],
'authors_words_label': 'Words', 'authors_music': [],
'authors_words_music': [], 'ccli_number': '',
'authors_none_label': 'Written by', 'title': 'My Song',
'authors_words_music_label': 'Words and Music',
'authors_none': ['my author'],
'ccli_license_label': 'CCLI License', 'authors_words': [],
'ccli_license': '0', 'authors_translation_label': 'Translation',
'authors_words_all': []}
MockedRenderer.assert_called_once_with(**args)
assert author_list == ['my author'], 'The author list should be returned correctly with one author'

View File

@ -21,78 +21,74 @@
"""
This module contains tests for the Songusage plugin.
"""
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core.common.registry import Registry
from openlp.plugins.songusage.lib import upgrade
from openlp.plugins.songusage.lib.db import init_schema
from openlp.plugins.songusage.songusageplugin import SongUsagePlugin
class TestSongUsage(TestCase):
def test_about_text(state, mock_settings):
"""
Test the about text of the song usage plugin
"""
# GIVEN: The SongUsagePlugin
# WHEN: Retrieving the about text
# THEN: about() should return a string object
assert isinstance(SongUsagePlugin.about(), str)
# THEN: about() should return a non-empty string
assert len(SongUsagePlugin.about()) != 0
assert len(SongUsagePlugin.about()) != 0
def setUp(self):
Registry.create()
def test_about_text(self):
"""
Test the about text of the song usage plugin
"""
# GIVEN: The SongUsagePlugin
# WHEN: Retrieving the about text
# THEN: about() should return a string object
assert isinstance(SongUsagePlugin.about(), str)
# THEN: about() should return a non-empty string
assert len(SongUsagePlugin.about()) != 0
assert len(SongUsagePlugin.about()) != 0
@patch('openlp.plugins.songusage.songusageplugin.Manager')
def test_song_usage_init(MockedManager, settings):
"""
Test the initialisation of the SongUsagePlugin class
"""
# GIVEN: A mocked database manager
mocked_manager = MagicMock()
MockedManager.return_value = mocked_manager
@patch('openlp.plugins.songusage.songusageplugin.Manager')
def test_song_usage_init(self, MockedManager):
"""
Test the initialisation of the SongUsagePlugin class
"""
# GIVEN: A mocked database manager
mocked_manager = MagicMock()
MockedManager.return_value = mocked_manager
# WHEN: The SongUsagePlugin class is instantiated
song_usage = SongUsagePlugin()
# WHEN: The SongUsagePlugin class is instantiated
song_usage = SongUsagePlugin()
# THEN: It should be initialised correctly
MockedManager.assert_called_with('songusage', init_schema, upgrade_mod=upgrade)
assert mocked_manager == song_usage.manager
assert song_usage.song_usage_active is False
# THEN: It should be initialised correctly
MockedManager.assert_called_with('songusage', init_schema, upgrade_mod=upgrade)
assert mocked_manager == song_usage.manager
assert song_usage.song_usage_active is False
@patch('openlp.plugins.songusage.songusageplugin.Manager')
def test_check_pre_conditions(self, MockedManager):
"""
Test that check_pre_condition returns true for valid manager session
"""
# GIVEN: A mocked database manager
mocked_manager = MagicMock()
mocked_manager.session = MagicMock()
MockedManager.return_value = mocked_manager
song_usage = SongUsagePlugin()
@patch('openlp.plugins.songusage.songusageplugin.Manager')
def test_check_pre_conditions(MockedManager, settings):
"""
Test that check_pre_condition returns true for valid manager session
"""
# GIVEN: A mocked database manager
mocked_manager = MagicMock()
mocked_manager.session = MagicMock()
MockedManager.return_value = mocked_manager
song_usage = SongUsagePlugin()
# WHEN: The calling check_pre_conditions
ret = song_usage.check_pre_conditions()
# WHEN: The calling check_pre_conditions
ret = song_usage.check_pre_conditions()
# THEN: It should return True
assert ret is True
# THEN: It should return True
assert ret is True
@patch('openlp.plugins.songusage.songusageplugin.Manager')
def test_toggle_song_usage_state(self, MockedManager):
"""
Test that toggle_song_usage_state does toggle song_usage_state
"""
# GIVEN: A SongUsagePlugin
song_usage = SongUsagePlugin()
song_usage.set_button_state = MagicMock()
song_usage.song_usage_active = True
# WHEN: calling toggle_song_usage_state
song_usage.toggle_song_usage_state()
@patch('openlp.plugins.songusage.songusageplugin.Manager')
def test_toggle_song_usage_state(MockedManager, settings):
"""
Test that toggle_song_usage_state does toggle song_usage_state
"""
# GIVEN: A SongUsagePlugin
song_usage = SongUsagePlugin()
song_usage.set_button_state = MagicMock()
song_usage.song_usage_active = True
# THEN: song_usage_state should have been toogled
assert song_usage.song_usage_active is False
# WHEN: calling toggle_song_usage_state
song_usage.toggle_song_usage_state()
# THEN: song_usage_state should have been toogled
assert song_usage.song_usage_active is False