Tests 3 - Finish UI and Widgets

This commit is contained in:
Tim Bentley 2020-02-15 21:04:17 +00:00
parent a0eeef724f
commit 86af416233
11 changed files with 2846 additions and 2763 deletions

View File

@ -82,11 +82,11 @@ def settings(qapp, registry):
def mock_settings(registry):
"""A Mock Settings() instance"""
# Create and register a mock settings object to work with
mock_settings = MagicMock()
Registry().register('settings', mock_settings)
yield mock_settings
mk_settings = MagicMock()
Registry().register('settings', mk_settings)
yield mk_settings
Registry().remove('settings')
del mock_settings
del mk_settings
@pytest.fixture(scope='function')

File diff suppressed because it is too large Load Diff

View File

@ -21,103 +21,100 @@
"""
Package to test the openlp.core.lib.mediamanageritem package.
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, patch
from openlp.core.common.registry import Registry
from openlp.core.lib.mediamanageritem import MediaManagerItem
from tests.helpers.testmixin import TestMixin
class TestMediaManagerItem(TestCase, TestMixin):
@pytest.yield_fixture
def media_env():
setup_patcher = patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup')
setup_patcher.start()
yield
setup_patcher.stop
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked(mocked_on_preview_click, media_env, registry):
"""
Test the MediaManagerItem class
Test that when an item is double-clicked then the item is previewed
"""
def setUp(self):
"""
Mock out stuff for all the tests
"""
Registry.create()
self.setup_patcher = patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup')
self.mocked_setup = self.setup_patcher.start()
self.addCleanup(self.setup_patcher.stop)
# GIVEN: A setting to enable "Double-click to go live" and a media manager item
mocked_settings = MagicMock()
mocked_settings.value.return_value = False
Registry().register('settings', mocked_settings)
mmi = MediaManagerItem(None)
mmi.can_preview = True
mmi.can_make_live = True
mmi.can_add_to_service = True
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked(self, mocked_on_preview_click):
"""
Test that when an item is double-clicked then the item is previewed
"""
# GIVEN: A setting to enable "Double-click to go live" and a media manager item
mocked_settings = MagicMock()
mocked_settings.value.return_value = False
Registry().register('settings', mocked_settings)
mmi = MediaManagerItem(None)
mmi.can_preview = True
mmi.can_make_live = True
mmi.can_add_to_service = True
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
# THEN: on_preview_click() should have been called
mocked_on_preview_click.assert_called_with()
# THEN: on_preview_click() should have been called
mocked_on_preview_click.assert_called_with()
def test_required_icons(self):
"""
Test the default icons for plugins
"""
# GIVEN: A MediaManagerItem
mmi = MediaManagerItem(None)
# WHEN: Object is created
mmi.required_icons()
# THEN: Default icons should be populated
assert mmi.has_import_icon is False, 'There should be no import icon by default'
assert mmi.has_new_icon is True, 'By default a new icon should be present'
assert mmi.has_file_icon is False, 'There should be no file icon by default'
assert mmi.has_delete_icon is True, 'By default a delete icon should be present'
assert mmi.add_to_service_item is False, 'There should be no add_to_service icon by default'
assert mmi.can_preview is True, 'There should be a preview icon by default'
assert mmi.can_make_live is True, 'There should be a make live by default'
assert mmi.can_add_to_service is True, 'There should be a add to service icon by default'
def test_required_icons(media_env):
"""
Test the default icons for plugins
"""
# GIVEN: A MediaManagerItem
mmi = MediaManagerItem(None)
# WHEN: Object is created
mmi.required_icons()
# THEN: Default icons should be populated
assert mmi.has_import_icon is False, 'There should be no import icon by default'
assert mmi.has_new_icon is True, 'By default a new icon should be present'
assert mmi.has_file_icon is False, 'There should be no file icon by default'
assert mmi.has_delete_icon is True, 'By default a delete icon should be present'
assert mmi.add_to_service_item is False, 'There should be no add_to_service icon by default'
assert mmi.can_preview is True, 'There should be a preview icon by default'
assert mmi.can_make_live is True, 'There should be a make live by default'
assert mmi.can_add_to_service is True, 'There should be a add to service icon by default'
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
def test_on_double_clicked_go_live(self, mocked_on_live_click):
"""
Test that when "Double-click to go live" is enabled that the item goes live
"""
# GIVEN: A setting to enable "Double-click to go live" and a media manager item
mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda x: x == 'advanced/double click live'
Registry().register('settings', mocked_settings)
mmi = MediaManagerItem(None)
mmi.can_preview = True
mmi.can_make_live = True
mmi.can_add_to_service = True
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
def test_on_double_clicked_go_live(mocked_on_live_click, media_env, registry):
"""
Test that when "Double-click to go live" is enabled that the item goes live
"""
# GIVEN: A setting to enable "Double-click to go live" and a media manager item
mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda x: x == 'advanced/double click live'
Registry().register('settings', mocked_settings)
mmi = MediaManagerItem(None)
mmi.can_preview = True
mmi.can_make_live = True
mmi.can_add_to_service = True
# THEN: on_live_click() should have been called
mocked_on_live_click.assert_called_with()
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked_single_click_preview(self, mocked_on_preview_click, mocked_on_live_click):
"""
Test that when "Single-click preview" is enabled then nothing happens on double-click
"""
# GIVEN: A setting to enable "Double-click to go live" and a media manager item
mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda x: x == 'advanced/single click preview'
Registry().register('settings', mocked_settings)
mmi = MediaManagerItem(None)
mmi.can_preview = True
mmi.can_make_live = True
mmi.can_add_to_service = True
# THEN: on_live_click() should have been called
mocked_on_live_click.assert_called_with()
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
# THEN: on_live_click() should have been called
assert 0 == mocked_on_live_click.call_count, 'on_live_click() should not have been called'
assert 0 == mocked_on_preview_click.call_count, 'on_preview_click() should not have been called'
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked_single_click_preview(mocked_on_preview_click, mocked_on_live_click, media_env, registry):
"""
Test that when "Single-click preview" is enabled then nothing happens on double-click
"""
# GIVEN: A setting to enable "Double-click to go live" and a media manager item
mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda x: x == 'advanced/single click preview'
Registry().register('settings', mocked_settings)
mmi = MediaManagerItem(None)
mmi.can_preview = True
mmi.can_make_live = True
mmi.can_add_to_service = True
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
# THEN: on_live_click() should have been called
assert 0 == mocked_on_live_click.call_count, 'on_live_click() should not have been called'
assert 0 == mocked_on_preview_click.call_count, 'on_preview_click() should not have been called'

View File

@ -21,7 +21,7 @@
"""
Package to test the openlp.core.lib.pluginmanager package.
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, patch
from openlp.core.state import State
@ -31,477 +31,491 @@ from openlp.core.lib.plugin import PluginStatus
from openlp.core.lib.pluginmanager import PluginManager
class TestPluginManager(TestCase):
@pytest.fixture()
def plugin_manager_env(registry, state):
mocked_main_window = MagicMock()
mocked_main_window.file_import_menu.return_value = None
mocked_main_window.file_export_menu.return_value = None
mocked_main_window.file_export_menu.return_value = None
mocked_settings_form = MagicMock()
Registry().register('service_list', MagicMock())
Registry().register('main_window', mocked_main_window)
Registry().register('settings_form', mocked_settings_form)
Registry().register('settings', MagicMock())
def test_bootstrap_initialise(settings, state):
"""
Test the PluginManager class
Test the PluginManager.bootstrap_initialise() method
"""
def setUp(self):
"""
Some pre-test setup required.
"""
self.mocked_main_window = MagicMock()
self.mocked_main_window.file_import_menu.return_value = None
self.mocked_main_window.file_export_menu.return_value = None
self.mocked_main_window.file_export_menu.return_value = None
self.mocked_settings_form = MagicMock()
Registry.create()
State().load_settings()
Registry().register('service_list', MagicMock())
Registry().register('main_window', self.mocked_main_window)
Registry().register('settings_form', self.mocked_settings_form)
Registry().register('settings', MagicMock())
def test_bootstrap_initialise(self):
"""
Test the PluginManager.bootstrap_initialise() method
"""
# GIVEN: A plugin manager with some mocked out methods
manager = PluginManager()
with patch.object(manager, 'hook_settings_tabs') as mocked_hook_settings_tabs, \
patch.object(manager, 'hook_media_manager') as mocked_hook_media_manager, \
patch.object(manager, 'hook_import_menu') as mocked_hook_import_menu, \
patch.object(manager, 'hook_export_menu') as mocked_hook_export_menu, \
patch.object(manager, 'hook_tools_menu') as mocked_hook_tools_menu, \
patch.object(manager, 'initialise_plugins') as mocked_initialise_plugins:
# WHEN: bootstrap_initialise() is called
manager.bootstrap_initialise()
manager.bootstrap_post_set_up()
# THEN: The hook methods should have been called
mocked_hook_settings_tabs.assert_called_with()
mocked_hook_media_manager.assert_called_with()
mocked_hook_import_menu.assert_called_with()
mocked_hook_export_menu.assert_called_with()
mocked_hook_tools_menu.assert_called_with()
mocked_initialise_plugins.assert_called_with()
def test_hook_media_manager_with_disabled_plugin(self):
"""
Test running the hook_media_manager() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Disabled)
State().flush_preconditions()
# WHEN: We run hook_media_manager()
plugin_manager.hook_media_manager()
# THEN: The create_media_manager_item() method should have been called
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.'
def test_hook_media_manager_with_active_plugin(self):
"""
Test running the hook_media_manager() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_media_manager()
plugin_manager.hook_media_manager()
# THEN: The create_media_manager_item() method should have been called
mocked_plugin.create_media_manager_item.assert_called_with()
def test_hook_settings_tabs_with_disabled_plugin_and_no_form(self):
"""
Test running the hook_settings_tabs() method with a disabled plugin and no form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The hook_settings_tabs() method should have been called
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.'
def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(self):
"""
Test running the hook_settings_tabs() method with a disabled plugin and a mocked form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock()
# Replace the autoloaded plugin with the version for testing in real code this would error
mocked_settings_form.plugin_manager = plugin_manager
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The create_settings_tab() method should not have been called, but the plugins lists should be the same
assert 0 == mocked_plugin.create_settings_tab.call_count, \
'The create_media_manager_item() method should not have been called.'
assert mocked_settings_form.plugin_manager.plugins == plugin_manager.plugins, \
'The plugins on the settings form should be the same as the plugins in the plugin manager'
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(self):
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock()
# Replace the autoloaded plugin with the version for testing in real code this would error
mocked_settings_form.plugin_manager = plugin_manager
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The create_media_manager_item() method should have been called with the mocked settings form
assert 1 == mocked_plugin.create_settings_tab.call_count, \
'The create_media_manager_item() method should have been called once.'
assert plugin_manager.plugins == mocked_settings_form.plugin_manager.plugins, \
'The plugins on the settings form should be the same as the plugins in the plugin manager'
def test_hook_settings_tabs_with_active_plugin_and_no_form(self):
"""
Test running the hook_settings_tabs() method with an active plugin and no settings form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The create_settings_tab() method should have been called
mocked_plugin.create_settings_tab.assert_called_with(self.mocked_settings_form)
def test_hook_import_menu_with_disabled_plugin(self):
"""
Test running the hook_import_menu() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu()
# THEN: The create_media_manager_item() method should have been called
assert 0 == mocked_plugin.add_import_menu_item.call_count, \
'The add_import_menu_item() method should not have been called.'
def test_hook_import_menu_with_active_plugin(self):
"""
Test running the hook_import_menu() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu()
# THEN: The add_import_menu_item() method should have been called
mocked_plugin.add_import_menu_item.assert_called_with(self.mocked_main_window.file_import_menu)
def test_hook_export_menu_with_disabled_plugin(self):
"""
Test running the hook_export_menu() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_export_menu()
plugin_manager.hook_export_menu()
# THEN: The add_export_menu_item() method should not have been called
assert 0 == mocked_plugin.add_export_menu_item.call_count, \
'The add_export_menu_item() method should not have been called.'
def test_hook_export_menu_with_active_plugin(self):
"""
Test running the hook_export_menu() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_export_menu()
plugin_manager.hook_export_menu()
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.add_export_menu_item.assert_called_with(self.mocked_main_window.file_export_menu)
def test_hook_upgrade_plugin_settings_with_disabled_plugin(self):
"""
Test running the hook_upgrade_plugin_settings() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
settings = Settings()
# WHEN: We run hook_upgrade_plugin_settings()
plugin_manager.hook_upgrade_plugin_settings(settings)
# THEN: The upgrade_settings() method should not have been called
assert 0 == mocked_plugin.upgrade_settings.call_count, \
'The upgrade_settings() method should not have been called.'
def test_hook_upgrade_plugin_settings_with_active_plugin(self):
"""
Test running the hook_upgrade_plugin_settings() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
settings = Settings()
# WHEN: We run hook_upgrade_plugin_settings()
plugin_manager.hook_upgrade_plugin_settings(settings)
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.upgrade_settings.assert_called_with(settings)
def test_hook_tools_menu_with_disabled_plugin(self):
"""
Test running the hook_tools_menu() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_tools_menu()
plugin_manager.hook_tools_menu()
# THEN: The add_tools_menu_item() method should have been called
assert 0 == mocked_plugin.add_tools_menu_item.call_count, \
'The add_tools_menu_item() method should not have been called.'
def test_hook_tools_menu_with_active_plugin(self):
"""
Test running the hook_tools_menu() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_tools_menu()
plugin_manager.hook_tools_menu()
# THEN: The add_tools_menu_item() method should have been called
mocked_plugin.add_tools_menu_item.assert_called_with(self.mocked_main_window.tools_menu)
def test_initialise_plugins_with_disabled_plugin(self):
"""
Test running the initialise_plugins() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run initialise_plugins()
plugin_manager.initialise_plugins()
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.'
def test_initialise_plugins_with_active_plugin(self):
"""
Test running the initialise_plugins() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run initialise_plugins()
plugin_manager.initialise_plugins()
# THEN: The is_active() and initialise() methods should have been called
mocked_plugin.is_active.assert_called_with()
mocked_plugin.initialise.assert_called_with()
def test_finalise_plugins_with_disabled_plugin(self):
"""
Test running the finalise_plugins() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
plugin_manager.finalise_plugins()
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.'
def test_finalise_plugins_with_active_plugin(self):
"""
Test running the finalise_plugins() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
plugin_manager.finalise_plugins()
# THEN: The is_active() and finalise() methods should have been called
mocked_plugin.is_active.assert_called_with()
mocked_plugin.finalise.assert_called_with()
def test_get_plugin_by_name_does_not_exist(self):
"""
Test running the get_plugin_by_name() method to find a plugin that does not exist
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.name = 'Mocked Plugin'
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
result = plugin_manager.get_plugin_by_name('Missing Plugin')
# THEN: The is_active() and finalise() methods should have been called
assert result is None, 'The result for get_plugin_by_name should be None'
def test_get_plugin_by_name_exists(self):
"""
Test running the get_plugin_by_name() method to find a plugin that exists
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.name = 'Mocked Plugin'
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
result = plugin_manager.get_plugin_by_name('Mocked Plugin')
# THEN: The is_active() and finalise() methods should have been called
assert result == mocked_plugin, 'The result for get_plugin_by_name should be the mocked plugin'
def test_new_service_created_with_disabled_plugin(self):
"""
Test running the new_service_created() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
plugin_manager.new_service_created()
# THEN: The isActive() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.new_service_created.call_count, \
'The new_service_created() method should not have been called.'
def test_new_service_created_with_active_plugin(self):
"""
Test running the new_service_created() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run new_service_created()
plugin_manager.new_service_created()
# THEN: The is_active() and finalise() methods should have been called
mocked_plugin.is_active.assert_called_with()
mocked_plugin.new_service_created.assert_called_with()
# GIVEN: A plugin manager with some mocked out methods
manager = PluginManager()
with patch.object(manager, 'hook_settings_tabs') as mocked_hook_settings_tabs, \
patch.object(manager, 'hook_media_manager') as mocked_hook_media_manager, \
patch.object(manager, 'hook_import_menu') as mocked_hook_import_menu, \
patch.object(manager, 'hook_export_menu') as mocked_hook_export_menu, \
patch.object(manager, 'hook_tools_menu') as mocked_hook_tools_menu, \
patch.object(manager, 'initialise_plugins') as mocked_initialise_plugins:
# WHEN: bootstrap_initialise() is called
manager.bootstrap_initialise()
manager.bootstrap_post_set_up()
# THEN: The hook methods should have been called
mocked_hook_settings_tabs.assert_called_with()
mocked_hook_media_manager.assert_called_with()
mocked_hook_import_menu.assert_called_with()
mocked_hook_export_menu.assert_called_with()
mocked_hook_tools_menu.assert_called_with()
mocked_initialise_plugins.assert_called_with()
def test_hook_media_manager_with_disabled_plugin(registry, state):
"""
Test running the hook_media_manager() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Disabled)
State().flush_preconditions()
# WHEN: We run hook_media_manager()
plugin_manager.hook_media_manager()
# THEN: The create_media_manager_item() method should have been called
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.'
def test_hook_media_manager_with_active_plugin(registry, state):
"""
Test running the hook_media_manager() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_media_manager()
plugin_manager.hook_media_manager()
# THEN: The create_media_manager_item() method should have been called
mocked_plugin.create_media_manager_item.assert_called_with()
def test_hook_settings_tabs_with_disabled_plugin_and_no_form(registry, state):
"""
Test running the hook_settings_tabs() method with a disabled plugin and no form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The hook_settings_tabs() method should have been called
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.'
def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(registry, state):
"""
Test running the hook_settings_tabs() method with a disabled plugin and a mocked form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock()
# Replace the autoloaded plugin with the version for testing in real code this would error
mocked_settings_form.plugin_manager = plugin_manager
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The create_settings_tab() method should not have been called, but the plugins lists should be the same
assert 0 == mocked_plugin.create_settings_tab.call_count, \
'The create_media_manager_item() method should not have been called.'
assert mocked_settings_form.plugin_manager.plugins == plugin_manager.plugins, \
'The plugins on the settings form should be the same as the plugins in the plugin manager'
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(registry, state):
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock()
# Replace the autoloaded plugin with the version for testing in real code this would error
mocked_settings_form.plugin_manager = plugin_manager
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The create_media_manager_item() method should have been called with the mocked settings form
assert 1 == mocked_plugin.create_settings_tab.call_count, \
'The create_media_manager_item() method should have been called once.'
assert plugin_manager.plugins == mocked_settings_form.plugin_manager.plugins, \
'The plugins on the settings form should be the same as the plugins in the plugin manager'
def test_hook_settings_tabs_with_active_plugin_and_no_form(plugin_manager_env):
"""
Test running the hook_settings_tabs() method with an active plugin and no settings form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The create_settings_tab() method should have been called
mocked_plugin.create_settings_tab.assert_called_with(Registry().get('settings_form'))
def test_hook_import_menu_with_disabled_plugin(registry, state):
"""
Test running the hook_import_menu() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu()
# THEN: The create_media_manager_item() method should have been called
assert 0 == mocked_plugin.add_import_menu_item.call_count, \
'The add_import_menu_item() method should not have been called.'
def test_hook_import_menu_with_active_plugin(plugin_manager_env):
"""
Test running the hook_import_menu() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu()
# THEN: The add_import_menu_item() method should have been called
mocked_plugin.add_import_menu_item.assert_called_with(Registry().get('main_window').file_import_menu)
def test_hook_export_menu_with_disabled_plugin(registry, state):
"""
Test running the hook_export_menu() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_export_menu()
plugin_manager.hook_export_menu()
# THEN: The add_export_menu_item() method should not have been called
assert 0 == mocked_plugin.add_export_menu_item.call_count, \
'The add_export_menu_item() method should not have been called.'
def test_hook_export_menu_with_active_plugin(plugin_manager_env):
"""
Test running the hook_export_menu() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_export_menu()
plugin_manager.hook_export_menu()
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.add_export_menu_item.assert_called_with(Registry().get('main_window').file_export_menu)
def test_hook_upgrade_plugin_settings_with_disabled_plugin(registry, state):
"""
Test running the hook_upgrade_plugin_settings() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
settings = Settings()
# WHEN: We run hook_upgrade_plugin_settings()
plugin_manager.hook_upgrade_plugin_settings(settings)
# THEN: The upgrade_settings() method should not have been called
assert 0 == mocked_plugin.upgrade_settings.call_count, \
'The upgrade_settings() method should not have been called.'
def test_hook_upgrade_plugin_settings_with_active_plugin(registry, state):
"""
Test running the hook_upgrade_plugin_settings() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
settings = Settings()
# WHEN: We run hook_upgrade_plugin_settings()
plugin_manager.hook_upgrade_plugin_settings(settings)
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.upgrade_settings.assert_called_with(settings)
def test_hook_tools_menu_with_disabled_plugin(registry, state):
"""
Test running the hook_tools_menu() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_tools_menu()
plugin_manager.hook_tools_menu()
# THEN: The add_tools_menu_item() method should have been called
assert 0 == mocked_plugin.add_tools_menu_item.call_count, \
'The add_tools_menu_item() method should not have been called.'
def test_hook_tools_menu_with_active_plugin(plugin_manager_env):
"""
Test running the hook_tools_menu() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run hook_tools_menu()
plugin_manager.hook_tools_menu()
# THEN: The add_tools_menu_item() method should have been called
mocked_plugin.add_tools_menu_item.assert_called_with(Registry().get('main_window').tools_menu)
def test_initialise_plugins_with_disabled_plugin(registry, state):
"""
Test running the initialise_plugins() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run initialise_plugins()
plugin_manager.initialise_plugins()
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.'
def test_initialise_plugins_with_active_plugin(registry, state):
"""
Test running the initialise_plugins() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run initialise_plugins()
plugin_manager.initialise_plugins()
# THEN: The is_active() and initialise() methods should have been called
mocked_plugin.is_active.assert_called_with()
mocked_plugin.initialise.assert_called_with()
def test_finalise_plugins_with_disabled_plugin(registry, state):
"""
Test running the finalise_plugins() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
plugin_manager.finalise_plugins()
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.'
def test_finalise_plugins_with_active_plugin(registry, state):
"""
Test running the finalise_plugins() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
plugin_manager.finalise_plugins()
# THEN: The is_active() and finalise() methods should have been called
mocked_plugin.is_active.assert_called_with()
mocked_plugin.finalise.assert_called_with()
def test_get_plugin_by_name_does_not_exist(registry, state):
"""
Test running the get_plugin_by_name() method to find a plugin that does not exist
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.name = 'Mocked Plugin'
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
result = plugin_manager.get_plugin_by_name('Missing Plugin')
# THEN: The is_active() and finalise() methods should have been called
assert result is None, 'The result for get_plugin_by_name should be None'
def test_get_plugin_by_name_exists(registry, state):
"""
Test running the get_plugin_by_name() method to find a plugin that exists
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.name = 'Mocked Plugin'
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
result = plugin_manager.get_plugin_by_name('Mocked Plugin')
# THEN: The is_active() and finalise() methods should have been called
assert result == mocked_plugin, 'The result for get_plugin_by_name should be the mocked plugin'
def test_new_service_created_with_disabled_plugin(registry, state):
"""
Test running the new_service_created() method with a disabled plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run finalise_plugins()
plugin_manager.new_service_created()
# THEN: The isActive() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.new_service_created.call_count, \
'The new_service_created() method should not have been called.'
def test_new_service_created_with_active_plugin(registry, state):
"""
Test running the new_service_created() method with an active plugin
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# WHEN: We run new_service_created()
plugin_manager.new_service_created()
# THEN: The is_active() and finalise() methods should have been called
mocked_plugin.is_active.assert_called_with()
mocked_plugin.new_service_created.assert_called_with()

View File

@ -22,18 +22,16 @@
Package to test the openlp.core.lib package.
"""
import os
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import Mock, MagicMock, patch
from openlp.core.state import State
from openlp.core.common import ThemeLevel, md5_hash
from openlp.core.common.enum import ServiceItemType
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib.formattingtags import FormattingTags
from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem
from tests.helpers.testmixin import TestMixin
from tests.utils import convert_file_service_item
from tests.utils.constants import RESOURCE_PATH
@ -63,407 +61,411 @@ RENDERED_VERSE = 'The Lord said to <span style="-webkit-text-fill-color:red">Noa
FOOTER = ['Arky Arky (Unknown)', 'Public Domain', 'CCLI 123456']
TEST_PATH = RESOURCE_PATH / 'service'
__default_settings__ = {
'songs/enable chords': True,
}
@pytest.fixture()
def state_env(state):
State().add_service("media", 0)
State().update_pre_conditions("media", True)
State().flush_preconditions()
class TestServiceItem(TestCase, TestMixin):
@pytest.fixture()
def service_item_env(state):
# Mock the renderer and its format_slide method
mocked_renderer = MagicMock()
def setUp(self):
"""
Set up the Registry
"""
self.build_settings()
self.setting.extend_default_settings(__default_settings__)
self.setting.setValue('songs/chord notation', 'english')
Registry.create()
Registry().register('settings', self.setting)
# Mock the renderer and its format_slide method
mocked_renderer = MagicMock()
def side_effect_return_arg(arg1, arg2):
return [arg1]
def side_effect_return_arg(arg1, arg2):
return [arg1]
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
mocked_renderer.format_slide = mocked_slide_formater
Registry().register('renderer', mocked_renderer)
Registry().register('image_manager', MagicMock())
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
mocked_renderer.format_slide = mocked_slide_formater
Registry().register('renderer', mocked_renderer)
Registry().register('image_manager', MagicMock())
def tearDown(self):
"""
Clean up
"""
self.destroy_settings()
def test_service_item_basic(self):
"""
Test the Service Item - basic test
"""
# GIVEN: A new service item
def test_service_item_basic():
"""
Test the Service Item - basic test
"""
# GIVEN: A new service item
# WHEN: A service item is created (without a plugin)
service_item = ServiceItem(None)
# WHEN: A service item is created (without a plugin)
service_item = ServiceItem(None)
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert service_item.missing_frames() is True, 'There should not be any frames in the service item'
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert service_item.missing_frames() is True, 'There should not be any frames in the service item'
def test_service_item_load_custom_from_service(self):
"""
Test the Service Item - adding a custom slide from a saved service
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
FormattingTags.load_tags()
# WHEN: We add a custom from a saved serviceand set the media state
line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj')
State().add_service("media", 0)
State().update_pre_conditions("media", True)
State().flush_preconditions()
service_item.set_from_service(line)
def test_service_item_load_custom_from_service(state_env, settings, service_item_env):
"""
Test the Service Item - adding a custom slide from a saved service
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
FormattingTags.load_tags()
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert len(service_item.get_frames()) == 2, 'The service item should have 2 display frames'
assert len(service_item.capabilities) == 5, 'There should be 5 default custom item capabilities'
# WHEN: We add a custom from a saved serviceand set the media state
line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj')
State().add_service("media", 0)
State().update_pre_conditions("media", True)
State().flush_preconditions()
service_item.set_from_service(line)
# THEN: The frames should also be valid
assert 'Test Custom' == service_item.get_display_title(), 'The title should be "Test Custom"'
assert 'Slide 1' == service_item.get_frames()[0]['text']
assert 'Slide 2' == service_item.get_rendered_frame(1)
assert 'Slide 1' == service_item.get_frame_title(0), '"Slide 1" has been returned as the title'
assert 'Slide 2' == service_item.get_frame_title(1), '"Slide 2" has been returned as the title'
assert '' == service_item.get_frame_title(2), 'Blank has been returned as the title of slide 3'
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert len(service_item.get_frames()) == 2, 'The service item should have 2 display frames'
assert len(service_item.capabilities) == 5, 'There should be 5 default custom item capabilities'
def test_service_item_load_image_from_service(self):
"""
Test the Service Item - adding an image from a saved service
"""
# GIVEN: A new service item and a mocked add icon function
image_name = 'image_1.jpg'
test_file = TEST_PATH / image_name
frame_array = {'path': test_file, 'title': image_name}
# THEN: The frames should also be valid
assert 'Test Custom' == service_item.get_display_title(), 'The title should be "Test Custom"'
assert 'Slide 1' == service_item.get_frames()[0]['text']
assert 'Slide 2' == service_item.get_rendered_frame(1)
assert 'Slide 1' == service_item.get_frame_title(0), '"Slide 1" has been returned as the title'
assert 'Slide 2' == service_item.get_frame_title(1), '"Slide 2" has been returned as the title'
assert '' == service_item.get_frame_title(2), 'Blank has been returned as the title of slide 3'
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
# WHEN: adding an image from a saved Service and mocked exists
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_1.osj')
with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists,\
patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \
mocked_get_section_data_path:
mocked_exists.return_value = True
mocked_get_section_data_path.return_value = Path('/path/')
service_item.set_from_service(line, TEST_PATH)
def test_service_item_load_image_from_service(state_env, settings):
"""
Test the Service Item - adding an image from a saved service
"""
# GIVEN: A new service item and a mocked add icon function
image_name = 'image_1.jpg'
test_file = TEST_PATH / image_name
frame_array = {'path': test_file, 'title': image_name}
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert test_file == service_item.get_rendered_frame(0), 'The first frame should match the path to the image'
assert frame_array == service_item.get_frames()[0], 'The return should match frame array1'
assert test_file == service_item.get_frame_path(0), \
'The frame path should match the full path to the image'
assert image_name == service_item.get_frame_title(0), 'The frame title should match the image name'
assert image_name == service_item.get_display_title(), 'The display title should match the first image name'
assert service_item.is_image() is True, 'This service item should be of an "image" type'
assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, \
'This service item should be able to be Maintained'
assert service_item.is_capable(ItemCapabilities.CanPreview) is True, \
'This service item should be able to be be Previewed'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, \
'This service item should be able to be run in a can be made to Loop'
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
'This service item should be able to have new items added to it'
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
@patch('openlp.core.lib.serviceitem.os.path.exists')
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
def test_service_item_load_image_from_local_service(self, mocked_get_section_data_path, mocked_exists):
"""
Test the Service Item - adding an image from a saved local service
"""
# GIVEN: A new service item and a mocked add icon function
mocked_get_section_data_path.return_value = Path('/path')
# WHEN: adding an image from a saved Service and mocked exists
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_1.osj')
with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists,\
patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \
mocked_get_section_data_path:
mocked_exists.return_value = True
image_name1 = 'image_1.jpg'
image_name2 = 'image_2.jpg'
test_file1 = os.path.join('/home', 'openlp', image_name1)
test_file2 = os.path.join('/home', 'openlp', image_name2)
frame_array1 = {'path': test_file1, 'title': image_name1}
frame_array2 = {'path': test_file2, 'title': image_name2}
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
service_item2 = ServiceItem(None)
service_item2.add_icon = MagicMock()
mocked_get_section_data_path.return_value = Path('/path/')
service_item.set_from_service(line, TEST_PATH)
# WHEN: adding an image from a saved Service and mocked exists
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj')
line2 = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj', 1)
service_item2.set_from_service(line2)
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert test_file == service_item.get_rendered_frame(0), 'The first frame should match the path to the image'
assert frame_array == service_item.get_frames()[0], 'The return should match frame array1'
assert test_file == service_item.get_frame_path(0), \
'The frame path should match the full path to the image'
assert image_name == service_item.get_frame_title(0), 'The frame title should match the image name'
assert image_name == service_item.get_display_title(), 'The display title should match the first image name'
assert service_item.is_image() is True, 'This service item should be of an "image" type'
assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, \
'This service item should be able to be Maintained'
assert service_item.is_capable(ItemCapabilities.CanPreview) is True, \
'This service item should be able to be be Previewed'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, \
'This service item should be able to be run in a can be made to Loop'
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
'This service item should be able to have new items added to it'
@patch('openlp.core.lib.serviceitem.os.path.exists')
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
def test_service_item_load_image_from_local_service(mocked_get_section_data_path, mocked_exists, settings, state_env):
"""
Test the Service Item - adding an image from a saved local service
"""
# GIVEN: A new service item and a mocked add icon function
mocked_get_section_data_path.return_value = Path('/path')
mocked_exists.return_value = True
image_name1 = 'image_1.jpg'
image_name2 = 'image_2.jpg'
test_file1 = os.path.join('/home', 'openlp', image_name1)
test_file2 = os.path.join('/home', 'openlp', image_name2)
frame_array1 = {'path': test_file1, 'title': image_name1}
frame_array2 = {'path': test_file2, 'title': image_name2}
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
service_item2 = ServiceItem(None)
service_item2.add_icon = MagicMock()
# WHEN: adding an image from a saved Service and mocked exists
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj')
line2 = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj', 1)
service_item2.set_from_service(line2)
service_item.set_from_service(line)
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The first service item should be valid'
assert service_item2.is_valid is True, 'The second service item should be valid'
# These test will fail on windows due to the difference in folder seperators
if os.name != 'nt':
assert test_file1 == service_item.get_rendered_frame(0), \
'The first frame should match the path to the image'
assert test_file2 == service_item2.get_rendered_frame(0), \
'The Second frame should match the path to the image'
assert frame_array1 == service_item.get_frames()[0], 'The return should match the frame array1'
assert frame_array2 == service_item2.get_frames()[0], 'The return should match the frame array2'
assert test_file1 == str(service_item.get_frame_path(0)), \
'The frame path should match the full path to the image'
assert test_file2 == str(service_item2.get_frame_path(0)), \
'The frame path should match the full path to the image'
assert image_name1 == service_item.get_frame_title(0), 'The 1st frame title should match the image name'
assert image_name2 == service_item2.get_frame_title(0), 'The 2nd frame title should match the image name'
assert service_item.name == service_item.title.lower(), \
'The plugin name should match the display title, as there are > 1 Images'
assert service_item.is_image() is True, 'This service item should be of an "image" type'
assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, \
'This service item should be able to be Maintained'
assert service_item.is_capable(ItemCapabilities.CanPreview) is True, \
'This service item should be able to be be Previewed'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, \
'This service item should be able to be run in a can be made to Loop'
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
'This service item should be able to have new items added to it'
def test_add_from_command_for_a_presentation():
"""
Test the Service Item - adding a presentation
"""
# GIVEN: A service item, a mocked icon and presentation data
service_item = ServiceItem(None)
presentation_name = 'test.pptx'
image = MagicMock()
display_title = 'DisplayTitle'
notes = 'Note1\nNote2\n'
frame = {'title': presentation_name, 'image': image, 'path': TEST_PATH,
'display_title': display_title, 'notes': notes, 'thumbnail': image}
# WHEN: adding presentation to service_item
service_item.add_from_command(TEST_PATH, presentation_name, image, display_title, notes)
# THEN: verify that it is setup as a Command and that the frame data matches
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
assert service_item.get_frames()[0] == frame, 'Frames should match'
def test_add_from_command_without_display_title_and_notes():
"""
Test the Service Item - add from command, but not presentation
"""
# GIVEN: A new service item, a mocked icon and image data
service_item = ServiceItem(None)
image_name = 'test.img'
image = MagicMock()
frame = {'title': image_name, 'image': image, 'path': TEST_PATH,
'display_title': None, 'notes': None, 'thumbnail': image}
# WHEN: adding image to service_item
service_item.add_from_command(TEST_PATH, image_name, image)
# THEN: verify that it is setup as a Command and that the frame data matches
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
assert service_item.get_frames()[0] == frame, 'Frames should match'
@patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager')
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
def test_add_from_command_for_a_presentation_thumb(mocked_get_section_data_path, mocked_image_manager):
"""
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
"""
# GIVEN: A service item, a mocked AppLocation and presentation data
mocked_get_section_data_path.return_value = Path('mocked') / 'section' / 'path'
service_item = ServiceItem(None)
service_item.add_capability(ItemCapabilities.HasThumbnails)
service_item.has_original_files = False
service_item.name = 'presentations'
presentation_name = 'test.pptx'
thumb = Path('tmp') / 'test' / 'thumb.png'
display_title = 'DisplayTitle'
notes = 'Note1\nNote2\n'
expected_thumb_path = Path('mocked') / 'section' / 'path' / 'thumbnails' / \
md5_hash(str(TEST_PATH / presentation_name).encode('utf8')) / 'thumb.png'
frame = {'title': presentation_name, 'image': str(expected_thumb_path), 'path': str(TEST_PATH),
'display_title': display_title, 'notes': notes, 'thumbnail': str(expected_thumb_path)}
# WHEN: adding presentation to service_item
service_item.add_from_command(str(TEST_PATH), presentation_name, thumb, display_title, notes)
# THEN: verify that it is setup as a Command and that the frame data matches
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
assert service_item.get_frames()[0] == frame, 'Frames should match'
# assert 1 == mocked_image_manager.add_image.call_count, 'image_manager should be used'
def test_service_item_load_optical_media_from_service(state_env):
"""
Test the Service Item - load an optical media item
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
# WHEN: We load a serviceitem with optical media
line = convert_file_service_item(TEST_PATH, 'serviceitem-dvd.osj')
with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists:
mocked_exists.return_value = True
service_item.set_from_service(line)
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The first service item should be valid'
assert service_item2.is_valid is True, 'The second service item should be valid'
# These test will fail on windows due to the difference in folder seperators
if os.name != 'nt':
assert test_file1 == service_item.get_rendered_frame(0), \
'The first frame should match the path to the image'
assert test_file2 == service_item2.get_rendered_frame(0), \
'The Second frame should match the path to the image'
assert frame_array1 == service_item.get_frames()[0], 'The return should match the frame array1'
assert frame_array2 == service_item2.get_frames()[0], 'The return should match the frame array2'
assert test_file1 == str(service_item.get_frame_path(0)), \
'The frame path should match the full path to the image'
assert test_file2 == str(service_item2.get_frame_path(0)), \
'The frame path should match the full path to the image'
assert image_name1 == service_item.get_frame_title(0), 'The 1st frame title should match the image name'
assert image_name2 == service_item2.get_frame_title(0), 'The 2nd frame title should match the image name'
assert service_item.name == service_item.title.lower(), \
'The plugin name should match the display title, as there are > 1 Images'
assert service_item.is_image() is True, 'This service item should be of an "image" type'
assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, \
'This service item should be able to be Maintained'
assert service_item.is_capable(ItemCapabilities.CanPreview) is True, \
'This service item should be able to be be Previewed'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, \
'This service item should be able to be run in a can be made to Loop'
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
'This service item should be able to have new items added to it'
# THEN: We should get back a valid service item with optical media info
assert service_item.is_valid is True, 'The service item should be valid'
assert service_item.is_capable(ItemCapabilities.IsOptical) is True, 'The item should be Optical'
assert service_item.start_time == 654.375, 'Start time should be 654.375'
assert service_item.end_time == 672.069, 'End time should be 672.069'
assert service_item.media_length == 17.694, 'Media length should be 17.694'
def test_add_from_command_for_a_presentation(self):
"""
Test the Service Item - adding a presentation
"""
# GIVEN: A service item, a mocked icon and presentation data
service_item = ServiceItem(None)
presentation_name = 'test.pptx'
image = MagicMock()
display_title = 'DisplayTitle'
notes = 'Note1\nNote2\n'
frame = {'title': presentation_name, 'image': image, 'path': TEST_PATH,
'display_title': display_title, 'notes': notes, 'thumbnail': image}
# WHEN: adding presentation to service_item
service_item.add_from_command(TEST_PATH, presentation_name, image, display_title, notes)
def test_service_item_load_song_and_audio_from_service(state_env, settings, service_item_env):
"""
Test the Service Item - adding a song slide from a saved service
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
FormattingTags.load_tags()
# THEN: verify that it is setup as a Command and that the frame data matches
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
assert service_item.get_frames()[0] == frame, 'Frames should match'
# WHEN: We add a custom from a saved service
line = convert_file_service_item(TEST_PATH, 'serviceitem-song-linked-audio.osj')
service_item.set_from_service(line, Path('/test/'))
def test_add_from_command_without_display_title_and_notes(self):
"""
Test the Service Item - add from command, but not presentation
"""
# GIVEN: A new service item, a mocked icon and image data
service_item = ServiceItem(None)
image_name = 'test.img'
image = MagicMock()
frame = {'title': image_name, 'image': image, 'path': TEST_PATH,
'display_title': None, 'notes': None, 'thumbnail': image}
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert len(service_item.display_slides) == 6, 'The service item should have 6 display slides'
assert len(service_item.capabilities) == 7, 'There should be 7 default custom item capabilities'
assert 'Amazing Grace' == service_item.get_display_title(), 'The title should be "Amazing Grace"'
assert CLEANED_VERSE[:-1] == service_item.get_frames()[0]['text'], \
'The returned text matches the input, except the last line feed'
assert 'Amazing Grace! how sweet the s' == service_item.get_frame_title(0), \
'"Amazing Grace! how sweet the s" has been returned as the title'
assert 'Twas grace that taught my hea' == service_item.get_frame_title(1), \
'"Twas grace that taught my hea" has been returned as the title'
assert Path('/test/amazing_grace.mp3') == service_item.background_audio[0], \
'"/test/amazing_grace.mp3" should be in the background_audio list'
# WHEN: adding image to service_item
service_item.add_from_command(TEST_PATH, image_name, image)
# THEN: verify that it is setup as a Command and that the frame data matches
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
assert service_item.get_frames()[0] == frame, 'Frames should match'
def test_service_item_get_theme_data_global_level(settings):
"""
Test the service item - get theme data when set to global theme level
"""
# GIVEN: A service item with a theme and theme level set to global
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Global)
@patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager')
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
def test_add_from_command_for_a_presentation_thumb(self, mocked_get_section_data_path, mocked_image_manager):
"""
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
"""
# GIVEN: A service item, a mocked AppLocation and presentation data
mocked_get_section_data_path.return_value = Path('mocked') / 'section' / 'path'
service_item = ServiceItem(None)
service_item.add_capability(ItemCapabilities.HasThumbnails)
service_item.has_original_files = False
service_item.name = 'presentations'
presentation_name = 'test.pptx'
thumb = Path('tmp') / 'test' / 'thumb.png'
display_title = 'DisplayTitle'
notes = 'Note1\nNote2\n'
expected_thumb_path = Path('mocked') / 'section' / 'path' / 'thumbnails' / \
md5_hash(str(TEST_PATH / presentation_name).encode('utf8')) / 'thumb.png'
frame = {'title': presentation_name, 'image': str(expected_thumb_path), 'path': str(TEST_PATH),
'display_title': display_title, 'notes': notes, 'thumbnail': str(expected_thumb_path)}
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# WHEN: adding presentation to service_item
service_item.add_from_command(str(TEST_PATH), presentation_name, thumb, display_title, notes)
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme
# THEN: verify that it is setup as a Command and that the frame data matches
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
assert service_item.get_frames()[0] == frame, 'Frames should match'
# assert 1 == mocked_image_manager.add_image.call_count, 'image_manager should be used'
def test_service_item_load_optical_media_from_service(self):
"""
Test the Service Item - load an optical media item
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
def test_service_item_get_theme_data_service_level_service_undefined(settings):
"""
Test the service item - get theme data when set to service theme level
"""
# GIVEN: A service item with a theme and theme level set to service
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Service)
# WHEN: We load a serviceitem with optical media
line = convert_file_service_item(TEST_PATH, 'serviceitem-dvd.osj')
with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists:
mocked_exists.return_value = True
service_item.set_from_service(line)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: We should get back a valid service item with optical media info
assert service_item.is_valid is True, 'The service item should be valid'
assert service_item.is_capable(ItemCapabilities.IsOptical) is True, 'The item should be Optical'
assert service_item.start_time == 654.375, 'Start time should be 654.375'
assert service_item.end_time == 672.069, 'End time should be 672.069'
assert service_item.media_length == 17.694, 'Media length should be 17.694'
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme
def test_service_item_load_song_and_audio_from_service(self):
"""
Test the Service Item - adding a song slide from a saved service
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
FormattingTags.load_tags()
# WHEN: We add a custom from a saved service
line = convert_file_service_item(TEST_PATH, 'serviceitem-song-linked-audio.osj')
service_item.set_from_service(line, Path('/test/'))
def test_service_item_get_theme_data_service_level_service_defined(settings):
"""
Test the service item - get theme data when set to service theme level
"""
# GIVEN: A service item with a theme and theme level set to service
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
service_item.from_service = True
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Service)
# THEN: We should get back a valid service item
assert service_item.is_valid is True, 'The new service item should be valid'
assert len(service_item.display_slides) == 6, 'The service item should have 6 display slides'
assert len(service_item.capabilities) == 7, 'There should be 7 default custom item capabilities'
assert 'Amazing Grace' == service_item.get_display_title(), 'The title should be "Amazing Grace"'
assert CLEANED_VERSE[:-1] == service_item.get_frames()[0]['text'], \
'The returned text matches the input, except the last line feed'
assert 'Amazing Grace! how sweet the s' == service_item.get_frame_title(0), \
'"Amazing Grace! how sweet the s" has been returned as the title'
assert 'Twas grace that taught my hea' == service_item.get_frame_title(1), \
'"Twas grace that taught my hea" has been returned as the title'
assert Path('/test/amazing_grace.mp3') == service_item.background_audio[0], \
'"/test/amazing_grace.mp3" should be in the background_audio list'
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
def test_service_item_get_theme_data_global_level(self):
"""
Test the service item - get theme data when set to global theme level
"""
# GIVEN: A service item with a theme and theme level set to global
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Global)
# THEN: theme should be the service theme
assert theme == settings.value('servicemanager/service theme')
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme
def test_service_item_get_theme_data_song_level(settings):
"""
Test the service item - get theme data when set to song theme level
"""
# GIVEN: A service item with a theme and theme level set to song
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Song)
def test_service_item_get_theme_data_service_level_service_undefined(self):
"""
Test the service item - get theme data when set to service theme level
"""
# GIVEN: A service item with a theme and theme level set to service
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Service)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the song theme
assert theme == service_item.theme
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme
def test_service_item_get_theme_data_service_level_service_defined(self):
"""
Test the service item - get theme data when set to service theme level
"""
# GIVEN: A service item with a theme and theme level set to service
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
service_item.from_service = True
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Service)
def test_service_item_get_theme_data_song_level_service_fallback(settings):
"""
Test the service item - get theme data when set to song theme level
but the song theme doesn't exist
"""
# GIVEN: A service item with a theme and theme level set to song
service_item = ServiceItem(None)
service_item.from_service = True
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Song)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the service theme
assert theme == Settings().value('servicemanager/service theme')
# THEN: theme should be the serice theme
assert theme == settings.value('servicemanager/service theme')
def test_service_item_get_theme_data_song_level(self):
"""
Test the service item - get theme data when set to song theme level
"""
# GIVEN: A service item with a theme and theme level set to song
service_item = ServiceItem(None)
service_item.theme = 'song_theme'
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Song)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
def test_service_item_get_theme_data_song_level_global_fallback(settings):
"""
Test the service item - get theme data when set to song theme level
but the song and service theme don't exist
"""
# GIVEN: A service item with a theme and theme level set to song
service_item = ServiceItem(None)
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Song)
# THEN: theme should be the song theme
assert theme == service_item.theme
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
def test_service_item_get_theme_data_song_level_service_fallback(self):
"""
Test the service item - get theme data when set to song theme level
but the song theme doesn't exist
"""
# GIVEN: A service item with a theme and theme level set to song
service_item = ServiceItem(None)
service_item.from_service = True
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Song)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the serice theme
assert theme == Settings().value('servicemanager/service theme')
def test_service_item_get_theme_data_song_level_global_fallback(self):
"""
Test the service item - get theme data when set to song theme level
but the song and service theme don't exist
"""
# GIVEN: A service item with a theme and theme level set to song
service_item = ServiceItem(None)
mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Song)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme

View File

@ -22,319 +22,324 @@
Package to test the openlp.core.lib.theme package.
"""
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, TransitionType, TransitionSpeed, Theme
class ThemeEnumerationTypes(TestCase):
def test_background_type_to_string():
"""
Test the theme enum methods.
Test the to_string method of :class:`BackgroundType`
"""
def test_background_type_to_string(self):
"""
Test the to_string method of :class:`BackgroundType`
"""
# GIVEN: The BackgroundType members
background_type_solid = BackgroundType.Solid
background_type_gradient = BackgroundType.Gradient
background_type_image = BackgroundType.Image
background_type_transparent = BackgroundType.Transparent
background_type_video = BackgroundType.Video
background_type_stream = BackgroundType.Stream
# GIVEN: The BackgroundType members
background_type_solid = BackgroundType.Solid
background_type_gradient = BackgroundType.Gradient
background_type_image = BackgroundType.Image
background_type_transparent = BackgroundType.Transparent
background_type_video = BackgroundType.Video
background_type_stream = BackgroundType.Stream
# WHEN: Calling BackgroundType.to_string
# THEN: The string equivalents should be returned
assert BackgroundType.to_string(background_type_solid) == 'solid'
assert BackgroundType.to_string(background_type_gradient) == 'gradient'
assert BackgroundType.to_string(background_type_image) == 'image'
assert BackgroundType.to_string(background_type_transparent) == 'transparent'
assert BackgroundType.to_string(background_type_video) == 'video'
assert BackgroundType.to_string(background_type_stream) == 'stream'
def test_background_type_from_string(self):
"""
Test the from_string method of :class:`BackgroundType`
"""
# GIVEN: The BackgroundType strings
background_type_solid = 'solid'
background_type_gradient = 'gradient'
background_type_image = 'image'
background_type_transparent = 'transparent'
background_type_video = 'video'
background_type_stream = 'stream'
# WHEN: Calling BackgroundType.from_string
# THEN: The enum equivalents should be returned
assert BackgroundType.from_string(background_type_solid) == BackgroundType.Solid
assert BackgroundType.from_string(background_type_gradient) == BackgroundType.Gradient
assert BackgroundType.from_string(background_type_image) == BackgroundType.Image
assert BackgroundType.from_string(background_type_transparent) == BackgroundType.Transparent
assert BackgroundType.from_string(background_type_video) == BackgroundType.Video
assert BackgroundType.from_string(background_type_stream) == BackgroundType.Stream
def test_background_gradient_type_to_string(self):
"""
Test the to_string method of :class:`BackgroundGradientType`
"""
# GIVEN: The BackgroundGradientType member
background_gradient_horizontal = BackgroundGradientType.Horizontal
background_gradient_vertical = BackgroundGradientType.Vertical
background_gradient_circular = BackgroundGradientType.Circular
background_gradient_left_top = BackgroundGradientType.LeftTop
background_gradient_left_bottom = BackgroundGradientType.LeftBottom
# WHEN: Calling BackgroundGradientType.to_string
# THEN: The string equivalents should be returned
assert BackgroundGradientType.to_string(background_gradient_horizontal) == 'horizontal'
assert BackgroundGradientType.to_string(background_gradient_vertical) == 'vertical'
assert BackgroundGradientType.to_string(background_gradient_circular) == 'circular'
assert BackgroundGradientType.to_string(background_gradient_left_top) == 'leftTop'
assert BackgroundGradientType.to_string(background_gradient_left_bottom) == 'leftBottom'
def test_background_gradient_type_from_string(self):
"""
Test the from_string method of :class:`BackgroundGradientType`
"""
# GIVEN: The BackgroundGradientType strings
background_gradient_horizontal = 'horizontal'
background_gradient_vertical = 'vertical'
background_gradient_circular = 'circular'
background_gradient_left_top = 'leftTop'
background_gradient_left_bottom = 'leftBottom'
# WHEN: Calling BackgroundGradientType.from_string
# THEN: The enum equivalents should be returned
assert BackgroundGradientType.from_string(background_gradient_horizontal) == BackgroundGradientType.Horizontal
assert BackgroundGradientType.from_string(background_gradient_vertical) == BackgroundGradientType.Vertical
assert BackgroundGradientType.from_string(background_gradient_circular) == BackgroundGradientType.Circular
assert BackgroundGradientType.from_string(background_gradient_left_top) == BackgroundGradientType.LeftTop
assert BackgroundGradientType.from_string(background_gradient_left_bottom) == BackgroundGradientType.LeftBottom
def test_transition_type_to_string(self):
"""
Test the to_string method of :class:`TransitionType`
"""
# GIVEN: The TransitionType member
transition_type_fade = TransitionType.Fade
transition_type_slide = TransitionType.Slide
transition_type_convex = TransitionType.Convex
transition_type_concave = TransitionType.Concave
transition_type_zoom = TransitionType.Zoom
# WHEN: Calling TransitionType.to_string
# THEN: The string equivalents should be returned
assert TransitionType.to_string(transition_type_fade) == 'fade'
assert TransitionType.to_string(transition_type_slide) == 'slide'
assert TransitionType.to_string(transition_type_convex) == 'convex'
assert TransitionType.to_string(transition_type_concave) == 'concave'
assert TransitionType.to_string(transition_type_zoom) == 'zoom'
def test_transition_type_from_string(self):
"""
Test the from_string method of :class:`TransitionType`
"""
# GIVEN: The TransitionType strings
transition_type_fade = 'fade'
transition_type_slide = 'slide'
transition_type_convex = 'convex'
transition_type_concave = 'concave'
transition_type_zoom = 'zoom'
# WHEN: Calling TransitionType.from_string
# THEN: The enum equivalents should be returned
assert TransitionType.from_string(transition_type_fade) == TransitionType.Fade
assert TransitionType.from_string(transition_type_slide) == TransitionType.Slide
assert TransitionType.from_string(transition_type_convex) == TransitionType.Convex
assert TransitionType.from_string(transition_type_concave) == TransitionType.Concave
assert TransitionType.from_string(transition_type_zoom) == TransitionType.Zoom
def test_transition_speed_to_string(self):
"""
Test the to_string method of :class:`TransitionSpeed`
"""
# GIVEN: The TransitionSpeed member
transition_speed_normal = TransitionSpeed.Normal
transition_speed_fast = TransitionSpeed.Fast
transition_speed_slow = TransitionSpeed.Slow
# WHEN: Calling TransitionSpeed.to_string
# THEN: The string equivalents should be returned
assert TransitionSpeed.to_string(transition_speed_normal) == 'normal'
assert TransitionSpeed.to_string(transition_speed_fast) == 'fast'
assert TransitionSpeed.to_string(transition_speed_slow) == 'slow'
def test_transition_speed_from_string(self):
"""
Test the from_string method of :class:`TransitionSpeed`
"""
# GIVEN: The TransitionSpeed strings
transition_speed_normal = 'normal'
transition_speed_fast = 'fast'
transition_speed_slow = 'slow'
# WHEN: Calling TransitionSpeed.from_string
# THEN: The enum equivalents should be returned
assert TransitionSpeed.from_string(transition_speed_normal) == TransitionSpeed.Normal
assert TransitionSpeed.from_string(transition_speed_fast) == TransitionSpeed.Fast
assert TransitionSpeed.from_string(transition_speed_slow) == TransitionSpeed.Slow
# WHEN: Calling BackgroundType.to_string
# THEN: The string equivalents should be returned
assert BackgroundType.to_string(background_type_solid) == 'solid'
assert BackgroundType.to_string(background_type_gradient) == 'gradient'
assert BackgroundType.to_string(background_type_image) == 'image'
assert BackgroundType.to_string(background_type_transparent) == 'transparent'
assert BackgroundType.to_string(background_type_video) == 'video'
assert BackgroundType.to_string(background_type_stream) == 'stream'
class TestTheme(TestCase):
def test_background_type_from_string():
"""
Test the Theme class
Test the from_string method of :class:`BackgroundType`
"""
def test_new_theme(self):
"""
Test the Theme constructor
"""
# GIVEN: The Theme class
# WHEN: A theme object is created
default_theme = Theme()
# GIVEN: The BackgroundType strings
background_type_solid = 'solid'
background_type_gradient = 'gradient'
background_type_image = 'image'
background_type_transparent = 'transparent'
background_type_video = 'video'
background_type_stream = 'stream'
# THEN: The default values should be correct
self.check_theme(default_theme)
# WHEN: Calling BackgroundType.from_string
# THEN: The enum equivalents should be returned
assert BackgroundType.from_string(background_type_solid) == BackgroundType.Solid
assert BackgroundType.from_string(background_type_gradient) == BackgroundType.Gradient
assert BackgroundType.from_string(background_type_image) == BackgroundType.Image
assert BackgroundType.from_string(background_type_transparent) == BackgroundType.Transparent
assert BackgroundType.from_string(background_type_video) == BackgroundType.Video
assert BackgroundType.from_string(background_type_stream) == BackgroundType.Stream
def test_expand_json(self):
"""
Test the expand_json method
"""
# GIVEN: A Theme object and some JSON to "expand"
theme = Theme()
theme_json = {
'background': {
'border_color': '#000000',
'type': 'solid'
def test_background_gradient_type_to_string():
"""
Test the to_string method of :class:`BackgroundGradientType`
"""
# GIVEN: The BackgroundGradientType member
background_gradient_horizontal = BackgroundGradientType.Horizontal
background_gradient_vertical = BackgroundGradientType.Vertical
background_gradient_circular = BackgroundGradientType.Circular
background_gradient_left_top = BackgroundGradientType.LeftTop
background_gradient_left_bottom = BackgroundGradientType.LeftBottom
# WHEN: Calling BackgroundGradientType.to_string
# THEN: The string equivalents should be returned
assert BackgroundGradientType.to_string(background_gradient_horizontal) == 'horizontal'
assert BackgroundGradientType.to_string(background_gradient_vertical) == 'vertical'
assert BackgroundGradientType.to_string(background_gradient_circular) == 'circular'
assert BackgroundGradientType.to_string(background_gradient_left_top) == 'leftTop'
assert BackgroundGradientType.to_string(background_gradient_left_bottom) == 'leftBottom'
def test_background_gradient_type_from_string():
"""
Test the from_string method of :class:`BackgroundGradientType`
"""
# GIVEN: The BackgroundGradientType strings
background_gradient_horizontal = 'horizontal'
background_gradient_vertical = 'vertical'
background_gradient_circular = 'circular'
background_gradient_left_top = 'leftTop'
background_gradient_left_bottom = 'leftBottom'
# WHEN: Calling BackgroundGradientType.from_string
# THEN: The enum equivalents should be returned
assert BackgroundGradientType.from_string(background_gradient_horizontal) == BackgroundGradientType.Horizontal
assert BackgroundGradientType.from_string(background_gradient_vertical) == BackgroundGradientType.Vertical
assert BackgroundGradientType.from_string(background_gradient_circular) == BackgroundGradientType.Circular
assert BackgroundGradientType.from_string(background_gradient_left_top) == BackgroundGradientType.LeftTop
assert BackgroundGradientType.from_string(background_gradient_left_bottom) == BackgroundGradientType.LeftBottom
def test_transition_type_to_string():
"""
Test the to_string method of :class:`TransitionType`
"""
# GIVEN: The TransitionType member
transition_type_fade = TransitionType.Fade
transition_type_slide = TransitionType.Slide
transition_type_convex = TransitionType.Convex
transition_type_concave = TransitionType.Concave
transition_type_zoom = TransitionType.Zoom
# WHEN: Calling TransitionType.to_string
# THEN: The string equivalents should be returned
assert TransitionType.to_string(transition_type_fade) == 'fade'
assert TransitionType.to_string(transition_type_slide) == 'slide'
assert TransitionType.to_string(transition_type_convex) == 'convex'
assert TransitionType.to_string(transition_type_concave) == 'concave'
assert TransitionType.to_string(transition_type_zoom) == 'zoom'
def test_transition_type_from_string():
"""
Test the from_string method of :class:`TransitionType`
"""
# GIVEN: The TransitionType strings
transition_type_fade = 'fade'
transition_type_slide = 'slide'
transition_type_convex = 'convex'
transition_type_concave = 'concave'
transition_type_zoom = 'zoom'
# WHEN: Calling TransitionType.from_string
# THEN: The enum equivalents should be returned
assert TransitionType.from_string(transition_type_fade) == TransitionType.Fade
assert TransitionType.from_string(transition_type_slide) == TransitionType.Slide
assert TransitionType.from_string(transition_type_convex) == TransitionType.Convex
assert TransitionType.from_string(transition_type_concave) == TransitionType.Concave
assert TransitionType.from_string(transition_type_zoom) == TransitionType.Zoom
def test_transition_speed_to_string():
"""
Test the to_string method of :class:`TransitionSpeed`
"""
# GIVEN: The TransitionSpeed member
transition_speed_normal = TransitionSpeed.Normal
transition_speed_fast = TransitionSpeed.Fast
transition_speed_slow = TransitionSpeed.Slow
# WHEN: Calling TransitionSpeed.to_string
# THEN: The string equivalents should be returned
assert TransitionSpeed.to_string(transition_speed_normal) == 'normal'
assert TransitionSpeed.to_string(transition_speed_fast) == 'fast'
assert TransitionSpeed.to_string(transition_speed_slow) == 'slow'
def test_transition_speed_from_string():
"""
Test the from_string method of :class:`TransitionSpeed`
"""
# GIVEN: The TransitionSpeed strings
transition_speed_normal = 'normal'
transition_speed_fast = 'fast'
transition_speed_slow = 'slow'
# WHEN: Calling TransitionSpeed.from_string
# THEN: The enum equivalents should be returned
assert TransitionSpeed.from_string(transition_speed_normal) == TransitionSpeed.Normal
assert TransitionSpeed.from_string(transition_speed_fast) == TransitionSpeed.Fast
assert TransitionSpeed.from_string(transition_speed_slow) == TransitionSpeed.Slow
def test_new_theme():
"""
Test the Theme constructor
"""
# GIVEN: The Theme class
# WHEN: A theme object is created
default_theme = Theme()
# THEN: The default values should be correct
check_theme(default_theme)
def test_expand_json():
"""
Test the expand_json method
"""
# GIVEN: A Theme object and some JSON to "expand"
theme = Theme()
theme_json = {
'background': {
'border_color': '#000000',
'type': 'solid'
},
'display': {
'vertical_align': 0
},
'font': {
'footer': {
'bold': False
},
'display': {
'vertical_align': 0
},
'font': {
'footer': {
'bold': False
},
'main': {
'name': 'Arial'
}
'main': {
'name': 'Arial'
}
}
}
# WHEN: Theme.expand_json() is run
theme.expand_json(theme_json)
# WHEN: Theme.expand_json() is run
theme.expand_json(theme_json)
# THEN: The attributes should be set on the object
self.check_theme(theme)
# THEN: The attributes should be set on the object
check_theme(theme)
def test_extend_image_filename(self):
"""
Test the extend_image_filename method
"""
# GIVEN: A theme object
theme = Theme()
theme.theme_name = 'MyBeautifulTheme'
theme.background_filename = Path('video.mp4')
theme.background_type = 'video'
path = Path.home()
# WHEN: Theme.extend_image_filename is run
theme.extend_image_filename(path)
def test_extend_image_filename():
"""
Test the extend_image_filename method
"""
# GIVEN: A theme object
theme = Theme()
theme.theme_name = 'MyBeautifulTheme'
theme.background_filename = Path('video.mp4')
theme.background_type = 'video'
path = Path.home()
# THEN: The filename of the background should be correct
expected_filename = path / 'MyBeautifulTheme' / 'video.mp4'
assert expected_filename == theme.background_filename
assert 'MyBeautifulTheme' == theme.theme_name
# WHEN: Theme.extend_image_filename is run
theme.extend_image_filename(path)
def test_save_retrieve(self):
"""
Load a dummy theme, save it and reload it
"""
# GIVEN: The default Theme class
# WHEN: A theme object is created
default_theme = Theme()
# THEN: The default values should be correct
save_theme_json = default_theme.export_theme()
lt = Theme()
lt.load_theme(save_theme_json)
self.check_theme(lt)
# THEN: The filename of the background should be correct
expected_filename = path / 'MyBeautifulTheme' / 'video.mp4'
assert expected_filename == theme.background_filename
assert 'MyBeautifulTheme' == theme.theme_name
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_footer(self, mock_geometry):
"""
Test the set_default_footer function sets the footer back to default
(reletive to the screen)
"""
# GIVEN: A screen geometry object and a Theme footer with a strange area
mock_geometry.display_geometry = MagicMock()
mock_geometry.display_geometry.height.return_value = 600
mock_geometry.display_geometry.width.return_value = 400
theme = Theme()
theme.font_main_x = 20
theme.font_footer_x = 207
theme.font_footer_y = 25
theme.font_footer_width = 4253
theme.font_footer_height = 5423
# WHEN: set_default_footer is called
theme.set_default_footer()
def test_save_retrieve():
"""
Load a dummy theme, save it and reload it
"""
# GIVEN: The default Theme class
# WHEN: A theme object is created
default_theme = Theme()
# THEN: The default values should be correct
save_theme_json = default_theme.export_theme()
lt = Theme()
lt.load_theme(save_theme_json)
check_theme(lt)
# THEN: footer should be set, header should not have changed
assert theme.font_main_x == 20, 'header should not have been changed'
assert theme.font_footer_x == 10, 'x pos should be reset to default of 10'
assert theme.font_footer_y == 540, 'y pos should be reset to (screen_size_height * 9 / 10)'
assert theme.font_footer_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert theme.font_footer_height == 60, 'height should have been reset to (screen_size_height / 10)'
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header(self, mock_geometry):
"""
Test the set_default_header function sets the header back to default
(reletive to the screen)
"""
# GIVEN: A screen geometry object and a Theme header with a strange area
mock_geometry.display_geometry = MagicMock()
mock_geometry.display_geometry.height.return_value = 600
mock_geometry.display_geometry.width.return_value = 400
theme = Theme()
theme.font_footer_x = 200
theme.font_main_x = 687
theme.font_main_y = 546
theme.font_main_width = 345
theme.font_main_height = 653
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_footer(mock_geometry):
"""
Test the set_default_footer function sets the footer back to default
(reletive to the screen)
"""
# GIVEN: A screen geometry object and a Theme footer with a strange area
mock_geometry.display_geometry = MagicMock()
mock_geometry.display_geometry.height.return_value = 600
mock_geometry.display_geometry.width.return_value = 400
theme = Theme()
theme.font_main_x = 20
theme.font_footer_x = 207
theme.font_footer_y = 25
theme.font_footer_width = 4253
theme.font_footer_height = 5423
# WHEN: set_default_header is called
theme.set_default_header()
# WHEN: set_default_footer is called
theme.set_default_footer()
# THEN: footer should be set, header should not have changed
assert theme.font_footer_x == 200, 'footer should not have been changed'
assert theme.font_main_x == 10, 'x pos should be reset to default of 10'
assert theme.font_main_y == 0, 'y pos should be reset to 0'
assert theme.font_main_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert theme.font_main_height == 540, 'height should have been reset to (screen_size_height * 9 / 10)'
# THEN: footer should be set, header should not have changed
assert theme.font_main_x == 20, 'header should not have been changed'
assert theme.font_footer_x == 10, 'x pos should be reset to default of 10'
assert theme.font_footer_y == 540, 'y pos should be reset to (screen_size_height * 9 / 10)'
assert theme.font_footer_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert theme.font_footer_height == 60, 'height should have been reset to (screen_size_height / 10)'
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header_footer(self, mock_geometry):
"""
Test the set_default_header_footer function sets the header and footer back to default
(reletive to the screen)
"""
# GIVEN: A screen geometry object and a Theme header with a strange area
mock_geometry.display_geometry = MagicMock()
theme = Theme()
theme.font_footer_x = 200
theme.font_main_x = 687
# WHEN: set_default_header is called
theme.set_default_header_footer()
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header(mock_geometry):
"""
Test the set_default_header function sets the header back to default
(reletive to the screen)
"""
# GIVEN: A screen geometry object and a Theme header with a strange area
mock_geometry.display_geometry = MagicMock()
mock_geometry.display_geometry.height.return_value = 600
mock_geometry.display_geometry.width.return_value = 400
theme = Theme()
theme.font_footer_x = 200
theme.font_main_x = 687
theme.font_main_y = 546
theme.font_main_width = 345
theme.font_main_height = 653
# THEN: footer should be set, header should not have changed
assert theme.font_footer_x == 10, 'footer x pos should be reset to default of 10'
assert theme.font_main_x == 10, 'header x pos should be reset to default of 10'
# WHEN: set_default_header is called
theme.set_default_header()
def check_theme(self, theme):
assert '#000000' == theme.background_border_color, 'background_border_color should be "#000000"'
assert 'solid' == theme.background_type, 'background_type should be "solid"'
assert 0 == theme.display_vertical_align, 'display_vertical_align should be 0'
assert theme.font_footer_bold is False, 'font_footer_bold should be False'
assert 'Arial' == theme.font_main_name, 'font_main_name should be "Arial"'
assert 53 == len(theme.__dict__), 'The theme should have 53 attributes'
# THEN: footer should be set, header should not have changed
assert theme.font_footer_x == 200, 'footer should not have been changed'
assert theme.font_main_x == 10, 'x pos should be reset to default of 10'
assert theme.font_main_y == 0, 'y pos should be reset to 0'
assert theme.font_main_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert theme.font_main_height == 540, 'height should have been reset to (screen_size_height * 9 / 10)'
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header_footer(mock_geometry):
"""
Test the set_default_header_footer function sets the header and footer back to default
(reletive to the screen)
"""
# GIVEN: A screen geometry object and a Theme header with a strange area
mock_geometry.display_geometry = MagicMock()
theme = Theme()
theme.font_footer_x = 200
theme.font_main_x = 687
# WHEN: set_default_header is called
theme.set_default_header_footer()
# THEN: footer should be set, header should not have changed
assert theme.font_footer_x == 10, 'footer x pos should be reset to default of 10'
assert theme.font_main_x == 10, 'header x pos should be reset to default of 10'
def check_theme(theme):
assert '#000000' == theme.background_border_color, 'background_border_color should be "#000000"'
assert 'solid' == theme.background_type, 'background_type should be "solid"'
assert 0 == theme.display_vertical_align, 'display_vertical_align should be 0'
assert theme.font_footer_bold is False, 'font_footer_bold should be False'
assert 'Arial' == theme.font_main_name, 'font_main_name should be "Arial"'
assert 53 == len(theme.__dict__), 'The theme should have 53 attributes'

View File

@ -21,7 +21,6 @@
"""
Package to test the openlp.core.lib.ui package.
"""
from unittest import TestCase
from unittest.mock import MagicMock, call, patch
from PyQt5 import QtCore, QtGui, QtWidgets
@ -32,287 +31,297 @@ from openlp.core.lib.ui import add_welcome_page, create_action, create_button, c
critical_error_message_box, find_and_set_in_combo_box, set_case_insensitive_completer
class TestUi(TestCase):
def test_add_welcome_page():
"""
Test the functions in the ui module
Test appending a welcome page to a wizard
"""
# GIVEN: A wizard
wizard = QtWidgets.QWizard()
def test_add_welcome_page(self):
"""
Test appending a welcome page to a wizard
"""
# GIVEN: A wizard
wizard = QtWidgets.QWizard()
# WHEN: A welcome page has been added to the wizard
add_welcome_page(wizard, ':/wizards/wizard_firsttime.bmp')
# WHEN: A welcome page has been added to the wizard
add_welcome_page(wizard, ':/wizards/wizard_firsttime.bmp')
# THEN: The wizard should have one page with a pixmap.
assert 1 == len(wizard.pageIds()), 'The wizard should have one page.'
assert isinstance(wizard.page(0).pixmap(QtWidgets.QWizard.WatermarkPixmap), QtGui.QPixmap)
# THEN: The wizard should have one page with a pixmap.
assert 1 == len(wizard.pageIds()), 'The wizard should have one page.'
assert isinstance(wizard.page(0).pixmap(QtWidgets.QWizard.WatermarkPixmap), QtGui.QPixmap)
def test_create_button_box(self):
"""
Test creating a button box for a dialog
"""
# GIVEN: A dialog
def test_create_button_box():
"""
Test creating a button box for a dialog
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create the button box with five buttons
btnbox = create_button_box(dialog, 'my_btns', ['ok', 'save', 'cancel', 'close', 'defaults'])
# THEN: We should get a QDialogButtonBox with five buttons
assert isinstance(btnbox, QtWidgets.QDialogButtonBox)
assert 5 == len(btnbox.buttons())
# WHEN: We create the button box with a custom button
btnbox = create_button_box(dialog, 'my_btns', None, [QtWidgets.QPushButton('Custom')])
# THEN: We should get a QDialogButtonBox with one button
assert isinstance(btnbox, QtWidgets.QDialogButtonBox)
assert 1 == len(btnbox.buttons())
# WHEN: We create the button box with a custom button and a custom role
btnbox = create_button_box(dialog, 'my_btns', None,
[(QtWidgets.QPushButton('Help'), QtWidgets.QDialogButtonBox.HelpRole)])
# THEN: We should get a QDialogButtonBox with one button with a certain role
assert isinstance(btnbox, QtWidgets.QDialogButtonBox)
assert 1 == len(btnbox.buttons())
assert QtWidgets.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0])
@patch('openlp.core.lib.ui.Registry')
def test_critical_error_message_box(MockRegistry):
"""
Test the critical_error_message_box() function
"""
# GIVEN: A mocked Registry
# WHEN: critical_error_message_box() is called
critical_error_message_box('Error', 'This is an error')
# THEN: The error_message() method on the main window should be called
MockRegistry.return_value.get.return_value.error_message.assert_called_once_with('Error', 'This is an error')
@patch('openlp.core.lib.ui.QtWidgets.QMessageBox.critical')
def test_critical_error_question(mocked_critical):
"""
Test the critical_error_message_box() function
"""
# GIVEN: A mocked critical() method and some other mocks
mocked_parent = MagicMock()
# WHEN: critical_error_message_box() is called
critical_error_message_box(None, 'This is a question', mocked_parent, True)
# THEN: The error_message() method on the main window should be called
mocked_critical.assert_called_once_with(mocked_parent, 'Error', 'This is a question',
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No))
def test_create_horizontal_adjusting_combo_box():
"""
Test creating a horizontal adjusting combo box
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create the combobox
combo = create_horizontal_adjusting_combo_box(dialog, 'combo1')
# THEN: We should get a ComboBox
assert isinstance(combo, QtWidgets.QComboBox)
assert combo.objectName() == 'combo1'
assert QtWidgets.QComboBox.AdjustToMinimumContentsLength == combo.sizeAdjustPolicy()
@patch('openlp.core.lib.ui.log')
def test_create_button(mocked_log):
"""
Test creating a button
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create a button with some attributes
btn = create_button(dialog, 'my_btn', text='Hello', tooltip='How are you?', enabled=False, role='test', test=1)
# THEN: We should get a button with those attributes
assert isinstance(btn, QtWidgets.QPushButton)
assert btn.objectName() == 'my_btn'
assert btn.text() == 'Hello'
assert btn.toolTip() == 'How are you?'
assert btn.isEnabled() is False
assert mocked_log.warning.call_args_list == [call('The role "test" is not defined in create_push_button().'),
call('Parameter test was not consumed in create_button().')]
def test_create_tool_button():
"""
Test creating a toolbutton
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create a toolbutton
btn = create_button(dialog, 'my_btn', btn_class='toolbutton')
# THEN: We should get a toolbutton
assert isinstance(btn, QtWidgets.QToolButton)
assert btn.objectName() == 'my_btn'
assert btn.isEnabled() is True
@patch('openlp.core.lib.ui.log')
def test_create_action(mocked_log):
"""
Test creating an action
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create an action with some properties
action = create_action(dialog, 'my_action', text='my text', icon=':/wizards/wizard_firsttime.bmp',
tooltip='my tooltip', statustip='my statustip', test=1)
# THEN: These properties should be set
assert isinstance(action, QtWidgets.QAction)
assert action.objectName() == 'my_action'
assert action.text() == 'my text'
assert isinstance(action.icon(), QtGui.QIcon)
assert action.toolTip() == 'my tooltip'
assert action.statusTip() == 'my statustip'
mocked_log.warning.assert_called_once_with('Parameter test was not consumed in create_action().')
def test_create_action_on_mac_osx():
"""
Test creating an action on OS X calls the correct method
"""
# GIVEN: A dialog and a mocked out is_macosx() method to always return True
with patch('openlp.core.lib.ui.is_macosx') as mocked_is_macosx, \
patch('openlp.core.lib.ui.QtWidgets.QAction') as MockedQAction:
mocked_is_macosx.return_value = True
mocked_action = MagicMock()
MockedQAction.return_value = mocked_action
dialog = QtWidgets.QDialog()
# WHEN: We create the button box with five buttons
btnbox = create_button_box(dialog, 'my_btns', ['ok', 'save', 'cancel', 'close', 'defaults'])
# WHEN: An action is created
create_action(dialog, 'my_action')
# THEN: We should get a QDialogButtonBox with five buttons
assert isinstance(btnbox, QtWidgets.QDialogButtonBox)
assert 5 == len(btnbox.buttons())
# THEN: setIconVisibleInMenu should be called
mocked_action.setIconVisibleInMenu.assert_called_with(False)
# WHEN: We create the button box with a custom button
btnbox = create_button_box(dialog, 'my_btns', None, [QtWidgets.QPushButton('Custom')])
# THEN: We should get a QDialogButtonBox with one button
assert isinstance(btnbox, QtWidgets.QDialogButtonBox)
assert 1 == len(btnbox.buttons())
# WHEN: We create the button box with a custom button and a custom role
btnbox = create_button_box(dialog, 'my_btns', None,
[(QtWidgets.QPushButton('Help'), QtWidgets.QDialogButtonBox.HelpRole)])
# THEN: We should get a QDialogButtonBox with one button with a certain role
assert isinstance(btnbox, QtWidgets.QDialogButtonBox)
assert 1 == len(btnbox.buttons())
assert QtWidgets.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0])
@patch('openlp.core.lib.ui.Registry')
def test_critical_error_message_box(self, MockRegistry):
"""
Test the critical_error_message_box() function
"""
# GIVEN: A mocked Registry
# WHEN: critical_error_message_box() is called
critical_error_message_box('Error', 'This is an error')
# THEN: The error_message() method on the main window should be called
MockRegistry.return_value.get.return_value.error_message.assert_called_once_with('Error', 'This is an error')
@patch('openlp.core.lib.ui.QtWidgets.QMessageBox.critical')
def test_critical_error_question(self, mocked_critical):
"""
Test the critical_error_message_box() function
"""
# GIVEN: A mocked critical() method and some other mocks
mocked_parent = MagicMock()
# WHEN: critical_error_message_box() is called
critical_error_message_box(None, 'This is a question', mocked_parent, True)
# THEN: The error_message() method on the main window should be called
mocked_critical.assert_called_once_with(mocked_parent, 'Error', 'This is a question',
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No))
def test_create_horizontal_adjusting_combo_box(self):
"""
Test creating a horizontal adjusting combo box
"""
# GIVEN: A dialog
def test_create_action_not_on_mac_osx():
"""
Test creating an action on something other than OS X doesn't call the method
"""
# GIVEN: A dialog and a mocked out is_macosx() method to always return True
with patch('openlp.core.lib.ui.is_macosx') as mocked_is_macosx, \
patch('openlp.core.lib.ui.QtWidgets.QAction') as MockedQAction:
mocked_is_macosx.return_value = False
mocked_action = MagicMock()
MockedQAction.return_value = mocked_action
dialog = QtWidgets.QDialog()
# WHEN: We create the combobox
combo = create_horizontal_adjusting_combo_box(dialog, 'combo1')
# WHEN: An action is created
create_action(dialog, 'my_action')
# THEN: We should get a ComboBox
assert isinstance(combo, QtWidgets.QComboBox)
assert combo.objectName() == 'combo1'
assert QtWidgets.QComboBox.AdjustToMinimumContentsLength == combo.sizeAdjustPolicy()
# THEN: setIconVisibleInMenu should not be called
assert 0 == mocked_action.setIconVisibleInMenu.call_count, \
'setIconVisibleInMenu should not have been called'
@patch('openlp.core.lib.ui.log')
def test_create_button(self, mocked_log):
"""
Test creating a button
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create a button with some attributes
btn = create_button(dialog, 'my_btn', text='Hello', tooltip='How are you?', enabled=False, role='test', test=1)
def test_create_checked_disabled_invisible_action():
"""
Test that an invisible, disabled, checked action is created correctly
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# THEN: We should get a button with those attributes
assert isinstance(btn, QtWidgets.QPushButton)
assert btn.objectName() == 'my_btn'
assert btn.text() == 'Hello'
assert btn.toolTip() == 'How are you?'
assert btn.isEnabled() is False
assert mocked_log.warning.call_args_list == [call('The role "test" is not defined in create_push_button().'),
call('Parameter test was not consumed in create_button().')]
# WHEN: We create an action with some properties
action = create_action(dialog, 'my_action', checked=True, enabled=False, visible=False)
def test_create_tool_button(self):
"""
Test creating a toolbutton
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# THEN: These properties should be set
assert action.isChecked() is True, 'The action should be checked'
assert action.isEnabled() is False, 'The action should be disabled'
assert action.isVisible() is False, 'The action should be invisble'
# WHEN: We create a toolbutton
btn = create_button(dialog, 'my_btn', btn_class='toolbutton')
# THEN: We should get a toolbutton
assert isinstance(btn, QtWidgets.QToolButton)
assert btn.objectName() == 'my_btn'
assert btn.isEnabled() is True
def test_create_action_separator():
"""
Test creating an action as separator
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
@patch('openlp.core.lib.ui.log')
def test_create_action(self, mocked_log):
"""
Test creating an action
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create an action as a separator
action = create_action(dialog, 'my_action', separator=True)
# WHEN: We create an action with some properties
action = create_action(dialog, 'my_action', text='my text', icon=':/wizards/wizard_firsttime.bmp',
tooltip='my tooltip', statustip='my statustip', test=1)
# THEN: The action should be a separator
assert action.isSeparator() is True, 'The action should be a separator'
# THEN: These properties should be set
assert isinstance(action, QtWidgets.QAction)
assert action.objectName() == 'my_action'
assert action.text() == 'my text'
assert isinstance(action.icon(), QtGui.QIcon)
assert action.toolTip() == 'my tooltip'
assert action.statusTip() == 'my statustip'
mocked_log.warning.assert_called_once_with('Parameter test was not consumed in create_action().')
def test_create_action_on_mac_osx(self):
"""
Test creating an action on OS X calls the correct method
"""
# GIVEN: A dialog and a mocked out is_macosx() method to always return True
with patch('openlp.core.lib.ui.is_macosx') as mocked_is_macosx, \
patch('openlp.core.lib.ui.QtWidgets.QAction') as MockedQAction:
mocked_is_macosx.return_value = True
mocked_action = MagicMock()
MockedQAction.return_value = mocked_action
dialog = QtWidgets.QDialog()
def test_create_valign_selection_widgets():
"""
Test creating a combo box for valign selection
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: An action is created
create_action(dialog, 'my_action')
# WHEN: We create the widgets
label, combo = create_valign_selection_widgets(dialog)
# THEN: setIconVisibleInMenu should be called
mocked_action.setIconVisibleInMenu.assert_called_with(False)
# THEN: We should get a label and a combobox.
assert translate('OpenLP.Ui', '&Vertical Align:') == label.text()
assert isinstance(combo, QtWidgets.QComboBox)
assert combo == label.buddy()
for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]:
assert combo.findText(text) >= 0
def test_create_action_not_on_mac_osx(self):
"""
Test creating an action on something other than OS X doesn't call the method
"""
# GIVEN: A dialog and a mocked out is_macosx() method to always return True
with patch('openlp.core.lib.ui.is_macosx') as mocked_is_macosx, \
patch('openlp.core.lib.ui.QtWidgets.QAction') as MockedQAction:
mocked_is_macosx.return_value = False
mocked_action = MagicMock()
MockedQAction.return_value = mocked_action
dialog = QtWidgets.QDialog()
# WHEN: An action is created
create_action(dialog, 'my_action')
def test_find_and_set_in_combo_box():
"""
Test finding a string in a combo box and setting it as the selected item if present
"""
# GIVEN: A ComboBox
combo = QtWidgets.QComboBox()
combo.addItems(['One', 'Two', 'Three'])
combo.setCurrentIndex(1)
# THEN: setIconVisibleInMenu should not be called
assert 0 == mocked_action.setIconVisibleInMenu.call_count, \
'setIconVisibleInMenu should not have been called'
# WHEN: We call the method with a non-existing value and set_missing=False
find_and_set_in_combo_box(combo, 'Four', set_missing=False)
def test_create_checked_disabled_invisible_action(self):
"""
Test that an invisible, disabled, checked action is created correctly
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# THEN: The index should not have changed
assert 1 == combo.currentIndex()
# WHEN: We create an action with some properties
action = create_action(dialog, 'my_action', checked=True, enabled=False, visible=False)
# WHEN: We call the method with a non-existing value
find_and_set_in_combo_box(combo, 'Four')
# THEN: These properties should be set
assert action.isChecked() is True, 'The action should be checked'
assert action.isEnabled() is False, 'The action should be disabled'
assert action.isVisible() is False, 'The action should be invisble'
# THEN: The index should have been reset
assert 0 == combo.currentIndex()
def test_create_action_separator(self):
"""
Test creating an action as separator
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We call the method with the default behavior
find_and_set_in_combo_box(combo, 'Three')
# WHEN: We create an action as a separator
action = create_action(dialog, 'my_action', separator=True)
# THEN: The index should have changed
assert 2 == combo.currentIndex()
# THEN: The action should be a separator
assert action.isSeparator() is True, 'The action should be a separator'
def test_create_valign_selection_widgets(self):
"""
Test creating a combo box for valign selection
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
def test_create_widget_action():
"""
Test creating an action for a widget
"""
# GIVEN: A button
button = QtWidgets.QPushButton()
# WHEN: We create the widgets
label, combo = create_valign_selection_widgets(dialog)
# WHEN: We call the function
action = create_widget_action(button, 'some action')
# THEN: We should get a label and a combobox.
assert translate('OpenLP.Ui', '&Vertical Align:') == label.text()
assert isinstance(combo, QtWidgets.QComboBox)
assert combo == label.buddy()
for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]:
assert combo.findText(text) >= 0
# THEN: The action should be returned
assert isinstance(action, QtWidgets.QAction)
assert action.objectName() == 'some action'
def test_find_and_set_in_combo_box(self):
"""
Test finding a string in a combo box and setting it as the selected item if present
"""
# GIVEN: A ComboBox
combo = QtWidgets.QComboBox()
combo.addItems(['One', 'Two', 'Three'])
combo.setCurrentIndex(1)
# WHEN: We call the method with a non-existing value and set_missing=False
find_and_set_in_combo_box(combo, 'Four', set_missing=False)
def test_set_case_insensitive_completer():
"""
Test setting a case insensitive completer on a widget
"""
# GIVEN: A QComboBox and a list of completion items
line_edit = QtWidgets.QLineEdit()
suggestions = ['one', 'Two', 'THRee', 'FOUR']
# THEN: The index should not have changed
assert 1 == combo.currentIndex()
# WHEN: We call the function
set_case_insensitive_completer(suggestions, line_edit)
# WHEN: We call the method with a non-existing value
find_and_set_in_combo_box(combo, 'Four')
# THEN: The index should have been reset
assert 0 == combo.currentIndex()
# WHEN: We call the method with the default behavior
find_and_set_in_combo_box(combo, 'Three')
# THEN: The index should have changed
assert 2 == combo.currentIndex()
def test_create_widget_action(self):
"""
Test creating an action for a widget
"""
# GIVEN: A button
button = QtWidgets.QPushButton()
# WHEN: We call the function
action = create_widget_action(button, 'some action')
# THEN: The action should be returned
assert isinstance(action, QtWidgets.QAction)
assert action.objectName() == 'some action'
def test_set_case_insensitive_completer(self):
"""
Test setting a case insensitive completer on a widget
"""
# GIVEN: A QComboBox and a list of completion items
line_edit = QtWidgets.QLineEdit()
suggestions = ['one', 'Two', 'THRee', 'FOUR']
# WHEN: We call the function
set_case_insensitive_completer(suggestions, line_edit)
# THEN: The Combobox should have a completer which is case insensitive
completer = line_edit.completer()
assert isinstance(completer, QtWidgets.QCompleter)
assert completer.caseSensitivity() == QtCore.Qt.CaseInsensitive
# THEN: The Combobox should have a completer which is case insensitive
completer = line_edit.completer()
assert isinstance(completer, QtWidgets.QCompleter)
assert completer.caseSensitivity() == QtCore.Qt.CaseInsensitive

View File

@ -21,156 +21,165 @@
"""
This module contains tests for the openlp.core.widgets.buttons module
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, call, patch
from openlp.core.widgets.buttons import ColorButton
class TestColorDialog(TestCase):
@pytest.yield_fixture()
def buttons_env():
change_color_patcher = patch('openlp.core.widgets.buttons.ColorButton.change_color')
clicked_patcher = patch('openlp.core.widgets.buttons.ColorButton.clicked')
color_changed_patcher = patch('openlp.core.widgets.buttons.ColorButton.colorChanged')
qt_gui_patcher = patch('openlp.core.widgets.buttons.QtWidgets')
translate_patcher = patch('openlp.core.widgets.buttons.translate', **{'return_value': 'Tool Tip Text'})
mocked_change_color = change_color_patcher.start()
mocked_clicked = clicked_patcher.start()
mocked_color_changed = color_changed_patcher.start()
mocked_qt_widgets = qt_gui_patcher.start()
translate_patcher.start()
yield mocked_clicked, mocked_color_changed, mocked_qt_widgets, mocked_change_color
change_color_patcher.stop()
clicked_patcher.stop()
color_changed_patcher.stop()
qt_gui_patcher.stop()
translate_patcher.stop()
@patch('openlp.core.widgets.buttons.ColorButton.setToolTip')
def test_constructor(mocked_set_tool_tip, buttons_env):
"""
Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class
Test that constructing a ColorButton object works correctly
"""
def setUp(self):
self.change_color_patcher = patch('openlp.core.widgets.buttons.ColorButton.change_color')
self.clicked_patcher = patch('openlp.core.widgets.buttons.ColorButton.clicked')
self.color_changed_patcher = patch('openlp.core.widgets.buttons.ColorButton.colorChanged')
self.qt_gui_patcher = patch('openlp.core.widgets.buttons.QtWidgets')
self.translate_patcher = patch('openlp.core.widgets.buttons.translate', **{'return_value': 'Tool Tip Text'})
self.addCleanup(self.change_color_patcher.stop)
self.addCleanup(self.clicked_patcher.stop)
self.addCleanup(self.color_changed_patcher.stop)
self.addCleanup(self.qt_gui_patcher.stop)
self.addCleanup(self.translate_patcher.stop)
self.mocked_change_color = self.change_color_patcher.start()
self.mocked_clicked = self.clicked_patcher.start()
self.mocked_color_changed = self.color_changed_patcher.start()
self.mocked_qt_widgets = self.qt_gui_patcher.start()
self.mocked_translate = self.translate_patcher.start()
@patch('openlp.core.widgets.buttons.ColorButton.setToolTip')
def test_constructor(self, mocked_set_tool_tip):
"""
Test that constructing a ColorButton object works correctly
"""
# GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
# WHEN: The ColorButton object is instantiated
mocked_clicked = buttons_env[0]
mocked_change_color = buttons_env[3]
widget = ColorButton()
# GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
# WHEN: The ColorButton object is instantiated
widget = ColorButton()
# THEN: The widget __init__ method should have the correct properties and methods called
assert widget.parent is None, 'The parent should be the same as the one that the class was instianted with'
mocked_change_color.assert_called_once_with('#ffffff')
mocked_set_tool_tip.assert_called_once_with('Tool Tip Text')
mocked_clicked.connect.assert_called_once_with(widget.on_clicked)
# THEN: The widget __init__ method should have the correct properties and methods called
assert widget.parent is None, 'The parent should be the same as the one that the class was instianted with'
self.mocked_change_color.assert_called_once_with('#ffffff')
mocked_set_tool_tip.assert_called_once_with('Tool Tip Text')
self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked)
@patch('openlp.core.widgets.buttons.ColorButton.setStyleSheet')
def test_change_color(self, mocked_set_style_sheet):
"""
Test that change_color sets the new color and the stylesheet
"""
self.change_color_patcher.stop()
@patch('openlp.core.widgets.buttons.ColorButton.setStyleSheet')
def test_change_color(mocked_set_style_sheet):
"""
Test that change_color sets the new color and the stylesheet
"""
# GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet
widget = ColorButton()
# GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet
widget = ColorButton()
# WHEN: Changing the color
widget.change_color('#000000')
# WHEN: Changing the color
widget.change_color('#000000')
# THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice
assert widget._color == '#000000', '_color should have been set to #000000'
mocked_set_style_sheet.assert_has_calls(
[call('background-color: #ffffff'), call('background-color: #000000')])
# THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice
assert widget._color == '#000000', '_color should have been set to #000000'
mocked_set_style_sheet.assert_has_calls(
[call('background-color: #ffffff'), call('background-color: #000000')])
self.mocked_change_color = self.change_color_patcher.start()
def test_color():
"""
Test that the color property method returns the set color
"""
# GIVEN: An instance of ColorButton, with a set _color attribute
widget = ColorButton()
widget._color = '#000000'
def test_color(self):
"""
Test that the color property method returns the set color
"""
# GIVEN: An instance of ColorButton, with a set _color attribute
widget = ColorButton()
widget._color = '#000000'
# WHEN: Accesing the color property
value = widget.color
# WHEN: Accesing the color property
value = widget.color
# THEN: The value set in _color should be returned
assert value == '#000000', 'The value returned should be equal to the one we set'
# THEN: The value set in _color should be returned
assert value == '#000000', 'The value returned should be equal to the one we set'
# @patch('openlp.core.widgets.buttons.ColorButton.__init__', **{'return_value': None})
def test_color_setter(self):
"""
Test that the color property setter method sets the color
"""
# GIVEN: An instance of ColorButton, with a mocked __init__
widget = ColorButton()
def test_color_setter(buttons_env):
"""
Test that the color property setter method sets the color
"""
# GIVEN: An instance of ColorButton, with a mocked __init__
mocked_change_color = buttons_env[3]
widget = ColorButton()
# WHEN: Setting the color property
widget.color = '#000000'
# WHEN: Setting the color property
widget.color = '#000000'
# THEN: Then change_color should have been called with the value we set
self.mocked_change_color.assert_called_with('#000000')
# THEN: Then change_color should have been called with the value we set
mocked_change_color.assert_called_with('#000000')
def test_on_clicked_invalid_color(self):
"""
Test the on_click method when an invalid color has been supplied
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
widget = ColorButton()
self.mocked_change_color.reset_mock()
self.mocked_color_changed.reset_mock()
widget._color = '#000000'
def test_on_clicked_invalid_color(buttons_env):
"""
Test the on_click method when an invalid color has been supplied
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
mocked_color_changed = buttons_env[1]
mocked_qt_widgets = buttons_env[2]
mocked_change_color = buttons_env[3]
widget = ColorButton()
mocked_change_color.reset_mock()
mocked_color_changed.reset_mock()
widget._color = '#000000'
# WHEN: The on_clicked method is called, and the color is invalid
self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
widget.on_clicked()
# WHEN: The on_clicked method is called, and the color is invalid
mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
widget.on_clicked()
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted
assert self.mocked_change_color.called is False, \
'change_color should not have been called with an invalid color'
assert self.mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted with an invalid color'
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted
assert mocked_change_color.called is False, \
'change_color should not have been called with an invalid color'
assert mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted with an invalid color'
def test_on_clicked_same_color(self):
"""
Test the on_click method when a new color has not been chosen
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
widget = ColorButton()
self.mocked_change_color.reset_mock()
self.mocked_color_changed.reset_mock()
widget._color = '#000000'
def test_on_clicked_same_color(buttons_env):
"""
Test the on_click method when a new color has not been chosen
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
mocked_color_changed = buttons_env[1]
mocked_qt_widgets = buttons_env[2]
mocked_change_color = buttons_env[3]
widget = ColorButton()
mocked_change_color.reset_mock()
mocked_color_changed.reset_mock()
widget._color = '#000000'
# WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color
self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#000000'})
widget.on_clicked()
# WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color
mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#000000'})
widget.on_clicked()
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted
assert self.mocked_change_color.called is False, \
'change_color should not have been called when the color has not changed'
assert self.mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted when the color has not changed'
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted
assert mocked_change_color.called is False, \
'change_color should not have been called when the color has not changed'
assert mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted when the color has not changed'
def test_on_clicked_new_color(self):
"""
Test the on_click method when a new color has been chosen and is valid
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
widget = ColorButton()
self.mocked_change_color.reset_mock()
self.mocked_color_changed.reset_mock()
widget._color = '#000000'
def test_on_clicked_new_color(buttons_env):
"""
Test the on_click method when a new color has been chosen and is valid
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
mocked_color_changed = buttons_env[1]
mocked_qt_widgets = buttons_env[2]
mocked_change_color = buttons_env[3]
widget = ColorButton()
mocked_change_color.reset_mock()
mocked_color_changed.reset_mock()
widget._color = '#000000'
# WHEN: The on_clicked method is called, and the color is valid, and different to the existing color
self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#ffffff'})
widget.on_clicked()
# WHEN: The on_clicked method is called, and the color is valid, and different to the existing color
mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#ffffff'})
widget.on_clicked()
# THEN: change_color should have been called and the colorChanged signal should have been emitted
self.mocked_change_color.assert_called_once_with('#ffffff')
self.mocked_color_changed.emit.assert_called_once_with('#ffffff')
# THEN: change_color should have been called and the colorChanged signal should have been emitted
mocked_change_color.assert_called_once_with('#ffffff')
mocked_color_changed.emit.assert_called_once_with('#ffffff')

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
@ -20,7 +19,6 @@
##########################################################################
import os
from pathlib import Path
from unittest import TestCase
from unittest.mock import patch
from PyQt5 import QtWidgets
@ -28,181 +26,188 @@ from PyQt5 import QtWidgets
from openlp.core.widgets.dialogs import FileDialog
class TestFileDialogPatches(TestCase):
def test_file_dialog():
"""
Tests for the :mod:`openlp.core.widgets.dialogs` module
Test that the :class:`FileDialog` instantiates correctly
"""
# GIVEN: The FileDialog class
# WHEN: Creating an instance
instance = FileDialog()
def test_file_dialog(self):
"""
Test that the :class:`FileDialog` instantiates correctly
"""
# GIVEN: The FileDialog class
# WHEN: Creating an instance
instance = FileDialog()
# THEN: The instance should be an instance of QFileDialog
assert isinstance(instance, QtWidgets.QFileDialog)
# THEN: The instance should be an instance of QFileDialog
assert isinstance(instance, QtWidgets.QFileDialog)
def test_get_existing_directory_user_abort(self):
"""
Test that `getExistingDirectory` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getExistingDirectory method
# WHEN: Calling FileDialog.getExistingDirectory and the user cancels the dialog returns a empty string
with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=''):
result = FileDialog.getExistingDirectory()
def test_get_existing_directory_user_abort():
"""
Test that `getExistingDirectory` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getExistingDirectory method
# WHEN: Calling FileDialog.getExistingDirectory and the user cancels the dialog returns a empty string
with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=''):
result = FileDialog.getExistingDirectory()
# THEN: The result should be None
assert result is None
# THEN: The result should be None
assert result is None
def test_get_existing_directory_user_accepts(self):
"""
Test that `getExistingDirectory` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getExistingDirectory method
# WHEN: Calling FileDialog.getExistingDirectory, the user chooses a file and accepts the dialog (it returns a
# string pointing to the directory)
with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=os.path.join('test', 'dir')):
result = FileDialog.getExistingDirectory()
# THEN: getExistingDirectory() should return a Path object pointing to the chosen file
assert result == Path('test', 'dir')
def test_get_existing_directory_user_accepts():
"""
Test that `getExistingDirectory` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getExistingDirectory method
# WHEN: Calling FileDialog.getExistingDirectory, the user chooses a file and accepts the dialog (it returns a
# string pointing to the directory)
with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=os.path.join('test', 'dir')):
result = FileDialog.getExistingDirectory()
def test_get_existing_directory_param_order(self):
"""
Test that `getExistingDirectory` passes the parameters to `QFileDialog.getExistingDirectory` in the correct
order
"""
# GIVEN: FileDialog
with patch('openlp.core.widgets.dialogs.QtWidgets.QFileDialog.getExistingDirectory', return_value='') \
as mocked_get_existing_directory:
# THEN: getExistingDirectory() should return a Path object pointing to the chosen file
assert result == Path('test', 'dir')
# WHEN: Calling the getExistingDirectory method with all parameters set
FileDialog.getExistingDirectory('Parent', 'Caption', Path('test', 'dir'), 'Options')
# THEN: The `QFileDialog.getExistingDirectory` should have been called with the parameters in the correct
# order
mocked_get_existing_directory.assert_called_once_with('Parent', 'Caption', os.path.join('test', 'dir'),
'Options')
def test_get_existing_directory_param_order():
"""
Test that `getExistingDirectory` passes the parameters to `QFileDialog.getExistingDirectory` in the correct
order
"""
# GIVEN: FileDialog
with patch('openlp.core.widgets.dialogs.QtWidgets.QFileDialog.getExistingDirectory', return_value='') \
as mocked_get_existing_directory:
def test_get_open_file_name_user_abort(self):
"""
Test that `getOpenFileName` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileName method
# WHEN: Calling FileDialog.getOpenFileName and the user cancels the dialog (it returns a tuple with the first
# value set as an empty string)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')):
result = FileDialog.getOpenFileName()
# WHEN: Calling the getExistingDirectory method with all parameters set
FileDialog.getExistingDirectory('Parent', 'Caption', Path('test', 'dir'), 'Options')
# THEN: First value should be None
assert result[0] is None
# THEN: The `QFileDialog.getExistingDirectory` should have been called with the parameters in the correct
# order
mocked_get_existing_directory.assert_called_once_with('Parent', 'Caption', os.path.join('test', 'dir'),
'Options')
def test_get_open_file_name_user_accepts(self):
"""
Test that `getOpenFileName` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileName method
# WHEN: Calling FileDialog.getOpenFileName, the user chooses a file and accepts the dialog (it returns a
# tuple with the first value set as an string pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName',
return_value=(os.path.join('test', 'chosen.file'), '')):
result = FileDialog.getOpenFileName()
# THEN: getOpenFileName() should return a tuple with the first value set to a Path object pointing to the
# chosen file
assert result[0] == Path('test', 'chosen.file')
def test_get_open_file_name_user_abort():
"""
Test that `getOpenFileName` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileName method
# WHEN: Calling FileDialog.getOpenFileName and the user cancels the dialog (it returns a tuple with the first
# value set as an empty string)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')):
result = FileDialog.getOpenFileName()
def test_get_open_file_name_selected_filter(self):
"""
Test that `getOpenFileName` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileName`
"""
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method
# WHEN: Calling FileDialog.getOpenFileName, and `QFileDialog.getOpenFileName` returns a known `selectedFilter`
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName', return_value=('', 'selected filter')):
result = FileDialog.getOpenFileName()
# THEN: First value should be None
assert result[0] is None
# THEN: getOpenFileName() should return a tuple with the second value set to a the selected filter
assert result[1] == 'selected filter'
def test_get_open_file_names_user_abort(self):
"""
Test that `getOpenFileNames` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getOpenFileNames and the user cancels the dialog (it returns a tuple with the first
# value set as an empty list)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], '')):
result = FileDialog.getOpenFileNames()
def test_get_open_file_name_user_accepts():
"""
Test that `getOpenFileName` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileName method
# WHEN: Calling FileDialog.getOpenFileName, the user chooses a file and accepts the dialog (it returns a
# tuple with the first value set as an string pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName',
return_value=(os.path.join('test', 'chosen.file'), '')):
result = FileDialog.getOpenFileName()
# THEN: First value should be an empty list
assert result[0] == []
# THEN: getOpenFileName() should return a tuple with the first value set to a Path object pointing to the
# chosen file
assert result[0] == Path('test', 'chosen.file')
def test_get_open_file_names_user_accepts(self):
"""
Test that `getOpenFileNames` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getOpenFileNames, the user chooses some files and accepts the dialog (it returns a
# tuple with the first value set as a list of strings pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames',
return_value=([os.path.join('test', 'chosen.file1'), os.path.join('test', 'chosen.file2')], '')):
result = FileDialog.getOpenFileNames()
# THEN: getOpenFileNames() should return a tuple with the first value set to a list of Path objects pointing
# to the chosen file
assert result[0] == [Path('test', 'chosen.file1'), Path('test', 'chosen.file2')]
def test_get_open_file_name_selected_filter():
"""
Test that `getOpenFileName` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileName`
"""
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method
# WHEN: Calling FileDialog.getOpenFileName, and `QFileDialog.getOpenFileName` returns a known `selectedFilter`
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName', return_value=('', 'selected filter')):
result = FileDialog.getOpenFileName()
def test_get_open_file_names_selected_filter(self):
"""
Test that `getOpenFileNames` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileNames`
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getOpenFileNames, and `QFileDialog.getOpenFileNames` returns a known
# `selectedFilter`
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], 'selected filter')):
result = FileDialog.getOpenFileNames()
# THEN: getOpenFileName() should return a tuple with the second value set to a the selected filter
assert result[1] == 'selected filter'
# THEN: getOpenFileNames() should return a tuple with the second value set to a the selected filter
assert result[1] == 'selected filter'
def test_get_save_file_name_user_abort(self):
"""
Test that `getSaveFileName` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method
# WHEN: Calling FileDialog.getSaveFileName and the user cancels the dialog (it returns a tuple with the first
# value set as an empty string)
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', '')):
result = FileDialog.getSaveFileName()
def test_get_open_file_names_user_abort():
"""
Test that `getOpenFileNames` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getOpenFileNames and the user cancels the dialog (it returns a tuple with the first
# value set as an empty list)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], '')):
result = FileDialog.getOpenFileNames()
# THEN: First value should be None
assert result[0] is None
# THEN: First value should be an empty list
assert result[0] == []
def test_get_save_file_name_user_accepts(self):
"""
Test that `getSaveFileName` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getSaveFileName method
# WHEN: Calling FileDialog.getSaveFileName, the user chooses a file and accepts the dialog (it returns a
# tuple with the first value set as an string pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName',
return_value=(os.path.join('test', 'chosen.file'), '')):
result = FileDialog.getSaveFileName()
# THEN: getSaveFileName() should return a tuple with the first value set to a Path object pointing to the
# chosen file
assert result[0] == Path('test', 'chosen.file')
def test_get_open_file_names_user_accepts():
"""
Test that `getOpenFileNames` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getOpenFileNames, the user chooses some files and accepts the dialog (it returns a
# tuple with the first value set as a list of strings pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames',
return_value=([os.path.join('test', 'chosen.file1'), os.path.join('test', 'chosen.file2')], '')):
result = FileDialog.getOpenFileNames()
def test_get_save_file_name_selected_filter(self):
"""
Test that `getSaveFileName` does not modify the selectedFilter as returned by `QFileDialog.getSaveFileName`
"""
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method
# WHEN: Calling FileDialog.getSaveFileName, and `QFileDialog.getSaveFileName` returns a known `selectedFilter`
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', 'selected filter')):
result = FileDialog.getSaveFileName()
# THEN: getOpenFileNames() should return a tuple with the first value set to a list of Path objects pointing
# to the chosen file
assert result[0] == [Path('test', 'chosen.file1'), Path('test', 'chosen.file2')]
# THEN: getSaveFileName() should return a tuple with the second value set to a the selected filter
assert result[1] == 'selected filter'
def test_get_open_file_names_selected_filter():
"""
Test that `getOpenFileNames` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileNames`
"""
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getOpenFileNames, and `QFileDialog.getOpenFileNames` returns a known
# `selectedFilter`
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], 'selected filter')):
result = FileDialog.getOpenFileNames()
# THEN: getOpenFileNames() should return a tuple with the second value set to a the selected filter
assert result[1] == 'selected filter'
def test_get_save_file_name_user_abort():
"""
Test that `getSaveFileName` handles the case when the user cancels the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method
# WHEN: Calling FileDialog.getSaveFileName and the user cancels the dialog (it returns a tuple with the first
# value set as an empty string)
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', '')):
result = FileDialog.getSaveFileName()
# THEN: First value should be None
assert result[0] is None
def test_get_save_file_name_user_accepts():
"""
Test that `getSaveFileName` handles the case when the user accepts the dialog
"""
# GIVEN: FileDialog with a mocked QDialog.getSaveFileName method
# WHEN: Calling FileDialog.getSaveFileName, the user chooses a file and accepts the dialog (it returns a
# tuple with the first value set as an string pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName',
return_value=(os.path.join('test', 'chosen.file'), '')):
result = FileDialog.getSaveFileName()
# THEN: getSaveFileName() should return a tuple with the first value set to a Path object pointing to the
# chosen file
assert result[0] == Path('test', 'chosen.file')
def test_get_save_file_name_selected_filter():
"""
Test that `getSaveFileName` does not modify the selectedFilter as returned by `QFileDialog.getSaveFileName`
"""
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method
# WHEN: Calling FileDialog.getSaveFileName, and `QFileDialog.getSaveFileName` returns a known `selectedFilter`
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', 'selected filter')):
result = FileDialog.getSaveFileName()
# THEN: getSaveFileName() should return a tuple with the second value set to a the selected filter
assert result[1] == 'selected filter'

View File

@ -22,8 +22,8 @@
This module contains tests for the openlp.core.widgets.edits module
"""
import os
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, PropertyMock, patch
from openlp.core.widgets.dialogs import FileDialog
@ -31,267 +31,280 @@ from openlp.core.widgets.edits import PathEdit
from openlp.core.widgets.enums import PathEditType
class TestPathEdit(TestCase):
@pytest.fixture()
def widget():
with patch('openlp.core.widgets.edits.PathEdit._setup'):
return PathEdit()
def test_path_getter(widget):
"""
Test the :class:`~openlp.core.widgets.edits.PathEdit` class
Test the `path` property getter.
"""
def setUp(self):
with patch('openlp.core.widgets.edits.PathEdit._setup'):
self.widget = PathEdit()
# GIVEN: An instance of PathEdit with the `_path` instance variable set
widget._path = Path('getter', 'test', 'pat.h')
def test_path_getter(self):
"""
Test the `path` property getter.
"""
# GIVEN: An instance of PathEdit with the `_path` instance variable set
self.widget._path = Path('getter', 'test', 'pat.h')
# WHEN: Reading the `path` property
# THEN: The value that we set should be returned
assert widget.path == Path('getter', 'test', 'pat.h')
# WHEN: Reading the `path` property
# THEN: The value that we set should be returned
assert self.widget.path == Path('getter', 'test', 'pat.h')
def test_path_setter(self):
"""
Test the `path` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `line_edit`
self.widget.line_edit = MagicMock()
def test_path_setter(widget):
"""
Test the `path` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `line_edit`
widget.line_edit = MagicMock()
# WHEN: Writing to the `path` property
self.widget.path = Path('setter', 'test', 'pat.h')
# WHEN: Writing to the `path` property
widget.path = Path('setter', 'test', 'pat.h')
# THEN: The `_path` instance variable should be set with the test data. The `line_edit` text and tooltip
# should have also been set.
assert self.widget._path == Path('setter', 'test', 'pat.h')
self.widget.line_edit.setToolTip.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
self.widget.line_edit.setText.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
# THEN: The `_path` instance variable should be set with the test data. The `line_edit` text and tooltip
# should have also been set.
assert widget._path == Path('setter', 'test', 'pat.h')
widget.line_edit.setToolTip.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
widget.line_edit.setText.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
def test_path_type_getter(self):
"""
Test the `path_type` property getter.
"""
# GIVEN: An instance of PathEdit
# WHEN: Reading the `path` property
# THEN: The default value should be returned
assert self.widget.path_type == PathEditType.Files
def test_path_type_setter(self):
"""
Test the `path_type` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `update_button_tool_tips` method.
with patch.object(self.widget, 'update_button_tool_tips') as mocked_update_button_tool_tips:
def test_path_type_getter(widget):
"""
Test the `path_type` property getter.
"""
# GIVEN: An instance of PathEdit
# WHEN: Reading the `path` property
# THEN: The default value should be returned
assert widget.path_type == PathEditType.Files
# WHEN: Writing to a different value than default to the `path_type` property
self.widget.path_type = PathEditType.Directories
# THEN: The `_path_type` instance variable should be set with the test data and not the default. The
# update_button_tool_tips should have been called.
assert self.widget._path_type == PathEditType.Directories
mocked_update_button_tool_tips.assert_called_once_with()
def test_path_type_setter(widget):
"""
Test the `path_type` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `update_button_tool_tips` method.
with patch.object(widget, 'update_button_tool_tips') as mocked_update_button_tool_tips:
def test_update_button_tool_tips_directories(self):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories`
self.widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock()
self.widget._path_type = PathEditType.Directories
# WHEN: Writing to a different value than default to the `path_type` property
widget.path_type = PathEditType.Directories
# WHEN: Calling update_button_tool_tips
self.widget.update_button_tool_tips()
# THEN: The `_path_type` instance variable should be set with the test data and not the default. The
# update_button_tool_tips should have been called.
assert widget._path_type == PathEditType.Directories
mocked_update_button_tool_tips.assert_called_once_with()
self.widget.browse_button.setToolTip.assert_called_once_with('Browse for directory.')
self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default directory.')
def test_update_button_tool_tips_files(self):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files`
self.widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock()
self.widget._path_type = PathEditType.Files
def test_update_button_tool_tips_directories(widget):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories`
widget.browse_button = MagicMock()
widget.revert_button = MagicMock()
widget._path_type = PathEditType.Directories
# WHEN: Calling update_button_tool_tips
self.widget.update_button_tool_tips()
# WHEN: Calling update_button_tool_tips
widget.update_button_tool_tips()
self.widget.browse_button.setToolTip.assert_called_once_with('Browse for file.')
self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default file.')
widget.browse_button.setToolTip.assert_called_once_with('Browse for directory.')
widget.revert_button.setToolTip.assert_called_once_with('Revert to default directory.')
@patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory', return_value=None)
@patch('openlp.core.widgets.edits.FileDialog.getOpenFileName')
def test_on_browse_button_clicked_directory(self, mocked_get_open_file_name, mocked_get_existing_directory):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory
self.widget._path_type = PathEditType.Directories
self.widget._path = Path('test', 'path')
def test_update_button_tool_tips_files(widget):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files`
widget.browse_button = MagicMock()
widget.revert_button = MagicMock()
widget._path_type = PathEditType.Files
# WHEN: Calling update_button_tool_tips
widget.update_button_tool_tips()
widget.browse_button.setToolTip.assert_called_once_with('Browse for file.')
widget.revert_button.setToolTip.assert_called_once_with('Revert to default file.')
@patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory', return_value=None)
@patch('openlp.core.widgets.edits.FileDialog.getOpenFileName')
def test_on_browse_button_clicked_directory(mocked_get_open_file_name, mocked_get_existing_directory, widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory
widget._path_type = PathEditType.Directories
widget._path = Path('test', 'path')
# WHEN: Calling on_browse_button_clicked
widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the default caption
mocked_get_existing_directory.assert_called_once_with(widget, 'Select Directory',
Path('test', 'path'),
FileDialog.ShowDirsOnly)
assert mocked_get_open_file_name.called is False
def test_on_browse_button_clicked_directory_custom_caption(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories,
and `dialog_caption` is set.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory with `default_caption` set.
with patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory', return_value=None) as \
mocked_get_existing_directory, \
patch('openlp.core.widgets.edits.FileDialog.getOpenFileName') as mocked_get_open_file_name:
widget._path_type = PathEditType.Directories
widget._path = Path('test', 'path')
widget.dialog_caption = 'Directory Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the default caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory',
# THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
mocked_get_existing_directory.assert_called_once_with(widget, 'Directory Caption',
Path('test', 'path'),
FileDialog.ShowDirsOnly)
assert mocked_get_open_file_name.called is False
def test_on_browse_button_clicked_directory_custom_caption(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories,
and `dialog_caption` is set.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory with `default_caption` set.
with patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory', return_value=None) as \
mocked_get_existing_directory, \
patch('openlp.core.widgets.edits.FileDialog.getOpenFileName') as mocked_get_open_file_name:
self.widget._path_type = PathEditType.Directories
self.widget._path = Path('test', 'path')
self.widget.dialog_caption = 'Directory Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
def test_on_browse_button_clicked_file(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
with patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory') as mocked_get_existing_directory, \
patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name:
widget._path_type = PathEditType.Files
widget._path = Path('test', 'pat.h')
# THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption',
Path('test', 'path'),
FileDialog.ShowDirsOnly)
assert mocked_get_open_file_name.called is False
# WHEN: Calling on_browse_button_clicked
widget.on_browse_button_clicked()
def test_on_browse_button_clicked_file(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
with patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory') as mocked_get_existing_directory, \
patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name:
self.widget._path_type = PathEditType.Files
self.widget._path = Path('test', 'pat.h')
# THEN: The FileDialog.getOpenFileName should have been called with the default caption
mocked_get_open_file_name.assert_called_once_with(widget, 'Select File', Path('test', 'pat.h'),
widget.filters)
assert mocked_get_existing_directory.called is False
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the default caption
mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', Path('test', 'pat.h'),
self.widget.filters)
assert mocked_get_existing_directory.called is False
def test_on_browse_button_clicked_file_custom_caption(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files and
`dialog_caption` is set.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
# with `default_caption` set.
with patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory') as mocked_get_existing_directory, \
patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name:
widget._path_type = PathEditType.Files
widget._path = Path('test', 'pat.h')
widget.dialog_caption = 'File Caption'
def test_on_browse_button_clicked_file_custom_caption(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files and
`dialog_caption` is set.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
# with `default_caption` set.
with patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory') as mocked_get_existing_directory, \
patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name:
self.widget._path_type = PathEditType.Files
self.widget._path = Path('test', 'pat.h')
self.widget.dialog_caption = 'File Caption'
# WHEN: Calling on_browse_button_clicked
widget.on_browse_button_clicked()
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the custom caption
mocked_get_open_file_name.assert_called_once_with(widget, 'File Caption', Path('test', 'pat.h'),
widget.filters)
assert mocked_get_existing_directory.called is False
# THEN: The FileDialog.getOpenFileName should have been called with the custom caption
mocked_get_open_file_name.assert_called_once_with(self.widget, 'File Caption', Path('test', 'pat.h'),
self.widget.filters)
assert mocked_get_existing_directory.called is False
def test_on_browse_button_clicked_user_cancels(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user cancels the FileDialog (an
empty str is returned)
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the
# file path.
with patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name:
def test_on_browse_button_clicked_user_cancels(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user cancels the FileDialog (an
empty str is returned)
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the
# file path.
with patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name:
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# WHEN: Calling on_browse_button_clicked
widget.on_browse_button_clicked()
# THEN: normpath should not have been called
assert mocked_get_open_file_name.called is True
# THEN: normpath should not have been called
assert mocked_get_open_file_name.called is True
def test_on_browse_button_clicked_user_accepts(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user accepts the FileDialog (a path
is returned)
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns a str for the file
# path.
with patch('openlp.core.widgets.edits.FileDialog.getOpenFileName',
return_value=(Path('test', 'pat.h'), '')) as mocked_get_open_file_name, \
patch.object(self.widget, 'on_new_path'):
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
def test_on_browse_button_clicked_user_accepts(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user accepts the FileDialog (a path
is returned)
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns a str for the file
# path.
with patch('openlp.core.widgets.edits.FileDialog.getOpenFileName',
return_value=(Path('test', 'pat.h'), '')) as mocked_get_open_file_name, \
patch.object(widget, 'on_new_path'):
# THEN: normpath and `on_new_path` should have been called
assert mocked_get_open_file_name.called is True
assert self.widget.on_new_path.called is True
# WHEN: Calling on_browse_button_clicked
widget.on_browse_button_clicked()
def test_on_revert_button_clicked(self):
"""
Test that the default path is set as the path when the `revert_button.clicked` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `on_new_path`, and the `default_path` set.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
self.widget.default_path = Path('default', 'pat.h')
# THEN: normpath and `on_new_path` should have been called
assert mocked_get_open_file_name.called is True
assert widget.on_new_path.called is True
# WHEN: Calling `on_revert_button_clicked`
self.widget.on_revert_button_clicked()
# THEN: on_new_path should have been called with the default path
mocked_on_new_path.assert_called_once_with(Path('default', 'pat.h'))
def test_on_revert_button_clicked(widget):
"""
Test that the default path is set as the path when the `revert_button.clicked` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `on_new_path`, and the `default_path` set.
with patch.object(widget, 'on_new_path') as mocked_on_new_path:
widget.default_path = Path('default', 'pat.h')
def test_on_line_edit_editing_finished(self):
"""
Test that the new path is set as the path when the `line_edit.editingFinished` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
self.widget.line_edit = MagicMock(**{'text.return_value': 'test/pat.h'})
# WHEN: Calling `on_revert_button_clicked`
widget.on_revert_button_clicked()
# WHEN: Calling `on_line_edit_editing_finished`
self.widget.on_line_edit_editing_finished()
# THEN: on_new_path should have been called with the default path
mocked_on_new_path.assert_called_once_with(Path('default', 'pat.h'))
# THEN: on_new_path should have been called with the path enetered in `line_edit`
mocked_on_new_path.assert_called_once_with(Path('test', 'pat.h'))
def test_on_new_path_no_change(self):
"""
Test `on_new_path` when called with a path that is the same as the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.widgets.edits.PathEdit.path', new_callable=PropertyMock):
self.widget._path = Path('/old', 'test', 'pat.h')
self.widget.pathChanged = MagicMock()
def test_on_line_edit_editing_finished(widget):
"""
Test that the new path is set as the path when the `line_edit.editingFinished` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
with patch.object(widget, 'on_new_path') as mocked_on_new_path:
widget.line_edit = MagicMock(**{'text.return_value': 'test/pat.h'})
# WHEN: Calling `on_new_path` with the same path as the existing path
self.widget.on_new_path(Path('/old', 'test', 'pat.h'))
# WHEN: Calling `on_line_edit_editing_finished`
widget.on_line_edit_editing_finished()
# THEN: The `pathChanged` signal should not be emitted
assert self.widget.pathChanged.emit.called is False
# THEN: on_new_path should have been called with the path enetered in `line_edit`
mocked_on_new_path.assert_called_once_with(Path('test', 'pat.h'))
def test_on_new_path_change(self):
"""
Test `on_new_path` when called with a path that is the different to the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.widgets.edits.PathEdit.path', new_callable=PropertyMock):
self.widget._path = Path('/old', 'test', 'pat.h')
self.widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the a new path
self.widget.on_new_path(Path('/new', 'test', 'pat.h'))
def test_on_new_path_no_change(widget):
"""
Test `on_new_path` when called with a path that is the same as the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.widgets.edits.PathEdit.path', new_callable=PropertyMock):
widget._path = Path('/old', 'test', 'pat.h')
widget.pathChanged = MagicMock()
# THEN: The `pathChanged` signal should be emitted
self.widget.pathChanged.emit.assert_called_once_with(Path('/new', 'test', 'pat.h'))
# WHEN: Calling `on_new_path` with the same path as the existing path
widget.on_new_path(Path('/old', 'test', 'pat.h'))
# THEN: The `pathChanged` signal should not be emitted
assert widget.pathChanged.emit.called is False
def test_on_new_path_change(widget):
"""
Test `on_new_path` when called with a path that is the different to the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.widgets.edits.PathEdit.path', new_callable=PropertyMock):
widget._path = Path('/old', 'test', 'pat.h')
widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the a new path
widget.on_new_path(Path('/new', 'test', 'pat.h'))
# THEN: The `pathChanged` signal should be emitted
widget.pathChanged.emit.assert_called_once_with(Path('/new', 'test', 'pat.h'))

View File

@ -24,7 +24,6 @@ Package to test the openlp.core.widgets.views package.
import os
import pytest
from types import GeneratorType
from unittest import TestCase
from unittest.mock import MagicMock, call, patch
from PyQt5 import QtGui
@ -54,56 +53,53 @@ def preview_widget_env():
viewport_patcher.stop()
class TestHandleMimeDataUrls(TestCase):
def test_files():
"""
Test the :func:`openlp.core.widgets.views.handle_mime_data_urls` function.
Test handle_mime_data_urls when the data points to some files.
"""
def test_files(self):
"""
Test handle_mime_data_urls when the data points to some files.
"""
# GIVEN: Some mocked objects that return True when is_file is called, and some mocked mime data
mocked_path_instance_1 = MagicMock(**{'is_file.return_value': True})
mocked_path_instance_2 = MagicMock(**{'is_file.return_value': True})
with patch('openlp.core.widgets.views.Path',
side_effect=[mocked_path_instance_1, mocked_path_instance_2]) as mocked_path:
mocked_q_url_1 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path', '1.ext')})
mocked_q_url_2 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path', '2.ext')})
mocked_q_mime_data = MagicMock(**{'urls.return_value': [mocked_q_url_1, mocked_q_url_2]})
# GIVEN: Some mocked objects that return True when is_file is called, and some mocked mime data
mocked_path_instance_1 = MagicMock(**{'is_file.return_value': True})
mocked_path_instance_2 = MagicMock(**{'is_file.return_value': True})
with patch('openlp.core.widgets.views.Path',
side_effect=[mocked_path_instance_1, mocked_path_instance_2]) as mocked_path:
mocked_q_url_1 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path', '1.ext')})
mocked_q_url_2 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path', '2.ext')})
mocked_q_mime_data = MagicMock(**{'urls.return_value': [mocked_q_url_1, mocked_q_url_2]})
# WHEN: Calling handle_mime_data_urls with the mocked mime data
result = handle_mime_data_urls(mocked_q_mime_data)
# WHEN: Calling handle_mime_data_urls with the mocked mime data
result = handle_mime_data_urls(mocked_q_mime_data)
# THEN: Both mocked Path objects should be returned in the list
mocked_path.assert_has_calls([call(os.path.join('file', 'test', 'path', '1.ext')),
call(os.path.join('file', 'test', 'path', '2.ext'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2]
# THEN: Both mocked Path objects should be returned in the list
mocked_path.assert_has_calls([call(os.path.join('file', 'test', 'path', '1.ext')),
call(os.path.join('file', 'test', 'path', '2.ext'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2]
def test_directory(self):
"""
Test handle_mime_data_urls when the data points to some directories.
"""
# GIVEN: Some mocked objects that return True when is_dir is called, and some mocked mime data
mocked_path_instance_1 = MagicMock()
mocked_path_instance_2 = MagicMock()
mocked_path_instance_3 = MagicMock()
mocked_path_instance_4 = MagicMock(**{'is_file.return_value': False, 'is_directory.return_value': True,
'iterdir.return_value': [mocked_path_instance_1, mocked_path_instance_2]})
mocked_path_instance_5 = MagicMock(**{'is_file.return_value': False, 'is_directory.return_value': True,
'iterdir.return_value': [mocked_path_instance_3]})
with patch('openlp.core.widgets.views.Path',
side_effect=[mocked_path_instance_4, mocked_path_instance_5]) as mocked_path:
mocked_q_url_1 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path')})
mocked_q_url_2 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path')})
mocked_q_mime_data = MagicMock(**{'urls.return_value': [mocked_q_url_1, mocked_q_url_2]})
# WHEN: Calling handle_mime_data_urls with the mocked mime data
result = handle_mime_data_urls(mocked_q_mime_data)
def test_directory():
"""
Test handle_mime_data_urls when the data points to some directories.
"""
# GIVEN: Some mocked objects that return True when is_dir is called, and some mocked mime data
mocked_path_instance_1 = MagicMock()
mocked_path_instance_2 = MagicMock()
mocked_path_instance_3 = MagicMock()
mocked_path_instance_4 = MagicMock(**{'is_file.return_value': False, 'is_directory.return_value': True,
'iterdir.return_value': [mocked_path_instance_1, mocked_path_instance_2]})
mocked_path_instance_5 = MagicMock(**{'is_file.return_value': False, 'is_directory.return_value': True,
'iterdir.return_value': [mocked_path_instance_3]})
with patch('openlp.core.widgets.views.Path',
side_effect=[mocked_path_instance_4, mocked_path_instance_5]) as mocked_path:
mocked_q_url_1 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path')})
mocked_q_url_2 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path')})
mocked_q_mime_data = MagicMock(**{'urls.return_value': [mocked_q_url_1, mocked_q_url_2]})
# THEN: The three mocked Path file objects should be returned in the list
mocked_path.assert_has_calls([call(os.path.join('file', 'test', 'path')),
call(os.path.join('file', 'test', 'path'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2, mocked_path_instance_3]
# WHEN: Calling handle_mime_data_urls with the mocked mime data
result = handle_mime_data_urls(mocked_q_mime_data)
# THEN: The three mocked Path file objects should be returned in the list
mocked_path.assert_has_calls([call(os.path.join('file', 'test', 'path')),
call(os.path.join('file', 'test', 'path'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2, mocked_path_instance_3]
def test_new_list_preview_widget(preview_widget_env, mock_settings):
@ -578,127 +574,124 @@ def test_autoscroll_normal(mocked_slide_count, mocked_item, mocked_scrollToItem,
mocked_item.assert_has_calls(calls)
class TestListWidgetWithDnD(TestCase):
def test_treewidgetwithdnd_clear():
"""
Test the :class:`~openlp.core.widgets.views.ListWidgetWithDnD` class
Test the clear method when called without any arguments.
"""
def test_clear(self):
"""
Test the clear method when called without any arguments.
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# WHEN: Calling clear with out any arguments
widget.clear()
# WHEN: Calling clear with out any arguments
widget.clear()
# THEN: The results text should be the standard 'no results' text.
assert widget.no_results_text == UiStrings().NoResults
def test_clear_search_while_typing(self):
"""
Test the clear method when called with the search_while_typing argument set to True
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# WHEN: Calling clear with search_while_typing set to True
widget.clear(search_while_typing=True)
# THEN: The results text should be the 'short results' text.
assert widget.no_results_text == UiStrings().ShortResults
def test_all_items_no_list_items(self):
"""
Test allItems when there are no items in the list widget
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
with patch.object(widget, 'count', return_value=0), \
patch.object(widget, 'item', side_effect=lambda x: [][x]):
# WHEN: Calling allItems
result = widget.allItems()
# THEN: An instance of a Generator object should be returned. The generator should not yeild any results
assert isinstance(result, GeneratorType)
assert list(result) == []
def test_all_items_list_items(self):
"""
Test allItems when the list widget contains some items.
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
with patch.object(widget, 'count', return_value=2), \
patch.object(widget, 'item', side_effect=lambda x: [5, 3][x]):
# WHEN: Calling allItems
result = widget.allItems()
# THEN: An instance of a Generator object should be returned. The generator should not yeild any results
assert isinstance(result, GeneratorType)
assert list(result) == [5, 3]
def test_paint_event(self):
"""
Test the paintEvent method when the list is not empty
"""
# GIVEN: An instance of ListWidgetWithDnD with a mocked out count methode which returns 1
# (i.e the list has an item)
widget = ListWidgetWithDnD()
with patch('openlp.core.widgets.views.QtWidgets.QListWidget.paintEvent') as mocked_paint_event, \
patch.object(widget, 'count', return_value=1), \
patch.object(widget, 'viewport') as mocked_viewport:
mocked_event = MagicMock()
# WHEN: Calling paintEvent
widget.paintEvent(mocked_event)
# THEN: The overridden paintEvnet should have been called
mocked_paint_event.assert_called_once_with(mocked_event)
assert mocked_viewport.called is False
def test_paint_event_no_items(self):
"""
Test the paintEvent method when the list is empty
"""
# GIVEN: An instance of ListWidgetWithDnD with a mocked out count methode which returns 0
# (i.e the list is empty)
widget = ListWidgetWithDnD()
mocked_painter_instance = MagicMock()
mocked_qrect = MagicMock()
with patch('openlp.core.widgets.views.QtWidgets.QListWidget.paintEvent') as mocked_paint_event, \
patch.object(widget, 'count', return_value=0), \
patch.object(widget, 'viewport'), \
patch('openlp.core.widgets.views.QtGui.QPainter',
return_value=mocked_painter_instance) as mocked_qpainter, \
patch('openlp.core.widgets.views.QtCore.QRect', return_value=mocked_qrect):
mocked_event = MagicMock()
# WHEN: Calling paintEvent
widget.paintEvent(mocked_event)
# THEN: The overridden paintEvnet should have been called, and some text should be drawn.
mocked_paint_event.assert_called_once_with(mocked_event)
mocked_qpainter.assert_called_once_with(widget.viewport())
mocked_painter_instance.drawText.assert_called_once_with(mocked_qrect, 4100, 'No Search Results')
# THEN: The results text should be the standard 'no results' text.
assert widget.no_results_text == UiStrings().NoResults
class TestTreeWidgetWithDnD(TestCase):
def test_clear_search_while_typing():
"""
Test the :class:`~openlp.core.widgets.views.TreeWidgetWithDnD` class
Test the clear method when called with the search_while_typing argument set to True
"""
def test_constructor(self):
"""
Test the constructor
"""
# GIVEN: A TreeWidgetWithDnD
# WHEN: An instance is created
widget = TreeWidgetWithDnD(name='Test')
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# THEN: It should be initialised correctly
assert widget.mime_data_text == 'Test'
assert widget.allow_internal_dnd is False
assert widget.indentation() == 0
assert widget.isAnimated() is True
# WHEN: Calling clear with search_while_typing set to True
widget.clear(search_while_typing=True)
# THEN: The results text should be the 'short results' text.
assert widget.no_results_text == UiStrings().ShortResults
def test_all_items_no_list_items():
"""
Test allItems when there are no items in the list widget
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
with patch.object(widget, 'count', return_value=0), \
patch.object(widget, 'item', side_effect=lambda x: [][x]):
# WHEN: Calling allItems
result = widget.allItems()
# THEN: An instance of a Generator object should be returned. The generator should not yeild any results
assert isinstance(result, GeneratorType)
assert list(result) == []
def test_all_items_list_items():
"""
Test allItems when the list widget contains some items.
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
with patch.object(widget, 'count', return_value=2), \
patch.object(widget, 'item', side_effect=lambda x: [5, 3][x]):
# WHEN: Calling allItems
result = widget.allItems()
# THEN: An instance of a Generator object should be returned. The generator should not yeild any results
assert isinstance(result, GeneratorType)
assert list(result) == [5, 3]
def test_paint_event():
"""
Test the paintEvent method when the list is not empty
"""
# GIVEN: An instance of ListWidgetWithDnD with a mocked out count methode which returns 1
# (i.e the list has an item)
widget = ListWidgetWithDnD()
with patch('openlp.core.widgets.views.QtWidgets.QListWidget.paintEvent') as mocked_paint_event, \
patch.object(widget, 'count', return_value=1), \
patch.object(widget, 'viewport') as mocked_viewport:
mocked_event = MagicMock()
# WHEN: Calling paintEvent
widget.paintEvent(mocked_event)
# THEN: The overridden paintEvnet should have been called
mocked_paint_event.assert_called_once_with(mocked_event)
assert mocked_viewport.called is False
def test_paint_event_no_items():
"""
Test the paintEvent method when the list is empty
"""
# GIVEN: An instance of ListWidgetWithDnD with a mocked out count methode which returns 0
# (i.e the list is empty)
widget = ListWidgetWithDnD()
mocked_painter_instance = MagicMock()
mocked_qrect = MagicMock()
with patch('openlp.core.widgets.views.QtWidgets.QListWidget.paintEvent') as mocked_paint_event, \
patch.object(widget, 'count', return_value=0), \
patch.object(widget, 'viewport'), \
patch('openlp.core.widgets.views.QtGui.QPainter',
return_value=mocked_painter_instance) as mocked_qpainter, \
patch('openlp.core.widgets.views.QtCore.QRect', return_value=mocked_qrect):
mocked_event = MagicMock()
# WHEN: Calling paintEvent
widget.paintEvent(mocked_event)
# THEN: The overridden paintEvnet should have been called, and some text should be drawn.
mocked_paint_event.assert_called_once_with(mocked_event)
mocked_qpainter.assert_called_once_with(widget.viewport())
mocked_painter_instance.drawText.assert_called_once_with(mocked_qrect, 4100, 'No Search Results')
def test_treewidgetwithdnd_constructor():
"""
Test the constructor
"""
# GIVEN: A TreeWidgetWithDnD
# WHEN: An instance is created
widget = TreeWidgetWithDnD(name='Test')
# THEN: It should be initialised correctly
assert widget.mime_data_text == 'Test'
assert widget.allow_internal_dnd is False
assert widget.indentation() == 0
assert widget.isAnimated() is True