Merge branch 'tests_4' into 'master'

Tests 4

See merge request openlp/openlp!140
This commit is contained in:
Tim Bentley 2020-02-18 08:08:39 +00:00
commit 2405ed7e4f
15 changed files with 1802 additions and 1839 deletions

View File

@ -71,6 +71,7 @@ def settings(qapp, registry):
sets = Settings()
sets.setValue('themes/global theme', 'my_theme')
Registry().register('settings', sets)
Registry().register('application', qapp)
qapp.settings = sets
yield sets
del sets

View File

@ -22,54 +22,52 @@
Package to test the openlp.core.ui.firsttimeform package.
"""
import datetime
from unittest import TestCase
from unittest.mock import patch
from openlp.core.ui.aboutform import AboutForm
from tests.helpers.testmixin import TestMixin
class TestAboutForm(TestCase, TestMixin):
@patch('openlp.core.ui.aboutform.webbrowser')
def test_on_contribute_button_clicked(mocked_webbrowser):
"""
Test that clicking on the "Volunteer" button opens a web page.
"""
# GIVEN: A new About dialog and a mocked out webbrowser module
about_form = AboutForm(None)
@patch('openlp.core.ui.aboutform.webbrowser')
def test_on_contribute_button_clicked(self, mocked_webbrowser):
"""
Test that clicking on the "Volunteer" button opens a web page.
"""
# GIVEN: A new About dialog and a mocked out webbrowser module
about_form = AboutForm(None)
# WHEN: The "Volunteer" button is "clicked"
about_form.on_contribute_button_clicked()
# WHEN: The "Volunteer" button is "clicked"
about_form.on_contribute_button_clicked()
# THEN: A web browser is opened
mocked_webbrowser.open_new.assert_called_with('http://openlp.org/contribute')
# THEN: A web browser is opened
mocked_webbrowser.open_new.assert_called_with('http://openlp.org/contribute')
@patch('openlp.core.ui.aboutform.get_version')
def test_about_form_build_number(self, mocked_get_version):
"""
Test that the build number is added to the about form
"""
# GIVEN: A mocked out get_version function
mocked_get_version.return_value = {'version': '3.1.5', 'build': '3000'}
@patch('openlp.core.ui.aboutform.get_version')
def test_about_form_build_number(mocked_get_version):
"""
Test that the build number is added to the about form
"""
# GIVEN: A mocked out get_version function
mocked_get_version.return_value = {'version': '3.1.5', 'build': '3000'}
# WHEN: The about form is created
about_form = AboutForm(None)
# WHEN: The about form is created
about_form = AboutForm(None)
# THEN: The build number should be in the text
assert 'OpenLP 3.1.5 build 3000' in about_form.about_text_edit.toPlainText(), \
"The build number should be set correctly"
# THEN: The build number should be in the text
assert 'OpenLP 3.1.5 build 3000' in about_form.about_text_edit.toPlainText(), \
"The build number should be set correctly"
def test_about_form_date(self):
"""
Test that the copyright date is included correctly
"""
# GIVEN: A correct application date
date_string = '2004-{year}'.format(year=datetime.date.today().year)
# WHEN: The about form is created
about_form = AboutForm(None)
about_text = about_form.about_text_edit.toPlainText()
def test_about_form_date():
"""
Test that the copyright date is included correctly
"""
# GIVEN: A correct application date
date_string = '2004-{year}'.format(year=datetime.date.today().year)
# THEN: The date should be in the text twice.
assert about_text.count(date_string, 0) == 1, "The text string should be added twice to the license string"
# WHEN: The about form is created
about_form = AboutForm(None)
about_text = about_form.about_text_edit.toPlainText()
# THEN: The date should be in the text twice.
assert about_text.count(date_string, 0) == 1, "The text string should be added twice to the license string"

View File

@ -21,49 +21,36 @@
"""
Package to test the openlp.core.ui.advancedtab package.
"""
from unittest import TestCase
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.ui.advancedtab import AdvancedTab
from openlp.core.ui.settingsform import SettingsForm
from tests.helpers.testmixin import TestMixin
class TestAdvancedTab(TestCase, TestMixin):
def test_creation(settings):
"""
Test that Advanced Tab is created.
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
def setUp(self):
"""
Set up a few things for the tests
"""
Registry.create()
Registry().register('settings', Settings())
# WHEN: I create an advanced tab
advanced_tab = AdvancedTab(settings_form)
def test_creation(self):
"""
Test that Advanced Tab is created.
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
# THEN:
assert "Advanced" == advanced_tab.tab_title, 'The tab title should be Advanced'
# WHEN: I create an advanced tab
advanced_tab = AdvancedTab(settings_form)
# THEN:
assert "Advanced" == advanced_tab.tab_title, 'The tab title should be Advanced'
def test_change_search_as_type(settings):
"""
Test that when search as type is changed custom and song configs are updated
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
advanced_tab = AdvancedTab(settings_form)
def test_change_search_as_type(self):
"""
Test that when search as type is changed custom and song configs are updated
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
advanced_tab = AdvancedTab(settings_form)
# WHEN: I change search as type check box
advanced_tab.on_search_as_type_check_box_changed(True)
# WHEN: I change search as type check box
advanced_tab.on_search_as_type_check_box_changed(True)
# THEN: we should have two post save processed to run
assert 2 == len(settings_form.processes), 'Two post save processes should be created'
assert "songs_config_updated" in settings_form.processes, 'The songs plugin should be called'
assert "custom_config_updated" in settings_form.processes, 'The custom plugin should be called'
# THEN: we should have two post save processed to run
assert 2 == len(settings_form.processes), 'Two post save processes should be created'
assert "songs_config_updated" in settings_form.processes, 'The songs plugin should be called'
assert "custom_config_updated" in settings_form.processes, 'The custom plugin should be called'

View File

@ -21,17 +21,14 @@
"""
Package to test the openlp.core.ui.firsttimeform package.
"""
import os
import tempfile
import pytest
from pathlib import Path
from unittest import TestCase, SkipTest
from unittest.mock import MagicMock, call, patch, DEFAULT
from PyQt5 import QtWidgets
from openlp.core.common.registry import Registry
from openlp.core.ui.firsttimeform import FirstTimeForm, ThemeListWidgetItem
from tests.helpers.testmixin import TestMixin
INVALID_CONFIG = """
@ -41,281 +38,280 @@ INVALID_CONFIG = """
}
"""
sample_theme_data = {'file_name': 'BlueBurst.otz', 'sha256': 'sha_256_hash',
'thumbnail': 'BlueBurst.png', 'title': 'Blue Burst'}
class TestThemeListWidgetItem(TestCase):
@pytest.fixture()
def ftf_app(registry, qapp):
Registry().register('application', qapp)
@pytest.yield_fixture()
def download_env(registry):
download_worker_patcher = patch('openlp.core.ui.firsttimeform.DownloadWorker')
run_thread_patcher = patch('openlp.core.ui.firsttimeform.run_thread')
mocked_download_worker = download_worker_patcher.start()
mocked_run_thread = run_thread_patcher.start()
yield mocked_download_worker, mocked_run_thread
download_worker_patcher.stop()
run_thread_patcher.stop()
def test_init_sample_data(download_env):
"""
Test the :class:`ThemeListWidgetItem` class
Test that the theme data is loaded correctly in to a ThemeListWidgetItem object when instantiated
"""
# GIVEN: A sample theme dictionary object
# WHEN: Creating an instance of `ThemeListWidgetItem`
mocked_download_worker = download_env[0]
instance = ThemeListWidgetItem('url', sample_theme_data, MagicMock())
def setUp(self):
self.sample_theme_data = {'file_name': 'BlueBurst.otz', 'sha256': 'sha_256_hash',
'thumbnail': 'BlueBurst.png', 'title': 'Blue Burst'}
download_worker_patcher = patch('openlp.core.ui.firsttimeform.DownloadWorker')
self.addCleanup(download_worker_patcher.stop)
self.mocked_download_worker = download_worker_patcher.start()
run_thread_patcher = patch('openlp.core.ui.firsttimeform.run_thread')
self.addCleanup(run_thread_patcher.stop)
self.mocked_run_thread = run_thread_patcher.start()
def test_init_sample_data(self):
"""
Test that the theme data is loaded correctly in to a ThemeListWidgetItem object when instantiated
"""
# GIVEN: A sample theme dictionary object
# WHEN: Creating an instance of `ThemeListWidgetItem`
instance = ThemeListWidgetItem('url', self.sample_theme_data, MagicMock())
# THEN: The data should have been set correctly
assert instance.file_name == 'BlueBurst.otz'
assert instance.sha256 == 'sha_256_hash'
assert instance.text() == 'Blue Burst'
assert instance.toolTip() == 'Blue Burst'
self.mocked_download_worker.assert_called_once_with('url', 'BlueBurst.png')
def test_init_download_worker(self):
"""
Test that the `DownloadWorker` worker is set up correctly and that the thread is started.
"""
# GIVEN: A sample theme dictionary object
mocked_ftw = MagicMock(spec=FirstTimeForm)
mocked_ftw.thumbnail_download_threads = []
# WHEN: Creating an instance of `ThemeListWidgetItem`
instance = ThemeListWidgetItem('url', self.sample_theme_data, mocked_ftw)
# THEN: The `DownloadWorker` should have been set up with the appropriate data
self.mocked_download_worker.assert_called_once_with('url', 'BlueBurst.png')
self.mocked_download_worker.download_failed.connect.called_once_with(instance._on_download_failed())
self.mocked_download_worker.download_succeeded.connect.called_once_with(instance._on_thumbnail_downloaded)
self.mocked_run_thread.assert_called_once_with(
self.mocked_download_worker(), 'thumbnail_download_BlueBurst.png')
assert mocked_ftw.thumbnail_download_threads == ['thumbnail_download_BlueBurst.png']
# THEN: The data should have been set correctly
assert instance.file_name == 'BlueBurst.otz'
assert instance.sha256 == 'sha_256_hash'
assert instance.text() == 'Blue Burst'
assert instance.toolTip() == 'Blue Burst'
mocked_download_worker.assert_called_once_with('url', 'BlueBurst.png')
class TestFirstTimeForm(TestCase, TestMixin):
def test_init_download_worker(download_env):
"""
Test that the `DownloadWorker` worker is set up correctly and that the thread is started.
"""
# GIVEN: A sample theme dictionary object
mocked_download_worker = download_env[0]
mocked_run_thread = download_env[1]
mocked_ftw = MagicMock(spec=FirstTimeForm)
mocked_ftw.thumbnail_download_threads = []
def setUp(self):
self.setup_application()
self.app.setApplicationVersion('0.0')
# Set up a fake "set_normal_cursor" method since we're not dealing with an actual OpenLP application object
self.app.set_normal_cursor = lambda: None
self.app.process_events = lambda: None
Registry.create()
Registry().register('application', self.app)
Registry().register('settings', MagicMock)
self.tempfile = os.path.join(tempfile.gettempdir(), 'testfile')
# WHEN: Creating an instance of `ThemeListWidgetItem`
instance = ThemeListWidgetItem('url', sample_theme_data, mocked_ftw)
def tearDown(self):
if os.path.isfile(self.tempfile):
os.remove(self.tempfile)
# THEN: The `DownloadWorker` should have been set up with the appropriate data
mocked_download_worker.assert_called_once_with('url', 'BlueBurst.png')
mocked_download_worker.download_failed.connect.called_once_with(instance._on_download_failed())
mocked_download_worker.download_succeeded.connect.called_once_with(instance._on_thumbnail_downloaded)
mocked_run_thread.assert_called_once_with(mocked_download_worker(), 'thumbnail_download_BlueBurst.png')
assert mocked_ftw.thumbnail_download_threads == ['thumbnail_download_BlueBurst.png']
def test_initialise(self):
"""
Test if we can intialise the FirstTimeForm
"""
# GIVEN: A First Time Wizard and an expected screen object
frw = FirstTimeForm(None)
expected_screens = MagicMock()
# WHEN: The First Time Wizard is initialised
frw.initialize(expected_screens)
def test_firsttimeform_initialise():
"""
Test if we can intialise the FirstTimeForm
"""
# GIVEN: A First Time Wizard and an expected screen object
frw = FirstTimeForm(None)
expected_screens = MagicMock()
# THEN: The screens should be set up, and the default values initialised
assert expected_screens == frw.screens, 'The screens should be correct'
assert frw.has_web_access is True, 'The default value of self.web_access should be True'
assert [] == frw.thumbnail_download_threads, 'The list of threads should be empty'
assert frw.has_run_wizard is False, 'has_run_wizard should be False'
# WHEN: The First Time Wizard is initialised
frw.initialize(expected_screens)
@patch('openlp.core.ui.firsttimeform.QtWidgets.QWizard.exec')
def test_exec(self, mocked_qwizard_exec):
# THEN: The screens should be set up, and the default values initialised
assert expected_screens == frw.screens, 'The screens should be correct'
assert frw.has_web_access is True, 'The default value of self.web_access should be True'
assert [] == frw.thumbnail_download_threads, 'The list of threads should be empty'
assert frw.has_run_wizard is False, 'has_run_wizard should be False'
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, 'set_defaults') as mocked_set_defaults:
# WHEN: exec is called
frw.exec()
@patch('openlp.core.ui.firsttimeform.QtWidgets.QWizard.exec')
def test_firsttimeform_exec(mocked_qwizard_exec):
# THEN: The wizard should be reset and the exec methon on the super class should have been called
mocked_set_defaults.assert_called_once()
mocked_qwizard_exec.assert_called_once()
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, 'set_defaults') as mocked_set_defaults:
@SkipTest
def test_set_defaults(self):
"""
Test that the default values are set when set_defaults() is run
"""
# GIVEN: An initialised FRW and a whole lot of stuff mocked out
frw = FirstTimeForm(None)
frw.initialize(MagicMock())
mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda key: {'core/has run wizard': False}[key]
with patch.object(frw, 'restart') as mocked_restart, \
patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
patch.object(frw, 'theme_combo_box') as mocked_theme_combo_box, \
patch.object(frw, 'songs_check_box') as mocked_songs_check_box, \
patch.object(Registry, 'register_function') as mocked_register_function, \
patch('openlp.core.ui.firsttimeform.Settings', return_value=mocked_settings), \
patch('openlp.core.ui.firsttimeform.gettempdir', return_value='temp') as mocked_gettempdir, \
patch('openlp.core.ui.firsttimeform.create_paths') as mocked_create_paths, \
patch.object(frw.application, 'set_normal_cursor'):
mocked_theme_manager = MagicMock()
Registry().register('theme_manager', mocked_theme_manager)
# WHEN: exec is called
frw.exec()
# WHEN: The set_defaults() method is run
frw.set_defaults()
# THEN: The wizard should be reset and the exec methon on the super class should have been called
mocked_set_defaults.assert_called_once()
mocked_qwizard_exec.assert_called_once()
# THEN: The default values should have been set
mocked_restart.assert_called_once()
assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set'
mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed)
mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load)
mocked_settings.value.assert_has_calls([call('core/has run wizard')])
mocked_gettempdir.assert_called_once()
mocked_create_paths.assert_called_once_with(Path('temp', 'openlp'))
mocked_theme_combo_box.clear.assert_called_once()
mocked_theme_manager.assert_not_called()
mocked_songs_check_box.assert_not_called()
@patch('openlp.core.ui.firsttimeform.QtWidgets.QWizard.accept')
def test_accept_method(self, mocked_qwizard_accept, *args):
"""
Test the FirstTimeForm.accept method
"""
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status') as mocked_set_plugin_status, \
patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT,
image_check_box=DEFAULT, media_check_box=DEFAULT, custom_check_box=DEFAULT,
song_usage_check_box=DEFAULT, alert_check_box=DEFAULT) as mocked_check_boxes, \
patch.object(frw, 'screen_selection_widget') as mocked_screen_selection_widget:
def test_set_defaults(mock_settings, ftf_app):
"""
Test that the default values are set when set_defaults() is run
"""
# GIVEN: An initialised FRW and a whole lot of stuff mocked out
frw = FirstTimeForm(None)
frw.initialize(MagicMock())
mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda key: {'core/has run wizard': False}[key]
with patch.object(frw, 'restart') as mocked_restart, \
patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
patch.object(frw, 'theme_combo_box') as mocked_theme_combo_box, \
patch.object(frw, 'songs_check_box') as mocked_songs_check_box, \
patch.object(Registry, 'register_function') as mocked_register_function, \
patch('openlp.core.ui.firsttimeform.gettempdir', return_value='temp') as mocked_gettempdir, \
patch('openlp.core.ui.firsttimeform.create_paths') as mocked_create_paths, \
patch.object(frw.application, 'set_normal_cursor'):
mocked_theme_manager = MagicMock()
Registry().register('theme_manager', mocked_theme_manager)
Registry().remove('settings')
Registry().register('settings', mocked_settings)
# WHEN: Calling accept
frw.accept()
# WHEN: The set_defaults() method is run
frw.set_defaults()
# THEN: The selected plugins should be enabled, the screen selection saved and the super method called
mocked_set_plugin_status.assert_has_calls([
call(mocked_check_boxes['songs_check_box'], 'songs/status'),
call(mocked_check_boxes['bible_check_box'], 'bibles/status'),
call(mocked_check_boxes['presentation_check_box'], 'presentations/status'),
call(mocked_check_boxes['image_check_box'], 'images/status'),
call(mocked_check_boxes['media_check_box'], 'media/status'),
call(mocked_check_boxes['custom_check_box'], 'custom/status'),
call(mocked_check_boxes['song_usage_check_box'], 'songusage/status'),
call(mocked_check_boxes['alert_check_box'], 'alerts/status')])
mocked_screen_selection_widget.save.assert_called_once()
mocked_qwizard_accept.assert_called_once()
# THEN: The default values should have been set
mocked_restart.assert_called_once()
assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set'
mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed)
mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load)
mocked_settings.value.assert_has_calls([call('core/has run wizard')])
mocked_gettempdir.assert_called_once()
mocked_create_paths.assert_called_once_with(Path('temp', 'openlp'))
mocked_theme_combo_box.clear.assert_called_once()
mocked_theme_manager.assert_not_called()
mocked_songs_check_box.assert_not_called()
def test_accept_method_theme_not_selected(self):
"""
Test the FirstTimeForm.accept method when there is no default theme selected
"""
# GIVEN: An instance of FirstTimeForm
mocked_settings = Registry().get('settings')
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status'), patch.object(frw, 'screen_selection_widget'), \
patch.object(frw, 'theme_combo_box', **{'currentIndex.return_value': -1}):
# WHEN: Calling accept and the currentIndex method of the theme_combo_box returns -1
frw.accept()
@patch('openlp.core.ui.firsttimeform.QtWidgets.QWizard.accept')
def test_accept_method(mocked_qwizard_accept, registry, *args):
"""
Test the FirstTimeForm.accept method
"""
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status') as mocked_set_plugin_status, \
patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT,
image_check_box=DEFAULT, media_check_box=DEFAULT, custom_check_box=DEFAULT,
song_usage_check_box=DEFAULT, alert_check_box=DEFAULT) as mocked_check_boxes, \
patch.object(frw, 'screen_selection_widget') as mocked_screen_selection_widget:
# THEN: OpenLP should not try to save a theme name
mocked_settings().setValue.assert_not_called()
# WHEN: Calling accept
frw.accept()
@patch('openlp.core.ui.firsttimeform.QtWidgets.QWizard.reject')
@patch('openlp.core.ui.firsttimeform.time')
@patch('openlp.core.ui.firsttimeform.get_thread_worker')
@patch('openlp.core.ui.firsttimeform.is_thread_finished')
def test_reject_method(
self, mocked_is_thread_finished, mocked_get_thread_worker, mocked_time, mocked_qwizard_reject):
"""
Test that the reject method shuts down the threads correctly
"""
# GIVEN: A FRW, some mocked threads and workers (that isn't quite done) and other mocked stuff
mocked_worker = MagicMock()
mocked_get_thread_worker.return_value = mocked_worker
mocked_is_thread_finished.side_effect = [False, True]
frw = FirstTimeForm(None)
frw.initialize(MagicMock())
frw.thumbnail_download_threads = ['test_thread']
with patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor:
# THEN: The selected plugins should be enabled, the screen selection saved and the super method called
mocked_set_plugin_status.assert_has_calls([
call(mocked_check_boxes['songs_check_box'], 'songs/status'),
call(mocked_check_boxes['bible_check_box'], 'bibles/status'),
call(mocked_check_boxes['presentation_check_box'], 'presentations/status'),
call(mocked_check_boxes['image_check_box'], 'images/status'),
call(mocked_check_boxes['media_check_box'], 'media/status'),
call(mocked_check_boxes['custom_check_box'], 'custom/status'),
call(mocked_check_boxes['song_usage_check_box'], 'songusage/status'),
call(mocked_check_boxes['alert_check_box'], 'alerts/status')])
mocked_screen_selection_widget.save.assert_called_once()
mocked_qwizard_accept.assert_called_once()
# WHEN: the reject method is called
frw.reject()
# THEN: The right things should be called in the right order
mocked_get_thread_worker.assert_called_once_with('test_thread')
mocked_worker.cancel_download.assert_called_once()
mocked_is_thread_finished.assert_called_with('test_thread')
assert mocked_is_thread_finished.call_count == 2, 'isRunning() should have been called twice'
mocked_time.sleep.assert_called_once_with(0.1)
mocked_set_normal_cursor.assert_called_once()
mocked_qwizard_reject.assert_called_once()
def test_accept_method_theme_not_selected(mock_settings):
"""
Test the FirstTimeForm.accept method when there is no default theme selected
"""
# GIVEN: An instance of FirstTimeForm
mock_settings = Registry().get('settings')
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status'), patch.object(frw, 'screen_selection_widget'), \
patch.object(frw, 'theme_combo_box', **{'currentIndex.return_value': -1}):
@patch('openlp.core.ui.firsttimeform.ProxyDialog')
def test_on_custom_button_clicked(self, mocked_proxy_dialog):
"""
Test _on_custom_button when it is called whe the 'internet settings' (CustomButton1) button is not clicked.
"""
# GIVEN: An instance of the FirstTimeForm
frw = FirstTimeForm(None)
# WHEN: Calling accept and the currentIndex method of the theme_combo_box returns -1
frw.accept()
# WHEN: Calling _on_custom_button_clicked with a different button to the 'internet settings button.
frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton2)
# THEN: OpenLP should not try to save a theme name
mock_settings().setValue.assert_not_called()
# THEN: The ProxyDialog should not be shown.
mocked_proxy_dialog.assert_not_called()
@patch('openlp.core.ui.firsttimeform.ProxyDialog')
def test_on_custom_button_clicked_internet_settings(self, mocked_proxy_dialog):
"""
Test _on_custom_button when it is called when the 'internet settings' (CustomButton1) button is clicked.
"""
# GIVEN: An instance of the FirstTimeForm
frw = FirstTimeForm(None)
@patch('openlp.core.ui.firsttimeform.QtWidgets.QWizard.reject')
@patch('openlp.core.ui.firsttimeform.time')
@patch('openlp.core.ui.firsttimeform.get_thread_worker')
@patch('openlp.core.ui.firsttimeform.is_thread_finished')
def test_reject_method(mocked_is_thread_finished, mocked_get_thread_worker,
mocked_time, mocked_qwizard_reject, ftf_app):
"""
Test that the reject method shuts down the threads correctly
"""
# GIVEN: A FRW, some mocked threads and workers (that isn't quite done) and other mocked stuff
mocked_worker = MagicMock()
mocked_get_thread_worker.return_value = mocked_worker
mocked_is_thread_finished.side_effect = [False, True]
frw = FirstTimeForm(None)
frw.initialize(MagicMock())
frw.thumbnail_download_threads = ['test_thread']
with patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor:
# WHEN: Calling _on_custom_button_clicked with the constant for the 'internet settings' button (CustomButton1)
frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton1)
# WHEN: the reject method is called
frw.reject()
# THEN: The ProxyDialog should be shown.
mocked_proxy_dialog.assert_called_with(frw)
mocked_proxy_dialog().retranslate_ui.assert_called_once()
mocked_proxy_dialog().exec.assert_called_once()
# THEN: The right things should be called in the right order
mocked_get_thread_worker.assert_called_once_with('test_thread')
mocked_worker.cancel_download.assert_called_once()
mocked_is_thread_finished.assert_called_with('test_thread')
assert mocked_is_thread_finished.call_count == 2, 'isRunning() should have been called twice'
mocked_time.sleep.assert_called_once_with(0.1)
mocked_set_normal_cursor.assert_called_once()
mocked_qwizard_reject.assert_called_once()
@patch('openlp.core.ui.firsttimeform.critical_error_message_box')
def test__parse_config_invalid_config(self, mocked_critical_error_message_box):
"""
Test `FirstTimeForm._parse_config` when called with invalid data
"""
# GIVEN: An instance of `FirstTimeForm`
first_time_form = FirstTimeForm(None)
# WHEN: Calling _parse_config with a string containing invalid data
result = first_time_form._parse_config(INVALID_CONFIG)
@patch('openlp.core.ui.firsttimeform.ProxyDialog')
def test_on_custom_button_clicked(mocked_proxy_dialog):
"""
Test _on_custom_button when it is called whe the 'internet settings' (CustomButton1) button is not clicked.
"""
# GIVEN: An instance of the FirstTimeForm
frw = FirstTimeForm(None)
# THEN: _parse_data should return False and the user should have should have been informed.
assert result is False
mocked_critical_error_message_box.assert_called_once()
# WHEN: Calling _on_custom_button_clicked with a different button to the 'internet settings button.
frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton2)
@patch('openlp.core.ui.firsttimeform.get_web_page')
@patch('openlp.core.ui.firsttimeform.QtWidgets.QMessageBox')
def test_network_error(self, mocked_message_box, mocked_get_web_page):
"""
Test we catch a network error in First Time Wizard - bug 1409627
"""
# GIVEN: Initial setup and mocks
first_time_form = FirstTimeForm(None)
first_time_form.initialize(MagicMock())
mocked_get_web_page.side_effect = ConnectionError('')
mocked_message_box.Ok = 'OK'
# THEN: The ProxyDialog should not be shown.
mocked_proxy_dialog.assert_not_called()
# WHEN: the First Time Wizard calls to get the initial configuration
first_time_form._download_index()
# THEN: the critical_error_message_box should have been called
mocked_message_box.critical.assert_called_once_with(
first_time_form, 'Network Error',
'There was a network error attempting to connect to retrieve initial configuration information', 'OK')
@patch('openlp.core.ui.firsttimeform.ProxyDialog')
def test_on_custom_button_clicked_internet_settings(mocked_proxy_dialog):
"""
Test _on_custom_button when it is called when the 'internet settings' (CustomButton1) button is clicked.
"""
# GIVEN: An instance of the FirstTimeForm
frw = FirstTimeForm(None)
# WHEN: Calling _on_custom_button_clicked with the constant for the 'internet settings' button (CustomButton1)
frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton1)
# THEN: The ProxyDialog should be shown.
mocked_proxy_dialog.assert_called_with(frw)
mocked_proxy_dialog().retranslate_ui.assert_called_once()
mocked_proxy_dialog().exec.assert_called_once()
@patch('openlp.core.ui.firsttimeform.critical_error_message_box')
def test__parse_config_invalid_config(mocked_critical_error_message_box):
"""
Test `FirstTimeForm._parse_config` when called with invalid data
"""
# GIVEN: An instance of `FirstTimeForm`
first_time_form = FirstTimeForm(None)
# WHEN: Calling _parse_config with a string containing invalid data
result = first_time_form._parse_config(INVALID_CONFIG)
# THEN: _parse_data should return False and the user should have should have been informed.
assert result is False
mocked_critical_error_message_box.assert_called_once()
@patch('openlp.core.ui.firsttimeform.get_web_page')
@patch('openlp.core.ui.firsttimeform.QtWidgets.QMessageBox')
def test_network_error(mocked_message_box, mocked_get_web_page, ftf_app):
"""
Test we catch a network error in First Time Wizard - bug 1409627
"""
# GIVEN: Initial setup and mocks
first_time_form = FirstTimeForm(None)
first_time_form.initialize(MagicMock())
mocked_get_web_page.side_effect = ConnectionError('')
mocked_message_box.Ok = 'OK'
# WHEN: the First Time Wizard calls to get the initial configuration
first_time_form._download_index()
# THEN: the critical_error_message_box should have been called
mocked_message_box.critical.assert_called_once_with(
first_time_form, 'Network Error',
'There was a network error attempting to connect to retrieve initial configuration information', 'OK')
def test_accept_method_theme_selected(mock_settings):

View File

@ -21,85 +21,88 @@
"""
Package to test the openlp.core.ui.formattingtagscontroller package.
"""
from unittest import TestCase
import pytest
from openlp.core.ui.formattingtagcontroller import FormattingTagController
class TestFormattingTagController(TestCase):
@pytest.fixture()
def services(registry, qapp):
return FormattingTagController()
def setUp(self):
self.services = FormattingTagController()
def test_strip(self):
"""
Test that the _strip strips the correct chars
"""
# GIVEN: An instance of the Formatting Tag Form and a string containing a tag
tag = '{tag}'
def test_strip(services):
"""
Test that the _strip strips the correct chars
"""
# GIVEN: An instance of the Formatting Tag Form and a string containing a tag
tag = '{tag}'
# WHEN: Calling _strip
result = self.services._strip(tag)
# WHEN: Calling _strip
result = services._strip(tag)
# THEN: The tag should be returned with the wrappers removed.
assert result == 'tag', 'FormattingTagForm._strip should return u\'tag\' when called with u\'{tag}\''
# THEN: The tag should be returned with the wrappers removed.
assert result == 'tag', 'FormattingTagForm._strip should return u\'tag\' when called with u\'{tag}\''
def test_end_tag_changed_processes_correctly(self):
"""
Test that the end html tags are generated correctly
"""
# GIVEN: A list of start , end tags and error messages
tests = []
test = {'start': '<b>', 'end': None, 'gen': '</b>', 'valid': None}
tests.append(test)
test = {'start': '<i>', 'end': '</i>', 'gen': None, 'valid': None}
tests.append(test)
test = {'start': '<b>', 'end': '</i>', 'gen': None,
'valid': 'End tag </b> does not match end tag for start tag <b>'}
tests.append(test)
# WHEN: Testing each one of them in turn
for test in tests:
error, result = self.services.end_tag_changed(test['start'], test['end'])
def test_end_tag_changed_processes_correctly(services):
"""
Test that the end html tags are generated correctly
"""
# GIVEN: A list of start , end tags and error messages
tests = []
test = {'start': '<b>', 'end': None, 'gen': '</b>', 'valid': None}
tests.append(test)
test = {'start': '<i>', 'end': '</i>', 'gen': None, 'valid': None}
tests.append(test)
test = {'start': '<b>', 'end': '</i>', 'gen': None,
'valid': 'End tag </b> does not match end tag for start tag <b>'}
tests.append(test)
# THEN: The result should match the predetermined value.
assert result == test['gen'], \
'Function should handle end tag correctly : %s and %s for %s ' % (test['gen'], result, test['start'])
assert error == test['valid'], 'Function should not generate unexpected error messages : %s ' % error
# WHEN: Testing each one of them in turn
for test in tests:
error, result = services.end_tag_changed(test['start'], test['end'])
def test_start_tag_changed_processes_correctly(self):
"""
Test that the end html tags are generated correctly
"""
# GIVEN: A list of start , end tags and error messages
tests = []
test = {'start': '<b>', 'end': '', 'gen': '</b>', 'valid': None}
tests.append(test)
test = {'start': '<i>', 'end': '</i>', 'gen': None, 'valid': None}
tests.append(test)
test = {'start': 'superfly', 'end': '', 'gen': None, 'valid': 'Start tag superfly is not valid HTML'}
tests.append(test)
# THEN: The result should match the predetermined value.
assert result == test['gen'], \
'Function should handle end tag correctly : %s and %s for %s ' % (test['gen'], result, test['start'])
assert error == test['valid'], 'Function should not generate unexpected error messages : %s ' % error
# WHEN: Testing each one of them in turn
for test in tests:
error, result = self.services.start_tag_changed(test['start'], test['end'])
# THEN: The result should match the predetermined value.
assert result == test['gen'], \
'Function should handle end tag correctly : %s and %s ' % (test['gen'], result)
assert error == test['valid'], 'Function should not generate unexpected error messages : %s ' % error
def test_start_tag_changed_processes_correctly(services):
"""
Test that the end html tags are generated correctly
"""
# GIVEN: A list of start , end tags and error messages
tests = []
test = {'start': '<b>', 'end': '', 'gen': '</b>', 'valid': None}
tests.append(test)
test = {'start': '<i>', 'end': '</i>', 'gen': None, 'valid': None}
tests.append(test)
test = {'start': 'superfly', 'end': '', 'gen': None, 'valid': 'Start tag superfly is not valid HTML'}
tests.append(test)
def test_start_html_to_end_html(self):
"""
Test that the end html tags are generated correctly
"""
# GIVEN: A list of valid and invalid tags
tests = {'<b>': '</b>', '<i>': '</i>', 'superfly': '', '<HTML START>': None,
'<span style="-webkit-text-fill-color:red">': '</span>'}
# WHEN: Testing each one of them in turn
for test in tests:
error, result = services.start_tag_changed(test['start'], test['end'])
# WHEN: Testing each one of them
for test1, test2 in tests.items():
result = self.services.start_html_to_end_html(test1)
# THEN: The result should match the predetermined value.
assert result == test['gen'], \
'Function should handle end tag correctly : %s and %s ' % (test['gen'], result)
assert error == test['valid'], 'Function should not generate unexpected error messages : %s ' % error
# THEN: The result should match the predetermined value.
assert result == test2, 'Calculated end tag should be valid: %s and %s = %s' % (test1, test2, result)
def test_start_html_to_end_html(services):
"""
Test that the end html tags are generated correctly
"""
# GIVEN: A list of valid and invalid tags
tests = {'<b>': '</b>', '<i>': '</i>', 'superfly': '', '<HTML START>': None,
'<span style="-webkit-text-fill-color:red">': '</span>'}
# WHEN: Testing each one of them
for test1, test2 in tests.items():
result = services.start_html_to_end_html(test1)
# THEN: The result should match the predetermined value.
assert result == test2, 'Calculated end tag should be valid: %s and %s = %s' % (test1, test2, result)

View File

@ -21,69 +21,63 @@
"""
Package to test the openlp.core.ui.formattingtagsform package.
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, call, patch
from openlp.core.ui.formattingtagform import FormattingTagForm
class TestFormattingTagForm(TestCase):
@pytest.yield_fixture()
def tagform_env(registry):
setup_patcher = patch('openlp.core.ui.formattingtagform.FormattingTagForm._setup')
mocked_setup_patcher = setup_patcher.start()
yield mocked_setup_patcher
setup_patcher.stop()
def setUp(self):
"""
Mock out stuff for all the tests
"""
self.setup_patcher = patch('openlp.core.ui.formattingtagform.FormattingTagForm._setup')
self.setup_patcher.start()
def tearDown(self):
"""
Remove the mocks
"""
self.setup_patcher.stop()
def test_on_row_selected(tagform_env):
"""
Test that the appropriate actions are preformed when on_row_selected is called
"""
# GIVEN: An instance of the Formatting Tag Form and a mocked delete_button
form = FormattingTagForm(None)
form.delete_button = MagicMock()
def test_on_row_selected(self):
"""
Test that the appropriate actions are preformed when on_row_selected is called
"""
# GIVEN: An instance of the Formatting Tag Form and a mocked delete_button
form = FormattingTagForm(None)
form.delete_button = MagicMock()
# WHEN: on_row_selected is called
form.on_row_selected()
# WHEN: on_row_selected is called
form.on_row_selected()
# THEN: setEnabled and should have been called on delete_button
form.delete_button.setEnabled.assert_called_with(True)
# THEN: setEnabled and should have been called on delete_button
form.delete_button.setEnabled.assert_called_with(True)
def test_on_new_clicked(self):
"""
Test that clicking the Add a new tag button does the right thing
"""
def test_on_new_clicked(tagform_env):
"""
Test that clicking the Add a new tag button does the right thing
"""
# GIVEN: A formatting tag form and a mocked out tag table widget
form = FormattingTagForm(None)
form.tag_table_widget = MagicMock()
row_count = 5
form.tag_table_widget.rowCount.return_value = row_count
# GIVEN: A formatting tag form and a mocked out tag table widget
form = FormattingTagForm(None)
form.tag_table_widget = MagicMock()
row_count = 5
form.tag_table_widget.rowCount.return_value = row_count
# WHEN: on_new_clicked is run (i.e. the Add new button was clicked)
with patch('openlp.core.ui.formattingtagform.QtWidgets.QTableWidgetItem') as MockedQTableWidgetItem:
mocked_table_widget = MagicMock()
MockedQTableWidgetItem.return_value = mocked_table_widget
form.on_new_clicked()
# WHEN: on_new_clicked is run (i.e. the Add new button was clicked)
with patch('openlp.core.ui.formattingtagform.QtWidgets.QTableWidgetItem') as MockedQTableWidgetItem:
mocked_table_widget = MagicMock()
MockedQTableWidgetItem.return_value = mocked_table_widget
form.on_new_clicked()
# THEN: A new row should be added to the table
form.tag_table_widget.rowCount.assert_called_with()
form.tag_table_widget.insertRow.assert_called_with(row_count)
expected_set_item_calls = [
call(row_count, 0, mocked_table_widget),
call(row_count, 1, mocked_table_widget),
call(row_count, 2, mocked_table_widget),
call(row_count, 3, mocked_table_widget)
]
assert expected_set_item_calls == form.tag_table_widget.setItem.call_args_list, \
'setItem should have been called correctly'
form.tag_table_widget.resizeRowsToContents.assert_called_with()
form.tag_table_widget.scrollToBottom.assert_called_with()
form.tag_table_widget.selectRow.assert_called_with(row_count)
# THEN: A new row should be added to the table
form.tag_table_widget.rowCount.assert_called_with()
form.tag_table_widget.insertRow.assert_called_with(row_count)
expected_set_item_calls = [
call(row_count, 0, mocked_table_widget),
call(row_count, 1, mocked_table_widget),
call(row_count, 2, mocked_table_widget),
call(row_count, 3, mocked_table_widget)
]
assert expected_set_item_calls == form.tag_table_widget.setItem.call_args_list, \
'setItem should have been called correctly'
form.tag_table_widget.resizeRowsToContents.assert_called_with()
form.tag_table_widget.scrollToBottom.assert_called_with()
form.tag_table_widget.selectRow.assert_called_with(row_count)

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
@ -21,28 +20,24 @@
"""
Package to test the openlp.core.ui.icons package.
"""
from unittest import TestCase
from unittest.mock import patch
from PyQt5 import QtGui
from openlp.core.ui.icons import UiIcons
from tests.helpers.testmixin import TestMixin
class TestIcons(TestCase, TestMixin):
@patch('openlp.core.ui.icons.UiIcons.__init__', return_value=None)
def test_simple_icon(_):
# GIVEN: an basic set of icons
icons = UiIcons()
icon_list = {
'active': {'icon': 'fa.child'}
@patch('openlp.core.ui.icons.UiIcons.__init__', return_value=None)
def test_simple_icon(self, _):
# GIVEN: an basic set of icons
icons = UiIcons()
icon_list = {
'active': {'icon': 'fa.child'}
}
}
icons.load_icons(icon_list)
# WHEN: I use the icons
icon_active = UiIcons().active
# THEN: I should have an icon
assert isinstance(icon_active, QtGui.QIcon)
icons.load_icons(icon_list)
# WHEN: I use the icons
icon_active = UiIcons().active
# THEN: I should have an icon
assert isinstance(icon_active, QtGui.QIcon)

View File

@ -22,293 +22,291 @@
Package to test openlp.core.ui.mainwindow package.
"""
import os
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtWidgets
from openlp.core.state import State
from openlp.core.common.i18n import UiStrings
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.display.screens import ScreenList
from openlp.core.ui.mainwindow import MainWindow
from tests.helpers.testmixin import TestMixin
from tests.utils.constants import TEST_RESOURCES_PATH, RESOURCE_PATH
class TestMainWindow(TestCase, TestMixin):
def _create_mock_action(parent, name, **kwargs):
"""
Test the main window
Create a fake action with some "real" attributes
"""
def _create_mock_action(self, parent, name, **kwargs):
"""
Create a fake action with some "real" attributes
"""
action = QtWidgets.QAction(parent)
action.setObjectName(name)
if kwargs.get('triggers'):
action.triggered.connect(kwargs.pop('triggers'))
return action
action = QtWidgets.QAction(parent)
action.setObjectName(name)
if kwargs.get('triggers'):
action.triggered.connect(kwargs.pop('triggers'))
return action
def setUp(self):
"""
Set up the objects we need for all of the tests
"""
Registry.create()
self.registry = Registry()
self.setup_application()
# Mock cursor busy/normal methods.
self.app.set_busy_cursor = MagicMock()
self.app.set_normal_cursor = MagicMock()
self.app.process_events = MagicMock()
self.app.args = []
Registry().register('application', self.app)
Registry().register('settings', Settings())
Registry().set_flag('no_web_server', True)
self.add_toolbar_action_patcher = patch('openlp.core.ui.mainwindow.create_action')
self.mocked_add_toolbar_action = self.add_toolbar_action_patcher.start()
self.mocked_add_toolbar_action.side_effect = self._create_mock_action
self.renderer_patcher = patch('openlp.core.display.render.Renderer')
self.mocked_renderer = self.renderer_patcher.start()
mocked_desktop = MagicMock()
mocked_desktop.screenCount.return_value = 1
mocked_desktop.screenGeometry.return_value = QtCore.QRect(0, 0, 1024, 768)
mocked_desktop.primaryScreen.return_value = 1
ScreenList.create(mocked_desktop)
State().load_settings()
self.main_window = MainWindow()
def tearDown(self):
"""
Delete all the C++ objects and stop all the patchers
"""
del self.main_window
self.renderer_patcher.stop()
self.add_toolbar_action_patcher.stop()
@pytest.yield_fixture()
def main_window(state, settings):
app = Registry().get('application')
app.set_busy_cursor = MagicMock()
app.set_normal_cursor = MagicMock()
app.process_events = MagicMock()
app.args = []
Registry().set_flag('no_web_server', True)
add_toolbar_action_patcher = patch('openlp.core.ui.mainwindow.create_action')
mocked_add_toolbar_action = add_toolbar_action_patcher.start()
mocked_add_toolbar_action.side_effect = _create_mock_action
renderer_patcher = patch('openlp.core.display.render.Renderer')
renderer_patcher.start()
mocked_desktop = MagicMock()
mocked_desktop.screenCount.return_value = 1
mocked_desktop.screenGeometry.return_value = QtCore.QRect(0, 0, 1024, 768)
mocked_desktop.primaryScreen.return_value = 1
ScreenList.create(mocked_desktop)
mainwindow = MainWindow()
yield mainwindow
del mainwindow
renderer_patcher.stop()
add_toolbar_action_patcher.stop()
def test_cmd_line_file(self):
"""
Test that passing a service file from the command line loads the service.
"""
# GIVEN a service as an argument to openlp
service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz')
# WHEN the argument is processed
with patch.object(self.main_window.service_manager, 'load_file') as mocked_load_file:
self.main_window.open_cmd_line_files([service])
def test_cmd_line_file(main_window):
"""
Test that passing a service file from the command line loads the service.
"""
# GIVEN a service as an argument to openlp
service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz')
# THEN the service from the arguments is loaded
mocked_load_file.assert_called_with(Path(service))
# WHEN the argument is processed
with patch.object(main_window.service_manager, 'load_file') as mocked_load_file:
main_window.open_cmd_line_files([service])
@patch('openlp.core.ui.servicemanager.ServiceManager.load_file')
def test_cmd_line_arg(self, mocked_load_file):
"""
Test that passing a non service file does nothing.
"""
# GIVEN a non service file as an argument to openlp
service = 'run_openlp.py'
# THEN the service from the arguments is loaded
mocked_load_file.assert_called_with(Path(service))
# WHEN the argument is processed
self.main_window.open_cmd_line_files(service)
# THEN the file should not be opened
assert mocked_load_file.called is False, 'load_file should not have been called'
@patch('openlp.core.ui.servicemanager.ServiceManager.load_file')
def test_cmd_line_arg(mocked_load_file, main_window):
"""
Test that passing a non service file does nothing.
"""
# GIVEN a non service file as an argument to openlp
service = 'run_openlp.py'
def test_main_window_title(self):
"""
Test that running a new instance of OpenLP set the window title correctly
"""
# GIVEN a newly opened OpenLP instance
# WHEN the argument is processed
main_window.open_cmd_line_files(service)
# WHEN no changes are made to the service
# THEN the file should not be opened
assert mocked_load_file.called is False, 'load_file should not have been called'
# THEN the main window's title shoud be the same as the OpenLP string in the UiStrings class
assert self.main_window.windowTitle() == UiStrings().OpenLP, \
'The main window\'s title should be the same as the OpenLP string in UiStrings class'
def test_set_service_modifed(self):
"""
Test that when setting the service's title the main window's title is set correctly
"""
# GIVEN a newly opened OpenLP instance
def test_main_window_title(main_window):
"""
Test that running a new instance of OpenLP set the window title correctly
"""
# GIVEN a newly opened OpenLP instance
# WHEN set_service_modified is called with with the modified flag set true and a file name
self.main_window.set_service_modified(True, 'test.osz')
# WHEN no changes are made to the service
# THEN the main window's title should be set to the
assert self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OpenLP, 'test.osz') == \
'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz*"'
# THEN the main window's title shoud be the same as the OpenLP string in the UiStrings class
assert main_window.windowTitle() == UiStrings().OpenLP, \
'The main window\'s title should be the same as the OpenLP string in UiStrings class'
def test_set_service_unmodified(self):
"""
Test that when setting the service's title the main window's title is set correctly
"""
# GIVEN a newly opened OpenLP instance
# WHEN set_service_modified is called with with the modified flag set False and a file name
self.main_window.set_service_modified(False, 'test.osz')
def test_set_service_modifed(main_window):
"""
Test that when setting the service's title the main window's title is set correctly
"""
# GIVEN a newly opened OpenLP instance
# THEN the main window's title should be set to the
assert self.main_window.windowTitle(), '%s - %s' % (UiStrings().OpenLP, 'test.osz') == \
'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz"'
# WHEN set_service_modified is called with with the modified flag set true and a file name
main_window.set_service_modified(True, 'test.osz')
def test_mainwindow_configuration(self):
"""
Check that the Main Window initialises the Registry Correctly
"""
# GIVEN: A built main window
# THEN the main window's title should be set to the
assert main_window.windowTitle(), '%s - %s*' % (UiStrings().OpenLP, 'test.osz') == \
'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz*"'
# WHEN: you check the started functions
# THEN: the following registry functions should have been registered
expected_service_list = ['application', 'settings', 'main_window', 'http_server', 'authentication_token',
'settings_form', 'service_manager', 'theme_manager', 'projector_manager']
expected_functions_list = ['bootstrap_initialise', 'bootstrap_post_set_up', 'bootstrap_completion',
'theme_update_global', 'config_screen_changed']
assert list(self.registry.service_list.keys()) == expected_service_list, \
'The service list should have been {}'.format(self.registry.service_list.keys())
assert list(self.registry.functions_list.keys()) == expected_functions_list, \
'The function list should have been {}'.format(self.registry.functions_list.keys())
assert 'application' in self.registry.service_list, 'The application should have been registered.'
assert 'main_window' in self.registry.service_list, 'The main_window should have been registered.'
def test_set_service_unmodified(main_window):
"""
Test that when setting the service's title the main window's title is set correctly
"""
# GIVEN a newly opened OpenLP instance
def test_projector_manager_hidden_on_startup(self):
"""
Test that the projector manager is hidden on startup
"""
# GIVEN: A built main window
# WHEN: OpenLP is started
# THEN: The projector manager should be hidden
assert self.main_window.projector_manager_dock.isVisible() is False
# WHEN set_service_modified is called with with the modified flag set False and a file name
main_window.set_service_modified(False, 'test.osz')
def test_on_search_shortcut_triggered_shows_media_manager(self):
"""
Test that the media manager is made visible when the search shortcut is triggered
"""
# GIVEN: A build main window set up for testing
with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \
patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box:
mocked_media_manager_dock.isVisible.return_value = False
mocked_media_tool_box.currentWidget.return_value = None
# THEN the main window's title should be set to the
assert main_window.windowTitle(), '%s - %s' % (UiStrings().OpenLP, 'test.osz') == \
'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz"'
# WHEN: The search shortcut is triggered
self.main_window.on_search_shortcut_triggered()
# THEN: The media manager dock is made visible
mocked_media_manager_dock.setVisible.assert_called_with(True)
def test_mainwindow_configuration(main_window):
"""
Check that the Main Window initialises the Registry Correctly
"""
# GIVEN: A built main window
def test_on_search_shortcut_triggered_focuses_widget(self):
"""
Test that the focus is set on the widget when the search shortcut is triggered
"""
# GIVEN: A build main window set up for testing
with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \
patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box:
mocked_media_manager_dock.isVisible.return_value = True
mocked_widget = MagicMock()
mocked_media_tool_box.currentWidget.return_value = mocked_widget
# WHEN: you check the started functions
# WHEN: The search shortcut is triggered
self.main_window.on_search_shortcut_triggered()
# THEN: the following registry functions should have been registered
expected_service_list = ['settings', 'application', 'main_window', 'http_server', 'authentication_token',
'settings_form', 'service_manager', 'theme_manager', 'projector_manager']
expected_functions_list = ['bootstrap_initialise', 'bootstrap_post_set_up', 'bootstrap_completion',
'theme_update_global', 'config_screen_changed']
assert list(Registry().service_list.keys()) == expected_service_list, \
'The service list should have been {}'.format(Registry().service_list.keys())
assert list(Registry().functions_list.keys()) == expected_functions_list, \
'The function list should have been {}'.format(Registry().functions_list.keys())
assert 'application' in Registry().service_list, 'The application should have been registered.'
assert 'main_window' in Registry().service_list, 'The main_window should have been registered.'
assert 'settings' in Registry().service_list, 'The settings should have been registered.'
# THEN: The media manager dock is made visible
assert 0 == mocked_media_manager_dock.setVisible.call_count
mocked_widget.on_focus.assert_called_with()
@patch('openlp.core.ui.mainwindow.FirstTimeForm')
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
def test_on_first_time_wizard_clicked_show_projectors_after(self, mocked_warning, MockWizard):
"""Test that the projector manager is shown after the FTW is run"""
# GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to True.
mocked_warning.return_value = QtWidgets.QMessageBox.Yes
MockWizard.return_value.was_cancelled = False
self.main_window.settings.setValue('projector/show after wizard', True)
def test_projector_manager_hidden_on_startup(main_window):
"""
Test that the projector manager is hidden on startup
"""
# GIVEN: A built main window
# WHEN: OpenLP is started
# THEN: The projector manager should be hidden
assert main_window.projector_manager_dock.isVisible() is False
with patch.object(self.main_window, 'projector_manager_dock') as mocked_dock, \
patch.object(self.registry, 'execute'), patch.object(self.main_window, 'theme_manager_contents'):
# WHEN: on_first_time_wizard_clicked is called
self.main_window.on_first_time_wizard_clicked()
# THEN: projector_manager_dock.setVisible should had been called once
mocked_dock.setVisible.assert_called_once_with(True)
def test_on_search_shortcut_triggered_shows_media_manager(main_window):
"""
Test that the media manager is made visible when the search shortcut is triggered
"""
# GIVEN: A build main window set up for testing
with patch.object(main_window, 'media_manager_dock') as mocked_media_manager_dock, \
patch.object(main_window, 'media_tool_box') as mocked_media_tool_box:
mocked_media_manager_dock.isVisible.return_value = False
mocked_media_tool_box.currentWidget.return_value = None
@patch('openlp.core.ui.mainwindow.FirstTimeForm')
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
def test_on_first_time_wizard_clicked_hide_projectors_after(self, mocked_warning, MockWizard):
"""Test that the projector manager is hidden after the FTW is run"""
# GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to False.
mocked_warning.return_value = QtWidgets.QMessageBox.Yes
MockWizard.return_value.was_cancelled = False
self.main_window.settings.setValue('projector/show after wizard', False)
# WHEN: The search shortcut is triggered
main_window.on_search_shortcut_triggered()
# THEN: The media manager dock is made visible
mocked_media_manager_dock.setVisible.assert_called_with(True)
def test_on_search_shortcut_triggered_focuses_widget(main_window):
"""
Test that the focus is set on the widget when the search shortcut is triggered
"""
# GIVEN: A build main window set up for testing
with patch.object(main_window, 'media_manager_dock') as mocked_media_manager_dock, \
patch.object(main_window, 'media_tool_box') as mocked_media_tool_box:
mocked_media_manager_dock.isVisible.return_value = True
mocked_widget = MagicMock()
mocked_media_tool_box.currentWidget.return_value = mocked_widget
# WHEN: The search shortcut is triggered
main_window.on_search_shortcut_triggered()
# THEN: The media manager dock is made visible
assert 0 == mocked_media_manager_dock.setVisible.call_count
mocked_widget.on_focus.assert_called_with()
@patch('openlp.core.ui.mainwindow.FirstTimeForm')
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
def test_on_first_time_wizard_clicked_show_projectors_after(mocked_warning, MockWizard, main_window):
"""Test that the projector manager is shown after the FTW is run"""
# GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to True.
mocked_warning.return_value = QtWidgets.QMessageBox.Yes
MockWizard.return_value.was_cancelled = False
main_window.settings.setValue('projector/show after wizard', True)
with patch.object(main_window, 'projector_manager_dock') as mocked_dock, \
patch.object(Registry(), 'execute'), patch.object(main_window, 'theme_manager_contents'):
# WHEN: on_first_time_wizard_clicked is called
with patch.object(self.main_window, 'projector_manager_dock') as mocked_dock, \
patch.object(self.registry, 'execute'), patch.object(self.main_window, 'theme_manager_contents'):
self.main_window.on_first_time_wizard_clicked()
main_window.on_first_time_wizard_clicked()
# THEN: projector_manager_dock.setVisible should had been called once
mocked_dock.setVisible.assert_called_once_with(False)
# THEN: projector_manager_dock.setVisible should had been called once
mocked_dock.setVisible.assert_called_once_with(True)
def test_increment_progress_bar_default_increment(self):
"""
Test that increment_progress_bar increments the progress bar by 1 when called without the `increment` arg.
"""
# GIVEN: A mocked progress bar
with patch.object(self.main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar:
# WHEN: Calling increment_progress_bar without the `increment` arg
self.main_window.increment_progress_bar()
@patch('openlp.core.ui.mainwindow.FirstTimeForm')
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
def test_on_first_time_wizard_clicked_hide_projectors_after(mocked_warning, MockWizard, main_window):
"""Test that the projector manager is hidden after the FTW is run"""
# GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to False.
mocked_warning.return_value = QtWidgets.QMessageBox.Yes
MockWizard.return_value.was_cancelled = False
main_window.settings.setValue('projector/show after wizard', False)
# THEN: The progress bar value should have been incremented by 1
mocked_progress_bar.setValue.assert_called_once_with(1)
# WHEN: on_first_time_wizard_clicked is called
with patch.object(main_window, 'projector_manager_dock') as mocked_dock, \
patch.object(Registry(), 'execute'), patch.object(main_window, 'theme_manager_contents'):
main_window.on_first_time_wizard_clicked()
def test_increment_progress_bar_custom_increment(self):
"""
Test that increment_progress_bar increments the progress bar by the `increment` arg when called with the
`increment` arg with a set value.
"""
# GIVEN: A mocked progress bar
with patch.object(self.main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar:
# THEN: projector_manager_dock.setVisible should had been called once
mocked_dock.setVisible.assert_called_once_with(False)
# WHEN: Calling increment_progress_bar with `increment` set to 10
self.main_window.increment_progress_bar(increment=10)
# THEN: The progress bar value should have been incremented by 10
mocked_progress_bar.setValue.assert_called_once_with(10)
def test_increment_progress_bar_default_increment(main_window):
"""
Test that increment_progress_bar increments the progress bar by 1 when called without the `increment` arg.
"""
# GIVEN: A mocked progress bar
with patch.object(main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar:
def test_eventFilter(self):
"""
Test the reimplemented event method
"""
# GIVEN: A file path and a QEvent.
file_path = str(RESOURCE_PATH / 'church.jpg')
mocked_file_method = MagicMock(return_value=file_path)
event = QtCore.QEvent(QtCore.QEvent.FileOpen)
event.file = mocked_file_method
# WHEN: Calling increment_progress_bar without the `increment` arg
main_window.increment_progress_bar()
# WHEN: Call the vent method.
result = self.main_window.eventFilter(MagicMock(), event)
# THEN: The progress bar value should have been incremented by 1
mocked_progress_bar.setValue.assert_called_once_with(1)
# THEN: The path should be inserted.
assert result is True, "The method should have returned True."
mocked_file_method.assert_called_once_with()
assert self.app.args[0] == file_path, "The path should be in args."
@patch('openlp.core.ui.mainwindow.is_macosx')
def test_application_activate_event(self, mocked_is_macosx):
"""
Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized
"""
# GIVEN: Mac OS X and an ApplicationActivate event
mocked_is_macosx.return_value = True
event = QtCore.QEvent(QtCore.QEvent.ApplicationActivate)
self.main_window.showMinimized()
def test_increment_progress_bar_custom_increment(main_window):
"""
Test that increment_progress_bar increments the progress bar by the `increment` arg when called with the
`increment` arg with a set value.
"""
# GIVEN: A mocked progress bar
with patch.object(main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar:
# WHEN: The icon in the dock is clicked
result = self.main_window.eventFilter(MagicMock(), event)
# WHEN: Calling increment_progress_bar with `increment` set to 10
main_window.increment_progress_bar(increment=10)
# THEN:
assert result is True, "The method should have returned True."
assert self.main_window.isMinimized() is False
# THEN: The progress bar value should have been incremented by 10
mocked_progress_bar.setValue.assert_called_once_with(10)
def test_eventFilter(main_window):
"""
Test the reimplemented event method
"""
# GIVEN: A file path and a QEvent.
file_path = str(RESOURCE_PATH / 'church.jpg')
mocked_file_method = MagicMock(return_value=file_path)
event = QtCore.QEvent(QtCore.QEvent.FileOpen)
event.file = mocked_file_method
# WHEN: Call the vent method.
result = main_window.eventFilter(MagicMock(), event)
# THEN: The path should be inserted.
assert result is True, "The method should have returned True."
mocked_file_method.assert_called_once_with()
assert Registry().get('application').args[0] == file_path, "The path should be in args."
@patch('openlp.core.ui.mainwindow.is_macosx')
def test_application_activate_event(mocked_is_macosx, main_window):
"""
Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized
"""
# GIVEN: Mac OS X and an ApplicationActivate event
mocked_is_macosx.return_value = True
event = QtCore.QEvent(QtCore.QEvent.ApplicationActivate)
main_window.showMinimized()
# WHEN: The icon in the dock is clicked
result = main_window.eventFilter(MagicMock(), event)
# THEN:
assert result is True, "The method should have returned True."
assert main_window.isMinimized() is False

File diff suppressed because it is too large Load Diff

View File

@ -21,154 +21,149 @@
"""
Package to test the openlp.core.ui.settingsform package.
"""
from unittest import TestCase
from unittest.mock import MagicMock, patch
from PyQt5 import QtWidgets
from openlp.core.common.registry import Registry
from openlp.core.ui.settingsform import SettingsForm
class TestSettingsForm(TestCase):
def test_insert_tab_visible(registry):
"""
Test that the insert_tab() method works correctly when a visible tab is inserted
"""
# GIVEN: A mocked tab and a Settings Form
settings_form = SettingsForm(None)
general_tab = MagicMock()
general_tab.tab_title = 'mock'
general_tab.tab_title_visible = 'Mock'
general_tab.icon_path = ':/icon/openlp-logo.svg'
def setUp(self):
"""
Set up a few things for the tests
"""
Registry.create()
def test_insert_tab_visible(self):
"""
Test that the insert_tab() method works correctly when a visible tab is inserted
"""
# GIVEN: A mocked tab and a Settings Form
settings_form = SettingsForm(None)
general_tab = MagicMock()
general_tab.tab_title = 'mock'
general_tab.tab_title_visible = 'Mock'
general_tab.icon_path = ':/icon/openlp-logo.svg'
# WHEN: We insert the general tab
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
settings_form.insert_tab(general_tab, is_visible=True)
# THEN: The general tab should have been inserted into the stacked layout and an item inserted into the list
mocked_add_widget.assert_called_with(general_tab)
assert 1 == mocked_add_item.call_count, 'addItem should have been called'
def test_insert_tab_not_visible(self):
"""
Test that the insert_tab() method works correctly when a tab that should not be visible is inserted
"""
# GIVEN: A general tab and a Settings Form
settings_form = SettingsForm(None)
general_tab = MagicMock()
general_tab.tab_title = 'mock'
# WHEN: We insert the general tab
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
settings_form.insert_tab(general_tab, is_visible=False)
# THEN: The general tab should have been inserted, but no list item should have been inserted into the list
mocked_add_widget.assert_called_with(general_tab)
assert 0 == mocked_add_item.call_count, 'addItem should not have been called'
def test_accept_with_inactive_plugins(self):
"""
Test that the accept() method works correctly when some of the plugins are inactive
"""
# GIVEN: A visible general tab and an invisible theme tab in a Settings Form
settings_form = SettingsForm(None)
general_tab = QtWidgets.QWidget(None)
general_tab.tab_title = 'mock-general'
general_tab.tab_title_visible = 'Mock General'
general_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_general_save = MagicMock()
general_tab.save = mocked_general_save
mocked_general_load = MagicMock()
general_tab.load = mocked_general_load
settings_form.insert_tab(general_tab, is_visible=True)
themes_tab = QtWidgets.QWidget(None)
themes_tab.tab_title = 'mock-themes'
themes_tab.tab_title_visible = 'Mock Themes'
themes_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_theme_save = MagicMock()
themes_tab.save = mocked_theme_save
mocked_theme_load = MagicMock()
themes_tab.load = mocked_theme_load
settings_form.insert_tab(themes_tab, is_visible=False)
# WHEN: The accept() method is called
settings_form.accept()
# THEN: The general tab's save() method should have been called, but not the themes tab
mocked_general_save.assert_called_with()
assert 0 == mocked_theme_save.call_count, 'The Themes tab\'s save() should not have been called'
def test_list_item_changed_invalid_item(self):
"""
Test that the list_item_changed() slot handles a non-existent item
"""
# GIVEN: A mocked tab inserted into a Settings Form
settings_form = SettingsForm(None)
general_tab = QtWidgets.QWidget(None)
general_tab.tab_title = 'mock'
general_tab.tab_title_visible = 'Mock'
general_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_general_load = MagicMock()
general_tab.load = mocked_general_load
# WHEN: We insert the general tab
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
settings_form.insert_tab(general_tab, is_visible=True)
with patch.object(settings_form.stacked_layout, 'count') as mocked_count:
# WHEN: The list_item_changed() slot is called with an invalid item index
settings_form.list_item_changed(100)
# THEN: The general tab should have been inserted into the stacked layout and an item inserted into the list
mocked_add_widget.assert_called_with(general_tab)
assert 1 == mocked_add_item.call_count, 'addItem should have been called'
# THEN: The rest of the method should not have been called
assert 0 == mocked_count.call_count, 'The count method of the stacked layout should not be called'
def test_reject_with_inactive_items(self):
"""
Test that the reject() method works correctly when some of the plugins are inactive
"""
# GIVEN: A visible general tab and an invisible theme tab in a Settings Form
settings_form = SettingsForm(None)
general_tab = QtWidgets.QWidget(None)
general_tab.tab_title = 'mock-general'
general_tab.tab_title_visible = 'Mock General'
general_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_general_cancel = MagicMock()
general_tab.cancel = mocked_general_cancel
mocked_general_load = MagicMock()
general_tab.load = mocked_general_load
settings_form.insert_tab(general_tab, is_visible=True)
themes_tab = QtWidgets.QWidget(None)
themes_tab.tab_title = 'mock-themes'
themes_tab.tab_title_visible = 'Mock Themes'
themes_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_theme_cancel = MagicMock()
themes_tab.cancel = mocked_theme_cancel
settings_form.insert_tab(themes_tab, is_visible=False)
def test_insert_tab_not_visible(registry):
"""
Test that the insert_tab() method works correctly when a tab that should not be visible is inserted
"""
# GIVEN: A general tab and a Settings Form
settings_form = SettingsForm(None)
general_tab = MagicMock()
general_tab.tab_title = 'mock'
# WHEN: The reject() method is called
settings_form.reject()
# WHEN: We insert the general tab
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
settings_form.insert_tab(general_tab, is_visible=False)
# THEN: The general tab's cancel() method should have been called, but not the themes tab
mocked_general_cancel.assert_called_with()
assert 0 == mocked_theme_cancel.call_count, 'The Themes tab\'s cancel() should not have been called'
# THEN: The general tab should have been inserted, but no list item should have been inserted into the list
mocked_add_widget.assert_called_with(general_tab)
assert 0 == mocked_add_item.call_count, 'addItem should not have been called'
def test_register_post_process(self):
"""
Test that the register_post_process() method works correctly
"""
# GIVEN: A settings form instance
settings_form = SettingsForm(None)
fake_function = MagicMock()
# WHEN: register_post_process() is called
settings_form.register_post_process(fake_function)
def test_accept_with_inactive_plugins(registry):
"""
Test that the accept() method works correctly when some of the plugins are inactive
"""
# GIVEN: A visible general tab and an invisible theme tab in a Settings Form
settings_form = SettingsForm(None)
general_tab = QtWidgets.QWidget(None)
general_tab.tab_title = 'mock-general'
general_tab.tab_title_visible = 'Mock General'
general_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_general_save = MagicMock()
general_tab.save = mocked_general_save
mocked_general_load = MagicMock()
general_tab.load = mocked_general_load
settings_form.insert_tab(general_tab, is_visible=True)
themes_tab = QtWidgets.QWidget(None)
themes_tab.tab_title = 'mock-themes'
themes_tab.tab_title_visible = 'Mock Themes'
themes_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_theme_save = MagicMock()
themes_tab.save = mocked_theme_save
mocked_theme_load = MagicMock()
themes_tab.load = mocked_theme_load
settings_form.insert_tab(themes_tab, is_visible=False)
# THEN: The fake function should be in the settings form's list
assert fake_function in settings_form.processes
# WHEN: The accept() method is called
settings_form.accept()
# THEN: The general tab's save() method should have been called, but not the themes tab
mocked_general_save.assert_called_with()
assert 0 == mocked_theme_save.call_count, 'The Themes tab\'s save() should not have been called'
def test_list_item_changed_invalid_item(registry):
"""
Test that the list_item_changed() slot handles a non-existent item
"""
# GIVEN: A mocked tab inserted into a Settings Form
settings_form = SettingsForm(None)
general_tab = QtWidgets.QWidget(None)
general_tab.tab_title = 'mock'
general_tab.tab_title_visible = 'Mock'
general_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_general_load = MagicMock()
general_tab.load = mocked_general_load
settings_form.insert_tab(general_tab, is_visible=True)
with patch.object(settings_form.stacked_layout, 'count') as mocked_count:
# WHEN: The list_item_changed() slot is called with an invalid item index
settings_form.list_item_changed(100)
# THEN: The rest of the method should not have been called
assert 0 == mocked_count.call_count, 'The count method of the stacked layout should not be called'
def test_reject_with_inactive_items(registry):
"""
Test that the reject() method works correctly when some of the plugins are inactive
"""
# GIVEN: A visible general tab and an invisible theme tab in a Settings Form
settings_form = SettingsForm(None)
general_tab = QtWidgets.QWidget(None)
general_tab.tab_title = 'mock-general'
general_tab.tab_title_visible = 'Mock General'
general_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_general_cancel = MagicMock()
general_tab.cancel = mocked_general_cancel
mocked_general_load = MagicMock()
general_tab.load = mocked_general_load
settings_form.insert_tab(general_tab, is_visible=True)
themes_tab = QtWidgets.QWidget(None)
themes_tab.tab_title = 'mock-themes'
themes_tab.tab_title_visible = 'Mock Themes'
themes_tab.icon_path = ':/icon/openlp-logo.svg'
mocked_theme_cancel = MagicMock()
themes_tab.cancel = mocked_theme_cancel
settings_form.insert_tab(themes_tab, is_visible=False)
# WHEN: The reject() method is called
settings_form.reject()
# THEN: The general tab's cancel() method should have been called, but not the themes tab
mocked_general_cancel.assert_called_with()
assert 0 == mocked_theme_cancel.call_count, 'The Themes tab\'s cancel() should not have been called'
def test_register_post_process(registry):
"""
Test that the register_post_process() method works correctly
"""
# GIVEN: A settings form instance
settings_form = SettingsForm(None)
fake_function = MagicMock()
# WHEN: register_post_process() is called
settings_form.register_post_process(fake_function)
# THEN: The fake function should be in the settings form's list
assert fake_function in settings_form.processes

View File

@ -212,7 +212,7 @@ def test_toggle_display_show():
mocked_on_hide_display.assert_called_once_with(False)
def test_on_go_live_preview_controller():
def test_on_go_live_preview_controller(registry):
"""
Test that when the on_go_preview() method is called the message is sent to the preview controller and focus is
set correctly.
@ -226,7 +226,6 @@ def test_on_go_live_preview_controller():
mocked_preview_widget.current_slide_number.return_value = 1
mocked_preview_widget.slide_count = MagicMock(return_value=2)
mocked_preview_controller.preview_widget = MagicMock()
Registry.create()
Registry().register('preview_controller', mocked_preview_controller)
slide_controller = SlideController(None)
slide_controller.service_item = mocked_service_item
@ -240,7 +239,7 @@ def test_on_go_live_preview_controller():
mocked_preview_controller.preview_widget.setFocus.assert_called_once_with()
def test_on_go_live_live_controller():
def test_on_go_live_live_controller(registry):
"""
Test that when the on_go_live() method is called the message is sent to the live controller and focus is
set correctly.
@ -254,7 +253,6 @@ def test_on_go_live_live_controller():
mocked_preview_widget.current_slide_number.return_value = 1
mocked_preview_widget.slide_count = MagicMock(return_value=2)
mocked_live_controller.preview_widget = MagicMock()
Registry.create()
Registry().register('live_controller', mocked_live_controller)
slide_controller = SlideController(None)
slide_controller.service_item = mocked_service_item
@ -269,7 +267,7 @@ def test_on_go_live_live_controller():
mocked_live_controller.preview_widget.setFocus.assert_called_once_with()
def test_on_go_live_service_manager():
def test_on_go_live_service_manager(registry):
"""
Test that when the on_go_live() method is called the message is sent to the live controller and focus is
set correctly.
@ -285,7 +283,6 @@ def test_on_go_live_service_manager():
mocked_preview_widget.current_slide_number.return_value = 1
mocked_preview_widget.slide_count = MagicMock(return_value=2)
mocked_live_controller.preview_widget = MagicMock()
Registry.create()
Registry().register('live_controller', mocked_live_controller)
Registry().register('service_manager', mocked_service_manager)
slide_controller = SlideController(None)
@ -603,7 +600,7 @@ def test_on_slide_selected_index_no_service_item():
@patch.object(Registry, 'execute')
def test_on_slide_selected_index_service_item_command(mocked_execute):
def test_on_slide_selected_index_service_item_command(mocked_execute, registry):
"""
Test that when there is a command service item, the command is executed
"""
@ -614,7 +611,6 @@ def test_on_slide_selected_index_service_item_command(mocked_execute):
mocked_update_preview = MagicMock()
mocked_preview_widget = MagicMock()
mocked_slide_selected = MagicMock()
Registry.create()
slide_controller = SlideController(None)
slide_controller.service_item = mocked_item
slide_controller.update_preview = mocked_update_preview
@ -634,7 +630,7 @@ def test_on_slide_selected_index_service_item_command(mocked_execute):
@patch.object(Registry, 'execute')
def test_on_slide_selected_index_service_item_not_command(mocked_execute):
def test_on_slide_selected_index_service_item_not_command(mocked_execute, registry):
"""
Test that when there is a service item but it's not a command, the preview widget is updated
"""
@ -645,7 +641,6 @@ def test_on_slide_selected_index_service_item_not_command(mocked_execute):
mocked_update_preview = MagicMock()
mocked_preview_widget = MagicMock()
mocked_slide_selected = MagicMock()
Registry.create()
slide_controller = SlideController(None)
slide_controller.service_item = mocked_item
slide_controller.update_preview = mocked_update_preview
@ -664,7 +659,7 @@ def test_on_slide_selected_index_service_item_not_command(mocked_execute):
@patch.object(Registry, 'execute')
def test_process_item(mocked_execute):
def test_process_item(mocked_execute, registry):
"""
Test that presentation service-items is closed when followed by a media service-item
"""
@ -685,7 +680,6 @@ def test_process_item(mocked_execute):
mocked_media_item.from_service = False
mocked_media_item.get_frames.return_value = []
mocked_main_window = MagicMock()
Registry.create()
Registry().register('main_window', mocked_main_window)
Registry().register('media_controller', MagicMock())
slide_controller = SlideController(None)
@ -784,7 +778,7 @@ def test_on_preview_double_click_add_to_service(mock_settings):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def test_update_preview_live(mocked_singleShot, mocked_image_manager):
def test_update_preview_live(mocked_singleShot, mocked_image_manager, registry):
"""
Test that the preview screen is updated with a screen grab for live service items
"""
@ -797,8 +791,6 @@ def test_update_preview_live(mocked_singleShot, mocked_image_manager):
mocked_live_item.is_capable.side_effect = [True, True]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
@ -827,7 +819,7 @@ def test_update_preview_live(mocked_singleShot, mocked_image_manager):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def test_update_preview_pres(mocked_singleShot, mocked_image_manager):
def test_update_preview_pres(mocked_singleShot, mocked_image_manager, registry):
"""
Test that the preview screen is updated with the correct preview for presentation service items
"""
@ -840,8 +832,6 @@ def test_update_preview_pres(mocked_singleShot, mocked_image_manager):
mocked_pres_item.is_capable.side_effect = [True, True]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
@ -869,7 +859,7 @@ def test_update_preview_pres(mocked_singleShot, mocked_image_manager):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def test_update_preview_media(mocked_singleShot, mocked_image_manager):
def test_update_preview_media(mocked_singleShot, mocked_image_manager, registry):
"""
Test that the preview screen is updated with the correct preview for media service items
"""
@ -883,7 +873,6 @@ def test_update_preview_media(mocked_singleShot, mocked_image_manager):
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
@ -912,7 +901,7 @@ def test_update_preview_media(mocked_singleShot, mocked_image_manager):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def test_update_preview_image(mocked_singleShot, mocked_image_manager):
def test_update_preview_image(mocked_singleShot, mocked_image_manager, registry):
"""
Test that the preview screen is updated with the correct preview for image service items
"""
@ -926,7 +915,6 @@ def test_update_preview_image(mocked_singleShot, mocked_image_manager):
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
@ -1030,12 +1018,11 @@ def test_set_text(mocked_super):
mocked_super().setText.assert_called_once_with('Label Text')
def test_initial_live_controller():
def test_initial_live_controller(registry):
"""
Test the initial live slide controller state .
"""
# GIVEN: A new SlideController instance.
Registry.create()
live_controller = LiveController(None)
# WHEN: the default controller is built.
@ -1043,12 +1030,11 @@ def test_initial_live_controller():
assert live_controller.is_live is True, 'The slide controller should be a live controller'
def test_initial_preview_controller():
def test_initial_preview_controller(registry):
"""
Test the initial preview slide controller state.
"""
# GIVEN: A new SlideController instance.
Registry.create()
preview_controller = PreviewController(None)
# WHEN: the default controller is built.

View File

@ -26,21 +26,17 @@ from PyQt5 import QtCore
from openlp.core.ui.splashscreen import SplashScreen
class TestSplashScreen():
def test_splashscreen():
"""
This will test the SplachScreen.py file
Test that the SpashScreen is created correctly
"""
def test_SplashScreen(self):
"""
Test that the SpashScreen is created correctly
"""
# GIVEN: the SplashScreen class
# WHEN: An object is created
# GIVEN: the SplashScreen class
# WHEN: An object is created
ss = SplashScreen()
# THEN: Nothing should go wrong and the instance should have the correct values
assert ss.objectName() == 'splashScreen', 'The ObjectName should have be ' \
'splashScreen'
assert ss.frameSize() == QtCore.QSize(370, 370), 'The frameSize should be (370, 370)'
assert ss.contextMenuPolicy() == QtCore.Qt.PreventContextMenu, 'The ContextMenuPolicy ' \
'should have been QtCore.Qt.PreventContextMenu or 4'
ss = SplashScreen()
# THEN: Nothing should go wrong and the instance should have the correct values
assert ss.objectName() == 'splashScreen', 'The ObjectName should have be ' \
'splashScreen'
assert ss.frameSize() == QtCore.QSize(370, 370), 'The frameSize should be (370, 370)'
assert ss.contextMenuPolicy() == QtCore.Qt.PreventContextMenu, 'The ContextMenuPolicy ' \
'should have been QtCore.Qt.PreventContextMenu or 4'

View File

@ -31,14 +31,13 @@ from openlp.core.ui.style import MEDIA_MANAGER_STYLE, WIN_REPAIR_STYLESHEET, get
@skipIf(not hasattr(openlp.core.ui.style, 'qdarkstyle'), 'qdarkstyle is not installed')
@patch('openlp.core.ui.style.HAS_DARK_STYLE', True)
@patch('openlp.core.ui.style.Settings')
@patch('openlp.core.ui.style.qdarkstyle')
def test_get_application_stylesheet_dark(mocked_qdarkstyle, MockSettings):
def test_get_application_stylesheet_dark(mocked_qdarkstyle, mock_settings):
"""Test that the dark stylesheet is returned when available and enabled"""
# GIVEN: We're on Windows and no dark style is set
mocked_settings = MagicMock()
mocked_settings.value.return_value = True
MockSettings.return_value = mocked_settings
mock_settings.return_value = mocked_settings
mocked_qdarkstyle.load_stylesheet_pyqt5.return_value = 'dark_style'
# WHEN: can_show_icon() is called

View File

@ -23,9 +23,9 @@ Package to test the openlp.core.ui.thememanager package.
"""
import os
import shutil
import pytest
from pathlib import Path
from tempfile import mkdtemp
from unittest import TestCase
from unittest.mock import ANY, Mock, MagicMock, patch, call
from PyQt5 import QtWidgets
@ -35,341 +35,346 @@ from openlp.core.ui.thememanager import ThemeManager
from tests.utils.constants import RESOURCE_PATH
class TestThemeManager(TestCase):
@pytest.yield_fixture()
def temp_folder():
tmp_folder = mkdtemp()
yield tmp_folder
shutil.rmtree(tmp_folder)
def setUp(self):
"""
Set up the tests
"""
Registry.create()
self.temp_folder = mkdtemp()
def tearDown(self):
"""
Clean up
"""
shutil.rmtree(self.temp_folder)
@patch('openlp.core.ui.thememanager.zipfile.ZipFile.__init__')
@patch('openlp.core.ui.thememanager.zipfile.ZipFile.write')
def test_export_theme(mocked_zipfile_write, mocked_zipfile_init, registry):
"""
Test exporting a theme .
"""
# GIVEN: A new ThemeManager instance.
theme_manager = ThemeManager()
theme_manager.theme_path = RESOURCE_PATH / 'themes'
mocked_zipfile_init.return_value = None
@patch('openlp.core.ui.thememanager.zipfile.ZipFile.__init__')
@patch('openlp.core.ui.thememanager.zipfile.ZipFile.write')
def test_export_theme(self, mocked_zipfile_write, mocked_zipfile_init):
"""
Test exporting a theme .
"""
# GIVEN: A new ThemeManager instance.
theme_manager = ThemeManager()
theme_manager.theme_path = RESOURCE_PATH / 'themes'
mocked_zipfile_init.return_value = None
# WHEN: The theme is exported
theme_manager._export_theme(Path('some', 'path', 'Default.otz'), 'Default')
# WHEN: The theme is exported
theme_manager._export_theme(Path('some', 'path', 'Default.otz'), 'Default')
# THEN: The zipfile should be created at the given path
mocked_zipfile_init.assert_called_with(Path('some', 'path', 'Default.otz'), 'w')
mocked_zipfile_write.assert_called_with(RESOURCE_PATH / 'themes' / 'Default' / 'Default.xml',
Path('Default', 'Default.xml'))
# THEN: The zipfile should be created at the given path
mocked_zipfile_init.assert_called_with(Path('some', 'path', 'Default.otz'), 'w')
mocked_zipfile_write.assert_called_with(RESOURCE_PATH / 'themes' / 'Default' / 'Default.xml',
Path('Default', 'Default.xml'))
def test_initial_theme_manager(self):
"""
Test the instantiation of theme manager.
"""
# GIVEN: A new service manager instance.
ThemeManager(None)
def test_initial_theme_manager(registry):
"""
Test the instantiation of theme manager.
"""
# GIVEN: A new service manager instance.
ThemeManager(None)
# WHEN: the default theme manager is built.
# THEN: The the controller should be registered in the registry.
assert Registry().get('theme_manager') is not None, 'The base theme manager should be registered'
# WHEN: the default theme manager is built.
# THEN: The the controller should be registered in the registry.
assert Registry().get('theme_manager') is not None, 'The base theme manager should be registered'
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_same_image(self, mocked_create_paths, mocked_shutil):
"""
Test that we don't try to overwrite a theme background image with itself
"""
# GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
# theme, create_paths, thememanager-attributes and background
# .filename path is the same as the source path.
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_same_image(mocked_create_paths, mocked_shutil, registry):
"""
Test that we don't try to overwrite a theme background image with itself
"""
# GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
# theme, create_paths, thememanager-attributes and background
# .filename path is the same as the source path.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = None
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.extract_formatted_xml = MagicMock()
mocked_theme.extract_formatted_xml.return_value = 'fake_theme_xml'.encode()
file_path_1 = RESOURCE_PATH / 'church.jpg'
mocked_theme.background_filename = file_path_1
mocked_theme.background_source = file_path_1
# WHEN: Calling save_theme with both background paths to the same image
theme_manager.save_theme(mocked_theme)
# THEN: The mocked_copyfile should not have been called
assert mocked_shutil.copyfile.called is False, 'copyfile should not be called'
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_diff_images(mocked_create_paths, mocked_shutil, registry):
"""
Test that we do overwrite a theme background image when a new is submitted
"""
# GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
# theme, create_paths, thememanager-attributes and background
# .filename path is the same as the source path.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = None
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = RESOURCE_PATH / 'church.jpg'
mocked_theme.background_source = RESOURCE_PATH / 'church2.jpg'
# WHEN: Calling save_theme with both background paths to different images
theme_manager.save_theme(mocked_theme)
# THEN: The mocked_copyfile should have been called
assert mocked_shutil.copyfile.called is True, 'copyfile should be called'
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_delete_old_image(mocked_create_paths, mocked_delete_file, mocked_shutil, registry):
"""
Test that we do delete a old theme background image when a new is submitted
"""
# GIVEN: A new theme manager instance, with mocked builtins.open,
# theme, create_paths, thememanager-attributes and background
# .filename path is the same as the source path.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = RESOURCE_PATH / 'old_church.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = RESOURCE_PATH / 'church.jpg'
mocked_theme.background_source = RESOURCE_PATH / 'church2.jpg'
# WHEN: Calling save_theme with both background paths to different images
theme_manager.save_theme(mocked_theme)
# THEN: The mocked_delete_file should have been called to delete the old cached background
assert mocked_delete_file.called is True, 'delete_file should be called'
@patch.object(ThemeManager, 'log_exception')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_missing_original(mocked_paths, mocked_delete, mocked_log_exception, registry):
"""
Test that we revert to the old theme background image if the source is missing
when changing the theme. (User doesn't change background but the original is
missing)
"""
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
# has left the background the same, or reselected the same path.
# Not using resource dir because I could potentially copy a file
folder_path = Path(mkdtemp())
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = folder_path / 'old.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = folder_path / 'old.png'
mocked_theme.background_source = folder_path / 'non_existent_original.png'
# WHEN: Calling save_theme with a invalid background_filename
# Although all filenames are considered invalid in this test,
# it is important it reverts to the old background path as this in reality is always
# valid unless someone has messed with the cache.
theme_manager.save_theme(mocked_theme)
# THEN: The old background should not have bee deleted
# AND the filename should have been replaced with the old cached background
# AND there is no exception
assert mocked_delete.called is False, 'delete_file should not be called'
assert mocked_theme.background_filename == theme_manager.old_background_image_path, \
'Background path should be reverted'
assert mocked_log_exception.called is False, \
'Should not have been an exception as the file wasn\'t changed'
@patch.object(ThemeManager, 'log_warning')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_missing_new(mocked_paths, mocked_delete, mocked_log_warning, registry):
"""
Test that we log a warning if the new background is missing
"""
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
# has changed the background to a invalid path.
# Not using resource dir because I could potentially copy a file
folder_path = Path(mkdtemp())
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = folder_path / 'old.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = folder_path / 'new_cached.png'
mocked_theme.background_source = folder_path / 'new_original.png'
# WHEN: Calling save_theme with a invalid background_filename
theme_manager.save_theme(mocked_theme)
# THEN: A warning should have happened due to attempting to copy a missing file
mocked_log_warning.assert_called_once_with('Background does not exist, retaining cached background')
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_background_override(mocked_paths, mocked_delete, mocked_shutil, registry):
"""
Test that we log a warning if the new background is missing
"""
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
# has changed the background to a invalid path.
# Not using resource dir because I could potentially copy a file
folder_path = Path(mkdtemp())
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = folder_path / 'old.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = folder_path / 'new_cached.png'
# mocked_theme.background_source.exists() will return True
mocked_theme.background_source = MagicMock()
# override_background.exists() will return True
override_background = MagicMock()
# WHEN: Calling save_theme with a background override
theme_manager.save_theme(mocked_theme, background_override=override_background)
# THEN: The override_background should have been copied rather than the background_source
mocked_shutil.copyfile.assert_called_once_with(override_background, mocked_theme.background_filename)
def test_save_theme_special_char_name(registry, temp_folder):
"""
Test that we can save themes with special characters in the name
"""
# GIVEN: A new theme manager instance, with mocked theme and thememanager-attributes.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = None
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = Path(temp_folder)
mocked_theme = MagicMock()
mocked_theme.theme_name = 'theme 愛 name'
mocked_theme.export_theme.return_value = "{}"
# WHEN: Calling save_theme with a theme with a name with special characters in it
theme_manager.save_theme(mocked_theme)
# THEN: It should have been created
assert os.path.exists(os.path.join(temp_folder, 'theme 愛 name', 'theme 愛 name.json')) is True, \
'Theme with special characters should have been created!'
@patch('openlp.core.ui.thememanager.QtWidgets.QMessageBox.question', return_value=QtWidgets.QMessageBox.Yes)
@patch('openlp.core.ui.thememanager.translate')
def test_over_write_message_box_yes(mocked_translate, mocked_qmessagebox_question, registry):
"""
Test that theme_manager.over_write_message_box returns True when the user clicks yes.
"""
# GIVEN: A patched QMessageBox.question and an instance of ThemeManager
mocked_translate.side_effect = lambda context, text: text
theme_manager = ThemeManager(None)
# WHEN: Calling over_write_message_box with 'Theme Name'
result = theme_manager.over_write_message_box('Theme Name')
# THEN: over_write_message_box should return True and the message box should contain the theme name
assert result is True
mocked_qmessagebox_question.assert_called_once_with(
theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?',
defaultButton=ANY)
@patch('openlp.core.ui.thememanager.QtWidgets.QMessageBox.question', return_value=QtWidgets.QMessageBox.No)
@patch('openlp.core.ui.thememanager.translate')
def test_over_write_message_box_no(mocked_translate, mocked_qmessagebox_question, registry):
"""
Test that theme_manager.over_write_message_box returns False when the user clicks no.
"""
# GIVEN: A patched QMessageBox.question and an instance of ThemeManager
mocked_translate.side_effect = lambda context, text: text
theme_manager = ThemeManager(None)
# WHEN: Calling over_write_message_box with 'Theme Name'
result = theme_manager.over_write_message_box('Theme Name')
# THEN: over_write_message_box should return False and the message box should contain the theme name
assert result is False
mocked_qmessagebox_question.assert_called_once_with(
theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?',
defaultButton=ANY)
def test_unzip_theme(registry):
"""
Test that unzipping of themes works
"""
# GIVEN: A theme file, a output folder and some mocked out internal functions
with patch('openlp.core.ui.thememanager.critical_error_message_box') \
as mocked_critical_error_message_box:
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = None
theme_manager._create_theme_from_xml = MagicMock()
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.extract_formatted_xml = MagicMock()
mocked_theme.extract_formatted_xml.return_value = 'fake_theme_xml'.encode()
file_path_1 = RESOURCE_PATH / 'church.jpg'
mocked_theme.background_filename = file_path_1
mocked_theme.background_source = file_path_1
# WHEN: Calling save_theme with both background paths to the same image
theme_manager.save_theme(mocked_theme)
# THEN: The mocked_copyfile should not have been called
assert mocked_shutil.copyfile.called is False, 'copyfile should not be called'
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_diff_images(self, mocked_create_paths, mocked_shutil):
"""
Test that we do overwrite a theme background image when a new is submitted
"""
# GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
# theme, create_paths, thememanager-attributes and background
# .filename path is the same as the source path.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = None
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = RESOURCE_PATH / 'church.jpg'
mocked_theme.background_source = RESOURCE_PATH / 'church2.jpg'
# WHEN: Calling save_theme with both background paths to different images
theme_manager.save_theme(mocked_theme)
# THEN: The mocked_copyfile should have been called
assert mocked_shutil.copyfile.called is True, 'copyfile should be called'
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_delete_old_image(self, mocked_create_paths, mocked_delete_file, mocked_shutil):
"""
Test that we do delete a old theme background image when a new is submitted
"""
# GIVEN: A new theme manager instance, with mocked builtins.open,
# theme, create_paths, thememanager-attributes and background
# .filename path is the same as the source path.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = RESOURCE_PATH / 'old_church.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = RESOURCE_PATH / 'church.jpg'
mocked_theme.background_source = RESOURCE_PATH / 'church2.jpg'
# WHEN: Calling save_theme with both background paths to different images
theme_manager.save_theme(mocked_theme)
# THEN: The mocked_delete_file should have been called to delete the old cached background
assert mocked_delete_file.called is True, 'delete_file should be called'
@patch.object(ThemeManager, 'log_exception')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_missing_original(self, mocked_paths, mocked_delete, mocked_log_exception):
"""
Test that we revert to the old theme background image if the source is missing
when changing the theme. (User doesn't change background but the original is
missing)
"""
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
# has left the background the same, or reselected the same path.
# Not using resource dir because I could potentially copy a file
theme_manager.theme_path = None
folder_path = Path(mkdtemp())
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = folder_path / 'old.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = folder_path / 'old.png'
mocked_theme.background_source = folder_path / 'non_existent_original.png'
theme_file_path = RESOURCE_PATH / 'themes' / 'Moss_on_tree.otz'
# WHEN: Calling save_theme with a invalid background_filename
# Although all filenames are considered invalid in this test,
# it is important it reverts to the old background path as this in reality is always
# valid unless someone has messed with the cache.
theme_manager.save_theme(mocked_theme)
# WHEN: We try to unzip it
theme_manager.unzip_theme(theme_file_path, folder_path)
# THEN: The old background should not have bee deleted
# AND the filename should have been replaced with the old cached background
# AND there is no exception
assert mocked_delete.called is False, 'delete_file should not be called'
assert mocked_theme.background_filename == theme_manager.old_background_image_path, \
'Background path should be reverted'
assert mocked_log_exception.called is False, \
'Should not have been an exception as the file wasn\'t changed'
# THEN: Files should be unpacked
assert (folder_path / 'Moss on tree' / 'Moss on tree.xml').exists() is True
assert mocked_critical_error_message_box.call_count == 0, 'No errors should have happened'
shutil.rmtree(folder_path)
@patch.object(ThemeManager, 'log_warning')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_missing_new(self, mocked_paths, mocked_delete, mocked_log_warning):
"""
Test that we log a warning if the new background is missing
"""
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
# has changed the background to a invalid path.
# Not using resource dir because I could potentially copy a file
folder_path = Path(mkdtemp())
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = folder_path / 'old.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = folder_path / 'new_cached.png'
mocked_theme.background_source = folder_path / 'new_original.png'
# WHEN: Calling save_theme with a invalid background_filename
theme_manager.save_theme(mocked_theme)
def test_unzip_theme_invalid_version(registry):
"""
Test that themes with invalid (< 2.0) or with no version attributes are rejected
"""
# GIVEN: An instance of ThemeManager whilst mocking a theme that returns a theme with no version attribute
with patch('openlp.core.ui.thememanager.zipfile.ZipFile') as mocked_zip_file,\
patch('openlp.core.ui.thememanager.ElementTree.getroot') as mocked_getroot,\
patch('openlp.core.ui.thememanager.XML'),\
patch('openlp.core.ui.thememanager.critical_error_message_box') as mocked_critical_error_message_box:
# THEN: A warning should have happened due to attempting to copy a missing file
mocked_log_warning.assert_called_once_with('Background does not exist, retaining cached background')
@patch('openlp.core.ui.thememanager.shutil')
@patch('openlp.core.ui.thememanager.delete_file')
@patch('openlp.core.ui.thememanager.create_paths')
def test_save_theme_background_override(self, mocked_paths, mocked_delete, mocked_shutil):
"""
Test that we log a warning if the new background is missing
"""
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
# has changed the background to a invalid path.
# Not using resource dir because I could potentially copy a file
folder_path = Path(mkdtemp())
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = folder_path / 'old.png'
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = MagicMock()
mocked_theme = MagicMock()
mocked_theme.theme_name = 'themename'
mocked_theme.background_filename = folder_path / 'new_cached.png'
# mocked_theme.background_source.exists() will return True
mocked_theme.background_source = MagicMock()
# override_background.exists() will return True
override_background = MagicMock()
# WHEN: Calling save_theme with a background override
theme_manager.save_theme(mocked_theme, background_override=override_background)
# THEN: The override_background should have been copied rather than the background_source
mocked_shutil.copyfile.assert_called_once_with(override_background, mocked_theme.background_filename)
def test_save_theme_special_char_name(self):
"""
Test that we can save themes with special characters in the name
"""
# GIVEN: A new theme manager instance, with mocked theme and thememanager-attributes.
theme_manager = ThemeManager(None)
theme_manager.old_background_image_path = None
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = Path(self.temp_folder)
mocked_theme = MagicMock()
mocked_theme.theme_name = 'theme 愛 name'
mocked_theme.export_theme.return_value = "{}"
# WHEN: Calling save_theme with a theme with a name with special characters in it
theme_manager.save_theme(mocked_theme)
# THEN: It should have been created
assert os.path.exists(os.path.join(self.temp_folder, 'theme 愛 name', 'theme 愛 name.json')) is True, \
'Theme with special characters should have been created!'
@patch('openlp.core.ui.thememanager.QtWidgets.QMessageBox.question', return_value=QtWidgets.QMessageBox.Yes)
@patch('openlp.core.ui.thememanager.translate')
def test_over_write_message_box_yes(self, mocked_translate, mocked_qmessagebox_question):
"""
Test that theme_manager.over_write_message_box returns True when the user clicks yes.
"""
# GIVEN: A patched QMessageBox.question and an instance of ThemeManager
mocked_translate.side_effect = lambda context, text: text
mocked_zip_file.return_value = MagicMock(**{'namelist.return_value': [os.path.join('theme', 'theme.xml')]})
mocked_getroot.return_value = MagicMock(**{'get.return_value': None})
theme_manager = ThemeManager(None)
# WHEN: Calling over_write_message_box with 'Theme Name'
result = theme_manager.over_write_message_box('Theme Name')
# WHEN: unzip_theme is called
theme_manager.unzip_theme(Path('theme.file'), Path('folder'))
# THEN: over_write_message_box should return True and the message box should contain the theme name
assert result is True
mocked_qmessagebox_question.assert_called_once_with(
theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?',
defaultButton=ANY)
# THEN: The critical_error_message_box should have been called
assert mocked_critical_error_message_box.call_count == 1, 'Should have been called once'
@patch('openlp.core.ui.thememanager.QtWidgets.QMessageBox.question', return_value=QtWidgets.QMessageBox.No)
@patch('openlp.core.ui.thememanager.translate')
def test_over_write_message_box_no(self, mocked_translate, mocked_qmessagebox_question):
"""
Test that theme_manager.over_write_message_box returns False when the user clicks no.
"""
# GIVEN: A patched QMessageBox.question and an instance of ThemeManager
mocked_translate.side_effect = lambda context, text: text
theme_manager = ThemeManager(None)
# WHEN: Calling over_write_message_box with 'Theme Name'
result = theme_manager.over_write_message_box('Theme Name')
def test_update_preview_images(registry):
"""
Test that the update_preview_images() method works correctly
"""
# GIVEN: A ThemeManager
def get_theme_data(value):
return '{}_theme_data'.format(value)
theme_manager = ThemeManager(None)
theme_manager.save_preview = MagicMock()
theme_manager._get_theme_data = Mock(side_effect=get_theme_data)
theme_manager.progress_form = MagicMock(**{'get_preview.return_value': 'preview'})
theme_manager.load_themes = MagicMock()
theme_list = {'Default': get_theme_data('Default'), 'Test': get_theme_data('Test')}
# THEN: over_write_message_box should return False and the message box should contain the theme name
assert result is False
mocked_qmessagebox_question.assert_called_once_with(
theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?',
defaultButton=ANY)
# WHEN: ThemeManager.update_preview_images() is called
theme_manager.update_preview_images(theme_list)
def test_unzip_theme(self):
"""
Test that unzipping of themes works
"""
# GIVEN: A theme file, a output folder and some mocked out internal functions
with patch('openlp.core.ui.thememanager.critical_error_message_box') \
as mocked_critical_error_message_box:
theme_manager = ThemeManager(None)
theme_manager._create_theme_from_xml = MagicMock()
theme_manager.update_preview_images = MagicMock()
theme_manager.theme_path = None
folder_path = Path(mkdtemp())
theme_file_path = RESOURCE_PATH / 'themes' / 'Moss_on_tree.otz'
# WHEN: We try to unzip it
theme_manager.unzip_theme(theme_file_path, folder_path)
# THEN: Files should be unpacked
assert (folder_path / 'Moss on tree' / 'Moss on tree.xml').exists() is True
assert mocked_critical_error_message_box.call_count == 0, 'No errors should have happened'
shutil.rmtree(folder_path)
def test_unzip_theme_invalid_version(self):
"""
Test that themes with invalid (< 2.0) or with no version attributes are rejected
"""
# GIVEN: An instance of ThemeManager whilst mocking a theme that returns a theme with no version attribute
with patch('openlp.core.ui.thememanager.zipfile.ZipFile') as mocked_zip_file,\
patch('openlp.core.ui.thememanager.ElementTree.getroot') as mocked_getroot,\
patch('openlp.core.ui.thememanager.XML'),\
patch('openlp.core.ui.thememanager.critical_error_message_box') as mocked_critical_error_message_box:
mocked_zip_file.return_value = MagicMock(**{'namelist.return_value': [os.path.join('theme', 'theme.xml')]})
mocked_getroot.return_value = MagicMock(**{'get.return_value': None})
theme_manager = ThemeManager(None)
# WHEN: unzip_theme is called
theme_manager.unzip_theme(Path('theme.file'), Path('folder'))
# THEN: The critical_error_message_box should have been called
assert mocked_critical_error_message_box.call_count == 1, 'Should have been called once'
def test_update_preview_images(self):
"""
Test that the update_preview_images() method works correctly
"""
# GIVEN: A ThemeManager
def get_theme_data(value):
return '{}_theme_data'.format(value)
theme_manager = ThemeManager(None)
theme_manager.save_preview = MagicMock()
theme_manager._get_theme_data = Mock(side_effect=get_theme_data)
theme_manager.progress_form = MagicMock(**{'get_preview.return_value': 'preview'})
theme_manager.load_themes = MagicMock()
theme_list = {'Default': get_theme_data('Default'), 'Test': get_theme_data('Test')}
# WHEN: ThemeManager.update_preview_images() is called
theme_manager.update_preview_images(theme_list)
# THEN: Things should work right
assert theme_manager.progress_form.theme_list == theme_list
theme_manager.progress_form.show.assert_called_once_with()
assert theme_manager.progress_form.get_preview.call_args_list == [call('Default', get_theme_data('Default')),
call('Test', get_theme_data('Test'))]
assert theme_manager.save_preview.call_args_list == [call('Default', 'preview'), call('Test', 'preview')]
theme_manager.progress_form.close.assert_called_once_with()
theme_manager.load_themes.assert_called_once_with()
# THEN: Things should work right
assert theme_manager.progress_form.theme_list == theme_list
theme_manager.progress_form.show.assert_called_once_with()
assert theme_manager.progress_form.get_preview.call_args_list == [call('Default', get_theme_data('Default')),
call('Test', get_theme_data('Test'))]
assert theme_manager.save_preview.call_args_list == [call('Default', 'preview'), call('Test', 'preview')]
theme_manager.progress_form.close.assert_called_once_with()
theme_manager.load_themes.assert_called_once_with()

View File

@ -32,7 +32,10 @@ from openlp.core.common.i18n import UiStrings
from openlp.core.widgets.views import ListPreviewWidget, ListWidgetWithDnD, TreeWidgetWithDnD, handle_mime_data_urls
from openlp.core.ui.icons import UiIcons
CLAPPERBOARD = UiIcons().clapperboard
@pytest.fixture
def clapperboard(mock_settings):
return UiIcons().clapperboard
@pytest.yield_fixture
@ -202,7 +205,7 @@ def test_replace_recalculate_layout_text(mocked_setRowHeight, mocked_resizeRowsT
@patch(u'openlp.core.widgets.views.ListPreviewWidget.resizeRowsToContents')
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
def test_replace_recalculate_layout_img(mocked_setRowHeight, mocked_resizeRowsToContents,
preview_widget_env, mock_settings):
preview_widget_env, mock_settings, clapperboard):
"""
Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc...
"""
@ -218,8 +221,8 @@ def test_replace_recalculate_layout_img(mocked_setRowHeight, mocked_resizeRowsTo
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': CLAPPERBOARD},
{'title': None, 'path': None, 'image': CLAPPERBOARD}]
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': clapperboard},
{'title': None, 'path': None, 'image': clapperboard}]
# init ListPreviewWidget and load service item
list_preview_widget = ListPreviewWidget(None, 1)
list_preview_widget.replace_service_item(service_item, 200, 0)
@ -242,7 +245,7 @@ def test_replace_recalculate_layout_img(mocked_setRowHeight, mocked_resizeRowsTo
@patch(u'openlp.core.widgets.views.ListPreviewWidget.resizeRowsToContents')
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
def test_replace_recalculate_layout_img_max(mocked_setRowHeight, mocked_resizeRowsToContents,
preview_widget_env, mock_settings):
preview_widget_env, mock_settings, clapperboard):
"""
Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc...
"""
@ -258,8 +261,8 @@ def test_replace_recalculate_layout_img_max(mocked_setRowHeight, mocked_resizeRo
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': CLAPPERBOARD},
{'title': None, 'path': None, 'image': CLAPPERBOARD}]
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': clapperboard},
{'title': None, 'path': None, 'image': clapperboard}]
# init ListPreviewWidget and load service item
list_preview_widget = ListPreviewWidget(None, 1)
list_preview_widget.replace_service_item(service_item, 200, 0)
@ -280,7 +283,7 @@ def test_replace_recalculate_layout_img_max(mocked_setRowHeight, mocked_resizeRo
@patch(u'openlp.core.widgets.views.ListPreviewWidget.resizeRowsToContents')
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
def test_replace_recalculate_layout_img_auto(mocked_setRowHeight, mocked_resizeRowsToContents,
preview_widget_env, mock_settings):
preview_widget_env, mock_settings, clapperboard):
"""
Test if "Max height for non-text slides..." auto, img slides resized in replace_service_item & __recalc...
"""
@ -297,8 +300,8 @@ def test_replace_recalculate_layout_img_auto(mocked_setRowHeight, mocked_resizeR
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': CLAPPERBOARD},
{'title': None, 'path': None, 'image': CLAPPERBOARD}]
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': clapperboard},
{'title': None, 'path': None, 'image': clapperboard}]
# init ListPreviewWidget and load service item
list_preview_widget = ListPreviewWidget(None, 1)
list_preview_widget.replace_service_item(service_item, 200, 0)
@ -359,7 +362,7 @@ def test_row_resized_text(mocked_cellWidget, mocked_setRowHeight, mocked_resizeR
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
@patch(u'openlp.core.widgets.views.ListPreviewWidget.cellWidget')
def test_row_resized_img(mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents,
preview_widget_env, mock_settings):
preview_widget_env, mock_settings, clapperboard):
"""
Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized.
"""
@ -375,8 +378,8 @@ def test_row_resized_img(mocked_cellWidget, mocked_setRowHeight, mocked_resizeRo
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': CLAPPERBOARD},
{'title': None, 'path': None, 'image': CLAPPERBOARD}]
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': clapperboard},
{'title': None, 'path': None, 'image': clapperboard}]
# Mock self.cellWidget().children().setMaximumWidth()
mocked_cellWidget_child = MagicMock()
mocked_cellWidget_obj = MagicMock()
@ -399,7 +402,7 @@ def test_row_resized_img(mocked_cellWidget, mocked_setRowHeight, mocked_resizeRo
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
@patch(u'openlp.core.widgets.views.ListPreviewWidget.cellWidget')
def test_row_resized_img_max(mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents,
preview_widget_env, mock_settings):
preview_widget_env, mock_settings, clapperboard):
"""
Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized.
"""
@ -414,8 +417,8 @@ def test_row_resized_img_max(mocked_cellWidget, mocked_setRowHeight, mocked_resi
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': CLAPPERBOARD},
{'title': None, 'path': None, 'image': CLAPPERBOARD}]
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': clapperboard},
{'title': None, 'path': None, 'image': clapperboard}]
# Mock self.cellWidget().children().setMaximumWidth()
mocked_cellWidget_child = MagicMock()
mocked_cellWidget_obj = MagicMock()
@ -436,7 +439,7 @@ def test_row_resized_img_max(mocked_cellWidget, mocked_setRowHeight, mocked_resi
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
@patch(u'openlp.core.widgets.views.ListPreviewWidget.cellWidget')
def test_row_resized_setting_changed(mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents,
preview_widget_env, mock_settings):
preview_widget_env, mock_settings, clapperboard):
"""
Test if "Max height for non-text slides..." enabled while item live, program doesn't crash on row_resized.
"""
@ -452,8 +455,8 @@ def test_row_resized_setting_changed(mocked_cellWidget, mocked_setRowHeight, moc
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': CLAPPERBOARD},
{'title': None, 'path': None, 'image': CLAPPERBOARD}]
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': clapperboard},
{'title': None, 'path': None, 'image': clapperboard}]
# Mock self.cellWidget().children()
mocked_cellWidget_obj = MagicMock()
mocked_cellWidget_obj.children.return_value = None