Merge branch 'tests_3' into 'master'

Tests 3 - Finish UI and Widgets

See merge request openlp/openlp!139
This commit is contained in:
Tim Bentley 2020-02-15 21:04:17 +00:00
commit 62b89ecec4
11 changed files with 2846 additions and 2763 deletions

View File

@ -82,11 +82,11 @@ def settings(qapp, registry):
def mock_settings(registry): def mock_settings(registry):
"""A Mock Settings() instance""" """A Mock Settings() instance"""
# Create and register a mock settings object to work with # Create and register a mock settings object to work with
mock_settings = MagicMock() mk_settings = MagicMock()
Registry().register('settings', mock_settings) Registry().register('settings', mk_settings)
yield mock_settings yield mk_settings
Registry().remove('settings') Registry().remove('settings')
del mock_settings del mk_settings
@pytest.fixture(scope='function') @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. Package to test the openlp.core.lib.mediamanageritem package.
""" """
from unittest import TestCase import pytest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.core.lib.mediamanageritem import MediaManagerItem 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): # GIVEN: A setting to enable "Double-click to go live" and a media manager item
""" mocked_settings = MagicMock()
Mock out stuff for all the tests mocked_settings.value.return_value = False
""" Registry().register('settings', mocked_settings)
Registry.create() mmi = MediaManagerItem(None)
self.setup_patcher = patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup') mmi.can_preview = True
self.mocked_setup = self.setup_patcher.start() mmi.can_make_live = True
self.addCleanup(self.setup_patcher.stop) mmi.can_add_to_service = True
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click') # WHEN: on_double_clicked() is called
def test_on_double_clicked(self, mocked_on_preview_click): mmi.on_double_clicked()
"""
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 # THEN: on_preview_click() should have been called
mmi.on_double_clicked() 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): def test_required_icons(media_env):
""" """
Test the default icons for plugins Test the default icons for plugins
""" """
# GIVEN: A MediaManagerItem # GIVEN: A MediaManagerItem
mmi = MediaManagerItem(None) mmi = MediaManagerItem(None)
# WHEN: Object is created # WHEN: Object is created
mmi.required_icons() mmi.required_icons()
# THEN: Default icons should be populated # THEN: Default icons should be populated
assert mmi.has_import_icon is False, 'There should be no import icon by default' 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_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_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.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.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_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_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' 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 @patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
mmi.on_double_clicked() 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 # WHEN: on_double_clicked() is called
mocked_on_live_click.assert_called_with() mmi.on_double_clicked()
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click') # THEN: on_live_click() should have been called
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click') mocked_on_live_click.assert_called_with()
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
# WHEN: on_double_clicked() is called
mmi.on_double_clicked()
# THEN: on_live_click() should have been called @patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
assert 0 == mocked_on_live_click.call_count, 'on_live_click() should not have been called' @patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
assert 0 == mocked_on_preview_click.call_count, 'on_preview_click() should not have been called' 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. Package to test the openlp.core.lib.pluginmanager package.
""" """
from unittest import TestCase import pytest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from openlp.core.state import State from openlp.core.state import State
@ -31,477 +31,491 @@ from openlp.core.lib.plugin import PluginStatus
from openlp.core.lib.pluginmanager import PluginManager 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
""" """
# GIVEN: A plugin manager with some mocked out methods
def setUp(self): manager = PluginManager()
"""
Some pre-test setup required. with patch.object(manager, 'hook_settings_tabs') as mocked_hook_settings_tabs, \
""" patch.object(manager, 'hook_media_manager') as mocked_hook_media_manager, \
self.mocked_main_window = MagicMock() patch.object(manager, 'hook_import_menu') as mocked_hook_import_menu, \
self.mocked_main_window.file_import_menu.return_value = None patch.object(manager, 'hook_export_menu') as mocked_hook_export_menu, \
self.mocked_main_window.file_export_menu.return_value = None patch.object(manager, 'hook_tools_menu') as mocked_hook_tools_menu, \
self.mocked_main_window.file_export_menu.return_value = None patch.object(manager, 'initialise_plugins') as mocked_initialise_plugins:
self.mocked_settings_form = MagicMock() # WHEN: bootstrap_initialise() is called
Registry.create() manager.bootstrap_initialise()
State().load_settings() manager.bootstrap_post_set_up()
Registry().register('service_list', MagicMock())
Registry().register('main_window', self.mocked_main_window) # THEN: The hook methods should have been called
Registry().register('settings_form', self.mocked_settings_form) mocked_hook_settings_tabs.assert_called_with()
Registry().register('settings', MagicMock()) mocked_hook_media_manager.assert_called_with()
mocked_hook_import_menu.assert_called_with()
def test_bootstrap_initialise(self): mocked_hook_export_menu.assert_called_with()
""" mocked_hook_tools_menu.assert_called_with()
Test the PluginManager.bootstrap_initialise() method mocked_initialise_plugins.assert_called_with()
"""
# GIVEN: A plugin manager with some mocked out methods
manager = PluginManager() def test_hook_media_manager_with_disabled_plugin(registry, state):
"""
with patch.object(manager, 'hook_settings_tabs') as mocked_hook_settings_tabs, \ Test running the hook_media_manager() method with a disabled plugin
patch.object(manager, 'hook_media_manager') as mocked_hook_media_manager, \ """
patch.object(manager, 'hook_import_menu') as mocked_hook_import_menu, \ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
patch.object(manager, 'hook_export_menu') as mocked_hook_export_menu, \ mocked_plugin = MagicMock()
patch.object(manager, 'hook_tools_menu') as mocked_hook_tools_menu, \ mocked_plugin.status = PluginStatus.Disabled
patch.object(manager, 'initialise_plugins') as mocked_initialise_plugins: plugin_manager = PluginManager()
# WHEN: bootstrap_initialise() is called Registry().register('mock_plugin', mocked_plugin)
manager.bootstrap_initialise() State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Disabled)
manager.bootstrap_post_set_up() State().flush_preconditions()
# THEN: The hook methods should have been called # WHEN: We run hook_media_manager()
mocked_hook_settings_tabs.assert_called_with() plugin_manager.hook_media_manager()
mocked_hook_media_manager.assert_called_with()
mocked_hook_import_menu.assert_called_with() # THEN: The create_media_manager_item() method should have been called
mocked_hook_export_menu.assert_called_with() assert 0 == mocked_plugin.create_media_manager_item.call_count, \
mocked_hook_tools_menu.assert_called_with() 'The create_media_manager_item() method should not have been called.'
mocked_initialise_plugins.assert_called_with()
def test_hook_media_manager_with_disabled_plugin(self): def test_hook_media_manager_with_active_plugin(registry, state):
""" """
Test running the hook_media_manager() method with a disabled plugin 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 Disabled # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager() plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Disabled) State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions() State().flush_preconditions()
# WHEN: We run hook_media_manager() # WHEN: We run hook_media_manager()
plugin_manager.hook_media_manager() plugin_manager.hook_media_manager()
# THEN: The create_media_manager_item() method should have been called # THEN: The create_media_manager_item() method should have been called
assert 0 == mocked_plugin.create_media_manager_item.call_count, \ mocked_plugin.create_media_manager_item.assert_called_with()
'The create_media_manager_item() method should not have been called.'
def test_hook_media_manager_with_active_plugin(self): def test_hook_settings_tabs_with_disabled_plugin_and_no_form(registry, state):
""" """
Test running the hook_media_manager() method with an active plugin 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 Active # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager() plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions() State().flush_preconditions()
# WHEN: We run hook_media_manager() # WHEN: We run hook_settings_tabs()
plugin_manager.hook_media_manager() plugin_manager.hook_settings_tabs()
# THEN: The create_media_manager_item() method should have been called # THEN: The hook_settings_tabs() method should have been called
mocked_plugin.create_media_manager_item.assert_called_with() 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_no_form(self):
"""
Test running the hook_settings_tabs() method with a disabled plugin and no form def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(registry, state):
""" """
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled Test running the hook_settings_tabs() method with a disabled plugin and a mocked form
mocked_plugin = MagicMock() """
mocked_plugin.status = PluginStatus.Disabled # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
plugin_manager = PluginManager() mocked_plugin = MagicMock()
Registry().register('mock_plugin', mocked_plugin) mocked_plugin.status = PluginStatus.Disabled
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) plugin_manager = PluginManager()
State().flush_preconditions() Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock()
# WHEN: We run hook_settings_tabs() # Replace the autoloaded plugin with the version for testing in real code this would error
plugin_manager.hook_settings_tabs() mocked_settings_form.plugin_manager = plugin_manager
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
# THEN: The hook_settings_tabs() method should have been called State().flush_preconditions()
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.' # WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(self):
""" # THEN: The create_settings_tab() method should not have been called, but the plugins lists should be the same
Test running the hook_settings_tabs() method with a disabled plugin and a mocked form assert 0 == mocked_plugin.create_settings_tab.call_count, \
""" 'The create_media_manager_item() method should not have been called.'
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled assert mocked_settings_form.plugin_manager.plugins == plugin_manager.plugins, \
mocked_plugin = MagicMock() 'The plugins on the settings form should be the same as the plugins in the plugin manager'
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) def test_hook_settings_tabs_with_active_plugin_and_mocked_form(registry, state):
mocked_settings_form = MagicMock() """
# Replace the autoloaded plugin with the version for testing in real code this would error Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
mocked_settings_form.plugin_manager = plugin_manager """
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
State().flush_preconditions() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
# WHEN: We run hook_settings_tabs() plugin_manager = PluginManager()
plugin_manager.hook_settings_tabs() Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock()
# THEN: The create_settings_tab() method should not have been called, but the plugins lists should be the same # Replace the autoloaded plugin with the version for testing in real code this would error
assert 0 == mocked_plugin.create_settings_tab.call_count, \ mocked_settings_form.plugin_manager = plugin_manager
'The create_media_manager_item() method should not have been called.' State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
assert mocked_settings_form.plugin_manager.plugins == plugin_manager.plugins, \ State().flush_preconditions()
'The plugins on the settings form should be the same as the plugins in the plugin manager'
# WHEN: We run hook_settings_tabs()
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(self): plugin_manager.hook_settings_tabs()
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form # 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, \
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active 'The create_media_manager_item() method should have been called once.'
mocked_plugin = MagicMock() assert plugin_manager.plugins == mocked_settings_form.plugin_manager.plugins, \
mocked_plugin.status = PluginStatus.Active 'The plugins on the settings form should be the same as the plugins in the plugin manager'
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
mocked_settings_form = MagicMock() def test_hook_settings_tabs_with_active_plugin_and_no_form(plugin_manager_env):
# Replace the autoloaded plugin with the version for testing in real code this would error """
mocked_settings_form.plugin_manager = plugin_manager Test running the hook_settings_tabs() method with an active plugin and no settings form
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) """
State().flush_preconditions() # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
# WHEN: We run hook_settings_tabs() mocked_plugin.status = PluginStatus.Active
plugin_manager.hook_settings_tabs() plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
# THEN: The create_media_manager_item() method should have been called with the mocked settings form State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
assert 1 == mocked_plugin.create_settings_tab.call_count, \ State().flush_preconditions()
'The create_media_manager_item() method should have been called once.'
assert plugin_manager.plugins == mocked_settings_form.plugin_manager.plugins, \ # WHEN: We run hook_settings_tabs()
'The plugins on the settings form should be the same as the plugins in the plugin manager' plugin_manager.hook_settings_tabs()
def test_hook_settings_tabs_with_active_plugin_and_no_form(self): # THEN: The create_settings_tab() method should have been called
""" mocked_plugin.create_settings_tab.assert_called_with(Registry().get('settings_form'))
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 def test_hook_import_menu_with_disabled_plugin(registry, state):
mocked_plugin = MagicMock() """
mocked_plugin.status = PluginStatus.Active Test running the hook_import_menu() method with a disabled plugin
plugin_manager = PluginManager() """
Registry().register('mock_plugin', mocked_plugin) # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) mocked_plugin = MagicMock()
State().flush_preconditions() mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
# WHEN: We run hook_settings_tabs() Registry().register('mock_plugin', mocked_plugin)
plugin_manager.hook_settings_tabs() State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
# THEN: The create_settings_tab() method should have been called
mocked_plugin.create_settings_tab.assert_called_with(self.mocked_settings_form) # WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu()
def test_hook_import_menu_with_disabled_plugin(self):
""" # THEN: The create_media_manager_item() method should have been called
Test running the hook_import_menu() method with a disabled plugin assert 0 == mocked_plugin.add_import_menu_item.call_count, \
""" 'The add_import_menu_item() method should not have been called.'
# 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 def test_hook_import_menu_with_active_plugin(plugin_manager_env):
plugin_manager = PluginManager() """
Registry().register('mock_plugin', mocked_plugin) Test running the hook_import_menu() method with an active plugin
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) """
State().flush_preconditions() # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
# WHEN: We run hook_import_menu() mocked_plugin.status = PluginStatus.Active
plugin_manager.hook_import_menu() plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
# THEN: The create_media_manager_item() method should have been called State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
assert 0 == mocked_plugin.add_import_menu_item.call_count, \ State().flush_preconditions()
'The add_import_menu_item() method should not have been called.'
# WHEN: We run hook_import_menu()
def test_hook_import_menu_with_active_plugin(self): plugin_manager.hook_import_menu()
"""
Test running the hook_import_menu() method with an active plugin # 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)
# 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 def test_hook_export_menu_with_disabled_plugin(registry, state):
plugin_manager = PluginManager() """
Registry().register('mock_plugin', mocked_plugin) Test running the hook_export_menu() method with a disabled plugin
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) """
State().flush_preconditions() # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
# WHEN: We run hook_import_menu() mocked_plugin.status = PluginStatus.Disabled
plugin_manager.hook_import_menu() plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
# THEN: The add_import_menu_item() method should have been called State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
mocked_plugin.add_import_menu_item.assert_called_with(self.mocked_main_window.file_import_menu) State().flush_preconditions()
def test_hook_export_menu_with_disabled_plugin(self): # WHEN: We run hook_export_menu()
""" plugin_manager.hook_export_menu()
Test running the hook_export_menu() method with a disabled plugin
""" # THEN: The add_export_menu_item() method should not have been called
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled assert 0 == mocked_plugin.add_export_menu_item.call_count, \
mocked_plugin = MagicMock() 'The add_export_menu_item() method should not have been called.'
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) def test_hook_export_menu_with_active_plugin(plugin_manager_env):
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) """
State().flush_preconditions() Test running the hook_export_menu() method with an active plugin
"""
# WHEN: We run hook_export_menu() # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
plugin_manager.hook_export_menu() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
# THEN: The add_export_menu_item() method should not have been called plugin_manager = PluginManager()
assert 0 == mocked_plugin.add_export_menu_item.call_count, \ Registry().register('mock_plugin', mocked_plugin)
'The add_export_menu_item() method should not have been called.' State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
def test_hook_export_menu_with_active_plugin(self):
""" # WHEN: We run hook_export_menu()
Test running the hook_export_menu() method with an active plugin plugin_manager.hook_export_menu()
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active # THEN: The add_export_menu_item() method should have been called
mocked_plugin = MagicMock() mocked_plugin.add_export_menu_item.assert_called_with(Registry().get('main_window').file_export_menu)
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) def test_hook_upgrade_plugin_settings_with_disabled_plugin(registry, state):
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) """
State().flush_preconditions() Test running the hook_upgrade_plugin_settings() method with a disabled plugin
"""
# WHEN: We run hook_export_menu() # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
plugin_manager.hook_export_menu() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled
# THEN: The add_export_menu_item() method should have been called plugin_manager = PluginManager()
mocked_plugin.add_export_menu_item.assert_called_with(self.mocked_main_window.file_export_menu) Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
def test_hook_upgrade_plugin_settings_with_disabled_plugin(self): State().flush_preconditions()
""" settings = Settings()
Test running the hook_upgrade_plugin_settings() method with a disabled plugin
""" # WHEN: We run hook_upgrade_plugin_settings()
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled plugin_manager.hook_upgrade_plugin_settings(settings)
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled # THEN: The upgrade_settings() method should not have been called
plugin_manager = PluginManager() assert 0 == mocked_plugin.upgrade_settings.call_count, \
Registry().register('mock_plugin', mocked_plugin) 'The upgrade_settings() method should not have been called.'
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
settings = Settings() def test_hook_upgrade_plugin_settings_with_active_plugin(registry, state):
"""
# WHEN: We run hook_upgrade_plugin_settings() Test running the hook_upgrade_plugin_settings() method with an active plugin
plugin_manager.hook_upgrade_plugin_settings(settings) """
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
# THEN: The upgrade_settings() method should not have been called mocked_plugin = MagicMock()
assert 0 == mocked_plugin.upgrade_settings.call_count, \ mocked_plugin.status = PluginStatus.Active
'The upgrade_settings() method should not have been called.' plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin)
def test_hook_upgrade_plugin_settings_with_active_plugin(self): State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
""" State().flush_preconditions()
Test running the hook_upgrade_plugin_settings() method with an active plugin settings = Settings()
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active # WHEN: We run hook_upgrade_plugin_settings()
mocked_plugin = MagicMock() plugin_manager.hook_upgrade_plugin_settings(settings)
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager() # THEN: The add_export_menu_item() method should have been called
Registry().register('mock_plugin', mocked_plugin) mocked_plugin.upgrade_settings.assert_called_with(settings)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions()
settings = Settings() def test_hook_tools_menu_with_disabled_plugin(registry, state):
"""
# WHEN: We run hook_upgrade_plugin_settings() Test running the hook_tools_menu() method with a disabled plugin
plugin_manager.hook_upgrade_plugin_settings(settings) """
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
# THEN: The add_export_menu_item() method should have been called mocked_plugin = MagicMock()
mocked_plugin.upgrade_settings.assert_called_with(settings) mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager()
def test_hook_tools_menu_with_disabled_plugin(self): Registry().register('mock_plugin', mocked_plugin)
""" State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
Test running the hook_tools_menu() method with a disabled plugin State().flush_preconditions()
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled # WHEN: We run hook_tools_menu()
mocked_plugin = MagicMock() plugin_manager.hook_tools_menu()
mocked_plugin.status = PluginStatus.Disabled
plugin_manager = PluginManager() # THEN: The add_tools_menu_item() method should have been called
Registry().register('mock_plugin', mocked_plugin) assert 0 == mocked_plugin.add_tools_menu_item.call_count, \
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) 'The add_tools_menu_item() method should not have been called.'
State().flush_preconditions()
# WHEN: We run hook_tools_menu() def test_hook_tools_menu_with_active_plugin(plugin_manager_env):
plugin_manager.hook_tools_menu() """
Test running the hook_tools_menu() method with an active plugin
# THEN: The add_tools_menu_item() method should have been called """
assert 0 == mocked_plugin.add_tools_menu_item.call_count, \ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
'The add_tools_menu_item() method should not have been called.' mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
def test_hook_tools_menu_with_active_plugin(self): plugin_manager = PluginManager()
""" Registry().register('mock_plugin', mocked_plugin)
Test running the hook_tools_menu() method with an active plugin State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
""" State().flush_preconditions()
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock() # WHEN: We run hook_tools_menu()
mocked_plugin.status = PluginStatus.Active plugin_manager.hook_tools_menu()
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) # THEN: The add_tools_menu_item() method should have been called
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) mocked_plugin.add_tools_menu_item.assert_called_with(Registry().get('main_window').tools_menu)
State().flush_preconditions()
# WHEN: We run hook_tools_menu() def test_initialise_plugins_with_disabled_plugin(registry, state):
plugin_manager.hook_tools_menu() """
Test running the initialise_plugins() method with a disabled plugin
# 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) # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock()
def test_initialise_plugins_with_disabled_plugin(self): mocked_plugin.status = PluginStatus.Disabled
""" mocked_plugin.is_active.return_value = False
Test running the initialise_plugins() method with a disabled plugin plugin_manager = PluginManager()
""" Registry().register('mock_plugin', mocked_plugin)
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
mocked_plugin = MagicMock() State().flush_preconditions()
mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False # WHEN: We run initialise_plugins()
plugin_manager = PluginManager() plugin_manager.initialise_plugins()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) # THEN: The is_active() method should have been called, and initialise() method should NOT have been called
State().flush_preconditions() mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.'
# WHEN: We run initialise_plugins()
plugin_manager.initialise_plugins()
def test_initialise_plugins_with_active_plugin(registry, state):
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called """
mocked_plugin.is_active.assert_called_with() Test running the initialise_plugins() method with an active plugin
assert 0 == mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.' """
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
def test_initialise_plugins_with_active_plugin(self): mocked_plugin = MagicMock()
""" mocked_plugin.status = PluginStatus.Active
Test running the initialise_plugins() method with an active plugin mocked_plugin.is_active.return_value = True
""" plugin_manager = PluginManager()
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active Registry().register('mock_plugin', mocked_plugin)
mocked_plugin = MagicMock() State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
mocked_plugin.status = PluginStatus.Active State().flush_preconditions()
mocked_plugin.is_active.return_value = True
plugin_manager = PluginManager() # WHEN: We run initialise_plugins()
Registry().register('mock_plugin', mocked_plugin) plugin_manager.initialise_plugins()
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions() # THEN: The is_active() and initialise() methods should have been called
mocked_plugin.is_active.assert_called_with()
# WHEN: We run initialise_plugins() mocked_plugin.initialise.assert_called_with()
plugin_manager.initialise_plugins()
# THEN: The is_active() and initialise() methods should have been called def test_finalise_plugins_with_disabled_plugin(registry, state):
mocked_plugin.is_active.assert_called_with() """
mocked_plugin.initialise.assert_called_with() Test running the finalise_plugins() method with a disabled plugin
"""
def test_finalise_plugins_with_disabled_plugin(self): # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
""" mocked_plugin = MagicMock()
Test running the finalise_plugins() method with a disabled plugin mocked_plugin.status = PluginStatus.Disabled
""" mocked_plugin.is_active.return_value = False
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled plugin_manager = PluginManager()
mocked_plugin = MagicMock() Registry().register('mock_plugin', mocked_plugin)
mocked_plugin.status = PluginStatus.Disabled State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
mocked_plugin.is_active.return_value = False State().flush_preconditions()
plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) # WHEN: We run finalise_plugins()
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) plugin_manager.finalise_plugins()
State().flush_preconditions()
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called
# WHEN: We run finalise_plugins() mocked_plugin.is_active.assert_called_with()
plugin_manager.finalise_plugins() assert 0 == mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.'
# THEN: The is_active() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with() def test_finalise_plugins_with_active_plugin(registry, state):
assert 0 == mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.' """
Test running the finalise_plugins() method with an active plugin
def test_finalise_plugins_with_active_plugin(self): """
""" # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
Test running the finalise_plugins() method with an active plugin mocked_plugin = MagicMock()
""" mocked_plugin.status = PluginStatus.Active
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active mocked_plugin.is_active.return_value = True
mocked_plugin = MagicMock() plugin_manager = PluginManager()
mocked_plugin.status = PluginStatus.Active Registry().register('mock_plugin', mocked_plugin)
mocked_plugin.is_active.return_value = True State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
plugin_manager = PluginManager() State().flush_preconditions()
Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) # WHEN: We run finalise_plugins()
State().flush_preconditions() plugin_manager.finalise_plugins()
# WHEN: We run finalise_plugins() # THEN: The is_active() and finalise() methods should have been called
plugin_manager.finalise_plugins() mocked_plugin.is_active.assert_called_with()
mocked_plugin.finalise.assert_called_with()
# 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):
"""
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
""" """
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()
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active mocked_plugin.name = 'Mocked Plugin'
mocked_plugin = MagicMock() plugin_manager = PluginManager()
mocked_plugin.name = 'Mocked Plugin' Registry().register('mock_plugin', mocked_plugin)
plugin_manager = PluginManager() State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
Registry().register('mock_plugin', mocked_plugin) State().flush_preconditions()
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')
# 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'
# 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):
def test_get_plugin_by_name_exists(self): """
""" Test running the get_plugin_by_name() method to find a plugin that exists
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
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active mocked_plugin = MagicMock()
mocked_plugin = MagicMock() mocked_plugin.name = 'Mocked Plugin'
mocked_plugin.name = 'Mocked Plugin' plugin_manager = PluginManager()
plugin_manager = PluginManager() Registry().register('mock_plugin', mocked_plugin)
Registry().register('mock_plugin', mocked_plugin) State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) State().flush_preconditions()
State().flush_preconditions()
# WHEN: We run finalise_plugins()
# WHEN: We run finalise_plugins() result = plugin_manager.get_plugin_by_name('Mocked Plugin')
result = plugin_manager.get_plugin_by_name('Mocked Plugin')
# THEN: The is_active() and finalise() methods should have been called
# 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'
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): def test_new_service_created_with_disabled_plugin(registry, state):
""" """
Test running the new_service_created() method with a disabled plugin 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 # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled mocked_plugin.status = PluginStatus.Disabled
mocked_plugin.is_active.return_value = False mocked_plugin.is_active.return_value = False
plugin_manager = PluginManager() plugin_manager = PluginManager()
Registry().register('mock_plugin', mocked_plugin) Registry().register('mock_plugin', mocked_plugin)
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
State().flush_preconditions() State().flush_preconditions()
# WHEN: We run finalise_plugins() # WHEN: We run finalise_plugins()
plugin_manager.new_service_created() plugin_manager.new_service_created()
# THEN: The isActive() method should have been called, and initialise() method should NOT have been called # THEN: The isActive() method should have been called, and initialise() method should NOT have been called
mocked_plugin.is_active.assert_called_with() mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.new_service_created.call_count, \ assert 0 == mocked_plugin.new_service_created.call_count, \
'The new_service_created() method should not have been called.' 'The new_service_created() method should not have been called.'
def test_new_service_created_with_active_plugin(self):
""" def test_new_service_created_with_active_plugin(registry, state):
Test running the new_service_created() method with an active plugin """
""" 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() # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin.status = PluginStatus.Active mocked_plugin = MagicMock()
mocked_plugin.is_active.return_value = True mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager() mocked_plugin.is_active.return_value = True
Registry().register('mock_plugin', mocked_plugin) plugin_manager = PluginManager()
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active) Registry().register('mock_plugin', mocked_plugin)
State().flush_preconditions() 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() # 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() # THEN: The is_active() and finalise() methods should have been called
mocked_plugin.new_service_created.assert_called_with() 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. Package to test the openlp.core.lib package.
""" """
import os import os
import pytest
from pathlib import Path from pathlib import Path
from unittest import TestCase
from unittest.mock import Mock, MagicMock, patch from unittest.mock import Mock, MagicMock, patch
from openlp.core.state import State from openlp.core.state import State
from openlp.core.common import ThemeLevel, md5_hash from openlp.core.common import ThemeLevel, md5_hash
from openlp.core.common.enum import ServiceItemType from openlp.core.common.enum import ServiceItemType
from openlp.core.common.registry import Registry 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.formattingtags import FormattingTags
from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem 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 import convert_file_service_item
from tests.utils.constants import RESOURCE_PATH 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'] FOOTER = ['Arky Arky (Unknown)', 'Public Domain', 'CCLI 123456']
TEST_PATH = RESOURCE_PATH / 'service' 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): def side_effect_return_arg(arg1, arg2):
""" return [arg1]
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): mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
return [arg1] mocked_renderer.format_slide = mocked_slide_formater
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg) Registry().register('renderer', mocked_renderer)
mocked_renderer.format_slide = mocked_slide_formater Registry().register('image_manager', MagicMock())
Registry().register('renderer', mocked_renderer)
Registry().register('image_manager', MagicMock())
def tearDown(self):
"""
Clean up
"""
self.destroy_settings()
def test_service_item_basic(self): def test_service_item_basic():
""" """
Test the Service Item - basic test Test the Service Item - basic test
""" """
# GIVEN: A new service item # GIVEN: A new service item
# WHEN: A service item is created (without a plugin) # WHEN: A service item is created (without a plugin)
service_item = ServiceItem(None) service_item = ServiceItem(None)
# THEN: We should get back a valid 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.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' 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 def test_service_item_load_custom_from_service(state_env, settings, service_item_env):
line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj') """
State().add_service("media", 0) Test the Service Item - adding a custom slide from a saved service
State().update_pre_conditions("media", True) """
State().flush_preconditions() # GIVEN: A new service item and a mocked add icon function
service_item.set_from_service(line) service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
FormattingTags.load_tags()
# THEN: We should get back a valid service item # WHEN: We add a custom from a saved serviceand set the media state
assert service_item.is_valid is True, 'The new service item should be valid' line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj')
assert len(service_item.get_frames()) == 2, 'The service item should have 2 display frames' State().add_service("media", 0)
assert len(service_item.capabilities) == 5, 'There should be 5 default custom item capabilities' State().update_pre_conditions("media", True)
State().flush_preconditions()
service_item.set_from_service(line)
# THEN: The frames should also be valid # THEN: We should get back a valid service item
assert 'Test Custom' == service_item.get_display_title(), 'The title should be "Test Custom"' assert service_item.is_valid is True, 'The new service item should be valid'
assert 'Slide 1' == service_item.get_frames()[0]['text'] assert len(service_item.get_frames()) == 2, 'The service item should have 2 display frames'
assert 'Slide 2' == service_item.get_rendered_frame(1) assert len(service_item.capabilities) == 5, 'There should be 5 default custom item capabilities'
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'
def test_service_item_load_image_from_service(self): # THEN: The frames should also be valid
""" assert 'Test Custom' == service_item.get_display_title(), 'The title should be "Test Custom"'
Test the Service Item - adding an image from a saved service assert 'Slide 1' == service_item.get_frames()[0]['text']
""" assert 'Slide 2' == service_item.get_rendered_frame(1)
# GIVEN: A new service item and a mocked add icon function assert 'Slide 1' == service_item.get_frame_title(0), '"Slide 1" has been returned as the title'
image_name = 'image_1.jpg' assert 'Slide 2' == service_item.get_frame_title(1), '"Slide 2" has been returned as the title'
test_file = TEST_PATH / image_name assert '' == service_item.get_frame_title(2), 'Blank has been returned as the title of slide 3'
frame_array = {'path': test_file, 'title': image_name}
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
# WHEN: adding an image from a saved Service and mocked exists def test_service_item_load_image_from_service(state_env, settings):
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_1.osj') """
with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists,\ Test the Service Item - adding an image from a saved service
patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \ """
mocked_get_section_data_path: # GIVEN: A new service item and a mocked add icon function
mocked_exists.return_value = True image_name = 'image_1.jpg'
mocked_get_section_data_path.return_value = Path('/path/') test_file = TEST_PATH / image_name
service_item.set_from_service(line, TEST_PATH) frame_array = {'path': test_file, 'title': image_name}
# THEN: We should get back a valid service item service_item = ServiceItem(None)
assert service_item.is_valid is True, 'The new service item should be valid' service_item.add_icon = MagicMock()
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') # WHEN: adding an image from a saved Service and mocked exists
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') line = convert_file_service_item(TEST_PATH, 'serviceitem_image_1.osj')
def test_service_item_load_image_from_local_service(self, mocked_get_section_data_path, mocked_exists): with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists,\
""" patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \
Test the Service Item - adding an image from a saved local service mocked_get_section_data_path:
"""
# 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 mocked_exists.return_value = True
image_name1 = 'image_1.jpg' mocked_get_section_data_path.return_value = Path('/path/')
image_name2 = 'image_2.jpg' service_item.set_from_service(line, TEST_PATH)
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 # THEN: We should get back a valid service item
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj') assert service_item.is_valid is True, 'The new service item should be valid'
line2 = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj', 1) assert test_file == service_item.get_rendered_frame(0), 'The first frame should match the path to the image'
service_item2.set_from_service(line2) 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) service_item.set_from_service(line)
# THEN: We should get back a valid service item # THEN: We should get back a valid service item with optical media info
assert service_item.is_valid is True, 'The first service item should be valid' assert service_item.is_valid is True, 'The service item should be valid'
assert service_item2.is_valid is True, 'The second service item should be valid' assert service_item.is_capable(ItemCapabilities.IsOptical) is True, 'The item should be Optical'
# These test will fail on windows due to the difference in folder seperators assert service_item.start_time == 654.375, 'Start time should be 654.375'
if os.name != 'nt': assert service_item.end_time == 672.069, 'End time should be 672.069'
assert test_file1 == service_item.get_rendered_frame(0), \ assert service_item.media_length == 17.694, 'Media length should be 17.694'
'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(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 def test_service_item_load_song_and_audio_from_service(state_env, settings, service_item_env):
service_item.add_from_command(TEST_PATH, presentation_name, image, display_title, notes) """
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 # WHEN: We add a custom from a saved service
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command' line = convert_file_service_item(TEST_PATH, 'serviceitem-song-linked-audio.osj')
assert service_item.get_frames()[0] == frame, 'Frames should match' service_item.set_from_service(line, Path('/test/'))
def test_add_from_command_without_display_title_and_notes(self): # THEN: We should get back a valid service item
""" assert service_item.is_valid is True, 'The new service item should be valid'
Test the Service Item - add from command, but not presentation 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'
# GIVEN: A new service item, a mocked icon and image data assert 'Amazing Grace' == service_item.get_display_title(), 'The title should be "Amazing Grace"'
service_item = ServiceItem(None) assert CLEANED_VERSE[:-1] == service_item.get_frames()[0]['text'], \
image_name = 'test.img' 'The returned text matches the input, except the last line feed'
image = MagicMock() assert 'Amazing Grace! how sweet the s' == service_item.get_frame_title(0), \
frame = {'title': image_name, 'image': image, 'path': TEST_PATH, '"Amazing Grace! how sweet the s" has been returned as the title'
'display_title': None, 'notes': None, 'thumbnail': image} 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 def test_service_item_get_theme_data_global_level(settings):
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command' """
assert service_item.get_frames()[0] == frame, 'Frames should match' 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') # WHEN: Get theme data is run
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') theme = service_item.get_theme_data()
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: adding presentation to service_item # THEN: theme should be the global theme
service_item.add_from_command(str(TEST_PATH), presentation_name, thumb, display_title, notes) 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): def test_service_item_get_theme_data_service_level_service_undefined(settings):
""" """
Test the Service Item - load an optical media item Test the service item - get theme data when set to service theme level
""" """
# GIVEN: A new service item and a mocked add icon function # GIVEN: A service item with a theme and theme level set to service
service_item = ServiceItem(None) service_item = ServiceItem(None)
service_item.add_icon = MagicMock() 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 # WHEN: Get theme data is run
line = convert_file_service_item(TEST_PATH, 'serviceitem-dvd.osj') theme = service_item.get_theme_data()
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 with optical media info # THEN: theme should be the global theme
assert service_item.is_valid is True, 'The service item should be valid' assert theme == mocked_theme_manager.global_theme
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_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 def test_service_item_get_theme_data_service_level_service_defined(settings):
line = convert_file_service_item(TEST_PATH, 'serviceitem-song-linked-audio.osj') """
service_item.set_from_service(line, Path('/test/')) 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 # WHEN: Get theme data is run
assert service_item.is_valid is True, 'The new service item should be valid' theme = service_item.get_theme_data()
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'
def test_service_item_get_theme_data_global_level(self): # THEN: theme should be the service theme
""" assert theme == settings.value('servicemanager/service theme')
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)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the global theme def test_service_item_get_theme_data_song_level(settings):
assert theme == mocked_theme_manager.global_theme """
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): # WHEN: Get theme data is run
""" theme = service_item.get_theme_data()
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 # THEN: theme should be the song theme
theme = service_item.get_theme_data() 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): def test_service_item_get_theme_data_song_level_service_fallback(settings):
""" """
Test the service item - get theme data when set to service theme level 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 service """
service_item = ServiceItem(None) # GIVEN: A service item with a theme and theme level set to song
service_item.theme = 'song_theme' service_item = ServiceItem(None)
service_item.from_service = True service_item.from_service = True
mocked_theme_manager = MagicMock() mocked_theme_manager = MagicMock()
mocked_theme_manager.global_theme = 'global_theme' mocked_theme_manager.global_theme = 'global_theme'
mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value) mocked_theme_manager.get_theme_data = Mock(side_effect=lambda value: value)
Registry().register('theme_manager', mocked_theme_manager) Registry().register('theme_manager', mocked_theme_manager)
Settings().setValue('servicemanager/service theme', 'service_theme') settings.setValue('servicemanager/service theme', 'service_theme')
Settings().setValue('themes/theme level', ThemeLevel.Service) settings.setValue('themes/theme level', ThemeLevel.Song)
# WHEN: Get theme data is run # WHEN: Get theme data is run
theme = service_item.get_theme_data() theme = service_item.get_theme_data()
# THEN: theme should be the service theme # THEN: theme should be the serice theme
assert theme == Settings().value('servicemanager/service 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 def test_service_item_get_theme_data_song_level_global_fallback(settings):
theme = service_item.get_theme_data() """
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 # WHEN: Get theme data is run
assert theme == service_item.theme theme = service_item.get_theme_data()
def test_service_item_get_theme_data_song_level_service_fallback(self): # THEN: theme should be the global theme
""" assert theme == mocked_theme_manager.global_theme
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

View File

@ -22,319 +22,324 @@
Package to test the openlp.core.lib.theme package. Package to test the openlp.core.lib.theme package.
""" """
from pathlib import Path from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, TransitionType, TransitionSpeed, Theme 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): # GIVEN: The BackgroundType members
""" background_type_solid = BackgroundType.Solid
Test the to_string method of :class:`BackgroundType` background_type_gradient = BackgroundType.Gradient
""" background_type_image = BackgroundType.Image
# GIVEN: The BackgroundType members background_type_transparent = BackgroundType.Transparent
background_type_solid = BackgroundType.Solid background_type_video = BackgroundType.Video
background_type_gradient = BackgroundType.Gradient background_type_stream = BackgroundType.Stream
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 # WHEN: Calling BackgroundType.to_string
# THEN: The string equivalents should be returned # THEN: The string equivalents should be returned
assert BackgroundType.to_string(background_type_solid) == 'solid' assert BackgroundType.to_string(background_type_solid) == 'solid'
assert BackgroundType.to_string(background_type_gradient) == 'gradient' assert BackgroundType.to_string(background_type_gradient) == 'gradient'
assert BackgroundType.to_string(background_type_image) == 'image' assert BackgroundType.to_string(background_type_image) == 'image'
assert BackgroundType.to_string(background_type_transparent) == 'transparent' assert BackgroundType.to_string(background_type_transparent) == 'transparent'
assert BackgroundType.to_string(background_type_video) == 'video' assert BackgroundType.to_string(background_type_video) == 'video'
assert BackgroundType.to_string(background_type_stream) == 'stream' 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
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): # GIVEN: The BackgroundType strings
""" background_type_solid = 'solid'
Test the Theme constructor background_type_gradient = 'gradient'
""" background_type_image = 'image'
# GIVEN: The Theme class background_type_transparent = 'transparent'
# WHEN: A theme object is created background_type_video = 'video'
default_theme = Theme() background_type_stream = 'stream'
# THEN: The default values should be correct # WHEN: Calling BackgroundType.from_string
self.check_theme(default_theme) # 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):
""" def test_background_gradient_type_to_string():
Test the expand_json method """
""" Test the to_string method of :class:`BackgroundGradientType`
# GIVEN: A Theme object and some JSON to "expand" """
theme = Theme() # GIVEN: The BackgroundGradientType member
theme_json = { background_gradient_horizontal = BackgroundGradientType.Horizontal
'background': { background_gradient_vertical = BackgroundGradientType.Vertical
'border_color': '#000000', background_gradient_circular = BackgroundGradientType.Circular
'type': 'solid' 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': { 'main': {
'vertical_align': 0 'name': 'Arial'
},
'font': {
'footer': {
'bold': False
},
'main': {
'name': 'Arial'
}
} }
} }
}
# WHEN: Theme.expand_json() is run # WHEN: Theme.expand_json() is run
theme.expand_json(theme_json) theme.expand_json(theme_json)
# THEN: The attributes should be set on the object # THEN: The attributes should be set on the object
self.check_theme(theme) 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 def test_extend_image_filename():
theme.extend_image_filename(path) """
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 # WHEN: Theme.extend_image_filename is run
expected_filename = path / 'MyBeautifulTheme' / 'video.mp4' theme.extend_image_filename(path)
assert expected_filename == theme.background_filename
assert 'MyBeautifulTheme' == theme.theme_name
def test_save_retrieve(self): # THEN: The filename of the background should be correct
""" expected_filename = path / 'MyBeautifulTheme' / 'video.mp4'
Load a dummy theme, save it and reload it assert expected_filename == theme.background_filename
""" assert 'MyBeautifulTheme' == theme.theme_name
# 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)
@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 def test_save_retrieve():
theme.set_default_footer() """
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') @patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header(self, mock_geometry): def test_set_default_footer(mock_geometry):
""" """
Test the set_default_header function sets the header back to default Test the set_default_footer function sets the footer back to default
(reletive to the screen) (reletive to the screen)
""" """
# GIVEN: A screen geometry object and a Theme header with a strange area # GIVEN: A screen geometry object and a Theme footer with a strange area
mock_geometry.display_geometry = MagicMock() mock_geometry.display_geometry = MagicMock()
mock_geometry.display_geometry.height.return_value = 600 mock_geometry.display_geometry.height.return_value = 600
mock_geometry.display_geometry.width.return_value = 400 mock_geometry.display_geometry.width.return_value = 400
theme = Theme() theme = Theme()
theme.font_footer_x = 200 theme.font_main_x = 20
theme.font_main_x = 687 theme.font_footer_x = 207
theme.font_main_y = 546 theme.font_footer_y = 25
theme.font_main_width = 345 theme.font_footer_width = 4253
theme.font_main_height = 653 theme.font_footer_height = 5423
# WHEN: set_default_header is called # WHEN: set_default_footer is called
theme.set_default_header() theme.set_default_footer()
# THEN: footer should be set, header should not have changed # 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 == 20, 'header should not have been changed'
assert theme.font_main_x == 10, 'x pos should be reset to default of 10' assert theme.font_footer_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_footer_y == 540, 'y pos should be reset to (screen_size_height * 9 / 10)'
assert theme.font_main_width == 380, 'width should have been reset to (screen_size_width - 20)' assert theme.font_footer_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)' 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 @patch('openlp.core.display.screens.ScreenList.current')
theme.set_default_header_footer() 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 # WHEN: set_default_header is called
assert theme.font_footer_x == 10, 'footer x pos should be reset to default of 10' theme.set_default_header()
assert theme.font_main_x == 10, 'header x pos should be reset to default of 10'
def check_theme(self, theme): # THEN: footer should be set, header should not have changed
assert '#000000' == theme.background_border_color, 'background_border_color should be "#000000"' assert theme.font_footer_x == 200, 'footer should not have been changed'
assert 'solid' == theme.background_type, 'background_type should be "solid"' assert theme.font_main_x == 10, 'x pos should be reset to default of 10'
assert 0 == theme.display_vertical_align, 'display_vertical_align should be 0' assert theme.font_main_y == 0, 'y pos should be reset to 0'
assert theme.font_footer_bold is False, 'font_footer_bold should be False' assert theme.font_main_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert 'Arial' == theme.font_main_name, 'font_main_name should be "Arial"' assert theme.font_main_height == 540, 'height should have been reset to (screen_size_height * 9 / 10)'
assert 53 == len(theme.__dict__), 'The theme should have 53 attributes'
@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. Package to test the openlp.core.lib.ui package.
""" """
from unittest import TestCase
from unittest.mock import MagicMock, call, patch from unittest.mock import MagicMock, call, patch
from PyQt5 import QtCore, QtGui, QtWidgets 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 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): # WHEN: A welcome page has been added to the wizard
""" add_welcome_page(wizard, ':/wizards/wizard_firsttime.bmp')
Test appending a welcome page to a wizard
"""
# GIVEN: A wizard
wizard = QtWidgets.QWizard()
# WHEN: A welcome page has been added to the wizard # THEN: The wizard should have one page with a pixmap.
add_welcome_page(wizard, ':/wizards/wizard_firsttime.bmp') 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): def test_create_button_box():
""" """
Test creating a button box for a dialog Test creating a button box for a dialog
""" """
# GIVEN: 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() dialog = QtWidgets.QDialog()
# WHEN: We create the button box with five buttons # WHEN: An action is created
btnbox = create_button_box(dialog, 'my_btns', ['ok', 'save', 'cancel', 'close', 'defaults']) create_action(dialog, 'my_action')
# THEN: We should get a QDialogButtonBox with five buttons # THEN: setIconVisibleInMenu should be called
assert isinstance(btnbox, QtWidgets.QDialogButtonBox) mocked_action.setIconVisibleInMenu.assert_called_with(False)
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 def test_create_action_not_on_mac_osx():
btnbox = create_button_box(dialog, 'my_btns', None, """
[(QtWidgets.QPushButton('Help'), QtWidgets.QDialogButtonBox.HelpRole)]) Test creating an action on something other than OS X doesn't call the method
# THEN: We should get a QDialogButtonBox with one button with a certain role """
assert isinstance(btnbox, QtWidgets.QDialogButtonBox) # GIVEN: A dialog and a mocked out is_macosx() method to always return True
assert 1 == len(btnbox.buttons()) with patch('openlp.core.lib.ui.is_macosx') as mocked_is_macosx, \
assert QtWidgets.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0]) patch('openlp.core.lib.ui.QtWidgets.QAction') as MockedQAction:
mocked_is_macosx.return_value = False
@patch('openlp.core.lib.ui.Registry') mocked_action = MagicMock()
def test_critical_error_message_box(self, MockRegistry): MockedQAction.return_value = mocked_action
"""
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
dialog = QtWidgets.QDialog() dialog = QtWidgets.QDialog()
# WHEN: We create the combobox # WHEN: An action is created
combo = create_horizontal_adjusting_combo_box(dialog, 'combo1') create_action(dialog, 'my_action')
# THEN: We should get a ComboBox # THEN: setIconVisibleInMenu should not be called
assert isinstance(combo, QtWidgets.QComboBox) assert 0 == mocked_action.setIconVisibleInMenu.call_count, \
assert combo.objectName() == 'combo1' 'setIconVisibleInMenu should not have been called'
assert QtWidgets.QComboBox.AdjustToMinimumContentsLength == combo.sizeAdjustPolicy()
@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 def test_create_checked_disabled_invisible_action():
btn = create_button(dialog, 'my_btn', text='Hello', tooltip='How are you?', enabled=False, role='test', test=1) """
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 # WHEN: We create an action with some properties
assert isinstance(btn, QtWidgets.QPushButton) action = create_action(dialog, 'my_action', checked=True, enabled=False, visible=False)
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(self): # THEN: These properties should be set
""" assert action.isChecked() is True, 'The action should be checked'
Test creating a toolbutton assert action.isEnabled() is False, 'The action should be disabled'
""" assert action.isVisible() is False, 'The action should be invisble'
# 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 def test_create_action_separator():
assert isinstance(btn, QtWidgets.QToolButton) """
assert btn.objectName() == 'my_btn' Test creating an action as separator
assert btn.isEnabled() is True """
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
@patch('openlp.core.lib.ui.log') # WHEN: We create an action as a separator
def test_create_action(self, mocked_log): action = create_action(dialog, 'my_action', separator=True)
"""
Test creating an action
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create an action with some properties # THEN: The action should be a separator
action = create_action(dialog, 'my_action', text='my text', icon=':/wizards/wizard_firsttime.bmp', assert action.isSeparator() is True, 'The action should be a separator'
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(self): def test_create_valign_selection_widgets():
""" """
Test creating an action on OS X calls the correct method Test creating a combo box for valign selection
""" """
# GIVEN: A dialog and a mocked out is_macosx() method to always return True # GIVEN: A dialog
with patch('openlp.core.lib.ui.is_macosx') as mocked_is_macosx, \ dialog = QtWidgets.QDialog()
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: An action is created # WHEN: We create the widgets
create_action(dialog, 'my_action') label, combo = create_valign_selection_widgets(dialog)
# THEN: setIconVisibleInMenu should be called # THEN: We should get a label and a combobox.
mocked_action.setIconVisibleInMenu.assert_called_with(False) 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 def test_find_and_set_in_combo_box():
create_action(dialog, 'my_action') """
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 # WHEN: We call the method with a non-existing value and set_missing=False
assert 0 == mocked_action.setIconVisibleInMenu.call_count, \ find_and_set_in_combo_box(combo, 'Four', set_missing=False)
'setIconVisibleInMenu should not have been called'
def test_create_checked_disabled_invisible_action(self): # THEN: The index should not have changed
""" assert 1 == combo.currentIndex()
Test that an invisible, disabled, checked action is created correctly
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create an action with some properties # WHEN: We call the method with a non-existing value
action = create_action(dialog, 'my_action', checked=True, enabled=False, visible=False) find_and_set_in_combo_box(combo, 'Four')
# THEN: These properties should be set # THEN: The index should have been reset
assert action.isChecked() is True, 'The action should be checked' assert 0 == combo.currentIndex()
assert action.isEnabled() is False, 'The action should be disabled'
assert action.isVisible() is False, 'The action should be invisble'
def test_create_action_separator(self): # WHEN: We call the method with the default behavior
""" find_and_set_in_combo_box(combo, 'Three')
Test creating an action as separator
"""
# GIVEN: A dialog
dialog = QtWidgets.QDialog()
# WHEN: We create an action as a separator # THEN: The index should have changed
action = create_action(dialog, 'my_action', separator=True) 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): def test_create_widget_action():
""" """
Test creating a combo box for valign selection Test creating an action for a widget
""" """
# GIVEN: A dialog # GIVEN: A button
dialog = QtWidgets.QDialog() button = QtWidgets.QPushButton()
# WHEN: We create the widgets # WHEN: We call the function
label, combo = create_valign_selection_widgets(dialog) action = create_widget_action(button, 'some action')
# THEN: We should get a label and a combobox. # THEN: The action should be returned
assert translate('OpenLP.Ui', '&Vertical Align:') == label.text() assert isinstance(action, QtWidgets.QAction)
assert isinstance(combo, QtWidgets.QComboBox) assert action.objectName() == 'some action'
assert combo == label.buddy()
for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]:
assert combo.findText(text) >= 0
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 def test_set_case_insensitive_completer():
find_and_set_in_combo_box(combo, 'Four', set_missing=False) """
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 # WHEN: We call the function
assert 1 == combo.currentIndex() set_case_insensitive_completer(suggestions, line_edit)
# WHEN: We call the method with a non-existing value # THEN: The Combobox should have a completer which is case insensitive
find_and_set_in_combo_box(combo, 'Four') completer = line_edit.completer()
assert isinstance(completer, QtWidgets.QCompleter)
# THEN: The index should have been reset assert completer.caseSensitivity() == QtCore.Qt.CaseInsensitive
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

View File

@ -21,156 +21,165 @@
""" """
This module contains tests for the openlp.core.widgets.buttons module 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 unittest.mock import MagicMock, call, patch
from openlp.core.widgets.buttons import ColorButton 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') # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
def test_constructor(self, mocked_set_tool_tip): # WHEN: The ColorButton object is instantiated
""" mocked_clicked = buttons_env[0]
Test that constructing a ColorButton object works correctly mocked_change_color = buttons_env[3]
""" widget = ColorButton()
# GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal # THEN: The widget __init__ method should have the correct properties and methods called
# WHEN: The ColorButton object is instantiated assert widget.parent is None, 'The parent should be the same as the one that the class was instianted with'
widget = ColorButton() 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') @patch('openlp.core.widgets.buttons.ColorButton.setStyleSheet')
def test_change_color(self, mocked_set_style_sheet): def test_change_color(mocked_set_style_sheet):
""" """
Test that change_color sets the new color and the stylesheet Test that change_color sets the new color and the stylesheet
""" """
self.change_color_patcher.stop() # 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 # WHEN: Changing the color
widget = ColorButton() widget.change_color('#000000')
# WHEN: Changing the color # THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice
widget.change_color('#000000') 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): # WHEN: Accesing the color property
""" value = widget.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'
# WHEN: Accesing the color property # THEN: The value set in _color should be returned
value = widget.color 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(buttons_env):
def test_color_setter(self): """
""" Test that the color property setter method sets the color
Test that the color property setter method sets the color """
""" # GIVEN: An instance of ColorButton, with a mocked __init__
# GIVEN: An instance of ColorButton, with a mocked __init__ mocked_change_color = buttons_env[3]
widget = ColorButton() widget = ColorButton()
# WHEN: Setting the color property # WHEN: Setting the color property
widget.color = '#000000' widget.color = '#000000'
# THEN: Then change_color should have been called with the value we set # THEN: Then change_color should have been called with the value we set
self.mocked_change_color.assert_called_with('#000000') 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 def test_on_clicked_invalid_color(buttons_env):
widget = ColorButton() """
self.mocked_change_color.reset_mock() Test the on_click method when an invalid color has been supplied
self.mocked_color_changed.reset_mock() """
widget._color = '#000000' # 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 # 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}) mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
widget.on_clicked() widget.on_clicked()
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted # 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, \ assert mocked_change_color.called is False, \
'change_color should not have been called with an invalid color' 'change_color should not have been called with an invalid color'
assert self.mocked_color_changed.emit.called is False, \ assert mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted with an invalid color' '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 def test_on_clicked_same_color(buttons_env):
widget = ColorButton() """
self.mocked_change_color.reset_mock() Test the on_click method when a new color has not been chosen
self.mocked_color_changed.reset_mock() """
widget._color = '#000000' # 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 # 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( mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#000000'}) **{'isValid.return_value': True, 'name.return_value': '#000000'})
widget.on_clicked() widget.on_clicked()
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted # 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, \ assert mocked_change_color.called is False, \
'change_color should not have been called when the color has not changed' 'change_color should not have been called when the color has not changed'
assert self.mocked_color_changed.emit.called is False, \ assert mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted when the color has not changed' '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 def test_on_clicked_new_color(buttons_env):
widget = ColorButton() """
self.mocked_change_color.reset_mock() Test the on_click method when a new color has been chosen and is valid
self.mocked_color_changed.reset_mock() """
widget._color = '#000000' # 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 # 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( mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#ffffff'}) **{'isValid.return_value': True, 'name.return_value': '#ffffff'})
widget.on_clicked() widget.on_clicked()
# THEN: change_color should have been called and the colorChanged signal should have been emitted # THEN: change_color should have been called and the colorChanged signal should have been emitted
self.mocked_change_color.assert_called_once_with('#ffffff') mocked_change_color.assert_called_once_with('#ffffff')
self.mocked_color_changed.emit.assert_called_once_with('#ffffff') mocked_color_changed.emit.assert_called_once_with('#ffffff')

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
########################################################################## ##########################################################################
# OpenLP - Open Source Lyrics Projection # # OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- # # ---------------------------------------------------------------------- #
@ -20,7 +19,6 @@
########################################################################## ##########################################################################
import os import os
from pathlib import Path from pathlib import Path
from unittest import TestCase
from unittest.mock import patch from unittest.mock import patch
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
@ -28,181 +26,188 @@ from PyQt5 import QtWidgets
from openlp.core.widgets.dialogs import FileDialog 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): # THEN: The instance should be an instance of QFileDialog
""" assert isinstance(instance, QtWidgets.QFileDialog)
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)
def test_get_existing_directory_user_abort(self): def test_get_existing_directory_user_abort():
""" """
Test that `getExistingDirectory` handles the case when the user cancels the dialog Test that `getExistingDirectory` handles the case when the user cancels the dialog
""" """
# GIVEN: FileDialog with a mocked QDialog.getExistingDirectory method # GIVEN: FileDialog with a mocked QDialog.getExistingDirectory method
# WHEN: Calling FileDialog.getExistingDirectory and the user cancels the dialog returns a empty string # WHEN: Calling FileDialog.getExistingDirectory and the user cancels the dialog returns a empty string
with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=''): with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=''):
result = FileDialog.getExistingDirectory() result = FileDialog.getExistingDirectory()
# THEN: The result should be None # THEN: The result should be None
assert result is 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 def test_get_existing_directory_user_accepts():
assert result == Path('test', 'dir') """
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): # THEN: getExistingDirectory() should return a Path object pointing to the chosen file
""" assert result == Path('test', 'dir')
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:
# 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 def test_get_existing_directory_param_order():
# order """
mocked_get_existing_directory.assert_called_once_with('Parent', 'Caption', os.path.join('test', 'dir'), Test that `getExistingDirectory` passes the parameters to `QFileDialog.getExistingDirectory` in the correct
'Options') 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): # WHEN: Calling the getExistingDirectory method with all parameters set
""" FileDialog.getExistingDirectory('Parent', 'Caption', Path('test', 'dir'), 'Options')
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()
# THEN: First value should be None # THEN: The `QFileDialog.getExistingDirectory` should have been called with the parameters in the correct
assert result[0] is None # 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 def test_get_open_file_name_user_abort():
# chosen file """
assert result[0] == Path('test', 'chosen.file') 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): # THEN: First value should be None
""" assert result[0] is None
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: 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): def test_get_open_file_name_user_accepts():
""" """
Test that `getOpenFileNames` handles the case when the user cancels the dialog Test that `getOpenFileName` handles the case when the user accepts the dialog
""" """
# GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method # GIVEN: FileDialog with a mocked QDialog.getOpenFileName method
# WHEN: Calling FileDialog.getOpenFileNames and the user cancels the dialog (it returns a tuple with the first # WHEN: Calling FileDialog.getOpenFileName, the user chooses a file and accepts the dialog (it returns a
# value set as an empty list) # tuple with the first value set as an string pointing to the file)
with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], '')): with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName',
result = FileDialog.getOpenFileNames() return_value=(os.path.join('test', 'chosen.file'), '')):
result = FileDialog.getOpenFileName()
# THEN: First value should be an empty list # THEN: getOpenFileName() should return a tuple with the first value set to a Path object pointing to the
assert result[0] == [] # 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 def test_get_open_file_name_selected_filter():
# to the chosen file """
assert result[0] == [Path('test', 'chosen.file1'), Path('test', 'chosen.file2')] 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): # THEN: getOpenFileName() should return a tuple with the second value set to a the selected filter
""" assert result[1] == '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(self): def test_get_open_file_names_user_abort():
""" """
Test that `getSaveFileName` handles the case when the user cancels the dialog Test that `getOpenFileNames` handles the case when the user cancels the dialog
""" """
# GIVEN: FileDialog with a mocked QDialog.get_save_file_name method # GIVEN: FileDialog with a mocked QDialog.getOpenFileNames method
# WHEN: Calling FileDialog.getSaveFileName and the user cancels the dialog (it returns a tuple with the first # WHEN: Calling FileDialog.getOpenFileNames and the user cancels the dialog (it returns a tuple with the first
# value set as an empty string) # value set as an empty list)
with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', '')): with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], '')):
result = FileDialog.getSaveFileName() result = FileDialog.getOpenFileNames()
# THEN: First value should be None # THEN: First value should be an empty list
assert result[0] is None 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 def test_get_open_file_names_user_accepts():
# chosen file """
assert result[0] == Path('test', 'chosen.file') 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): # THEN: getOpenFileNames() should return a tuple with the first value set to a list of Path objects pointing
""" # to the chosen file
Test that `getSaveFileName` does not modify the selectedFilter as returned by `QFileDialog.getSaveFileName` assert result[0] == [Path('test', 'chosen.file1'), Path('test', 'chosen.file2')]
"""
# 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' 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 This module contains tests for the openlp.core.widgets.edits module
""" """
import os import os
import pytest
from pathlib import Path from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, PropertyMock, patch from unittest.mock import MagicMock, PropertyMock, patch
from openlp.core.widgets.dialogs import FileDialog 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 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): # GIVEN: An instance of PathEdit with the `_path` instance variable set
with patch('openlp.core.widgets.edits.PathEdit._setup'): widget._path = Path('getter', 'test', 'pat.h')
self.widget = PathEdit()
def test_path_getter(self): # WHEN: Reading the `path` property
""" # THEN: The value that we set should be returned
Test the `path` property getter. assert widget.path == Path('getter', 'test', 'pat.h')
"""
# 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 self.widget.path == Path('getter', 'test', 'pat.h')
def test_path_setter(self): def test_path_setter(widget):
""" """
Test the `path` property setter. Test the `path` property setter.
""" """
# GIVEN: An instance of the PathEdit object and a mocked `line_edit` # GIVEN: An instance of the PathEdit object and a mocked `line_edit`
self.widget.line_edit = MagicMock() widget.line_edit = MagicMock()
# WHEN: Writing to the `path` property # WHEN: Writing to the `path` property
self.widget.path = Path('setter', 'test', 'pat.h') 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 # THEN: The `_path` instance variable should be set with the test data. The `line_edit` text and tooltip
# should have also been set. # should have also been set.
assert self.widget._path == Path('setter', 'test', 'pat.h') assert widget._path == Path('setter', 'test', 'pat.h')
self.widget.line_edit.setToolTip.assert_called_once_with(os.path.join('setter', 'test', 'pat.h')) 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')) 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): def test_path_type_getter(widget):
""" """
Test the `path_type` property setter. Test the `path_type` property getter.
""" """
# GIVEN: An instance of the PathEdit object and a mocked `update_button_tool_tips` method. # GIVEN: An instance of PathEdit
with patch.object(self.widget, 'update_button_tool_tips') as mocked_update_button_tool_tips: # 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 def test_path_type_setter(widget):
# update_button_tool_tips should have been called. """
assert self.widget._path_type == PathEditType.Directories Test the `path_type` property setter.
mocked_update_button_tool_tips.assert_called_once_with() """
# 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): # WHEN: Writing to a different value than default to the `path_type` property
""" widget.path_type = PathEditType.Directories
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: Calling update_button_tool_tips # THEN: The `_path_type` instance variable should be set with the test data and not the default. The
self.widget.update_button_tool_tips() # 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): def test_update_button_tool_tips_directories(widget):
""" """
Test the `update_button_tool_tips` method. Test the `update_button_tool_tips` method.
""" """
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` # GIVEN: An instance of PathEdit with the `path_type` set to `Directories`
self.widget.browse_button = MagicMock() widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock() widget.revert_button = MagicMock()
self.widget._path_type = PathEditType.Files widget._path_type = PathEditType.Directories
# WHEN: Calling update_button_tool_tips # WHEN: Calling update_button_tool_tips
self.widget.update_button_tool_tips() widget.update_button_tool_tips()
self.widget.browse_button.setToolTip.assert_called_once_with('Browse for file.') widget.browse_button.setToolTip.assert_called_once_with('Browse for directory.')
self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default file.') 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_update_button_tool_tips_files(widget):
def test_on_browse_button_clicked_directory(self, mocked_get_open_file_name, mocked_get_existing_directory): """
""" Test the `update_button_tool_tips` method.
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 `Files`
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked widget.browse_button = MagicMock()
# QFileDialog.getExistingDirectory widget.revert_button = MagicMock()
self.widget._path_type = PathEditType.Directories widget._path_type = PathEditType.Files
self.widget._path = Path('test', 'path')
# 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 # 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 # THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory', mocked_get_existing_directory.assert_called_once_with(widget, 'Directory Caption',
Path('test', 'path'), Path('test', 'path'),
FileDialog.ShowDirsOnly) FileDialog.ShowDirsOnly)
assert mocked_get_open_file_name.called is False 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 def test_on_browse_button_clicked_file(widget):
self.widget.on_browse_button_clicked() """
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 # WHEN: Calling on_browse_button_clicked
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption', widget.on_browse_button_clicked()
Path('test', 'path'),
FileDialog.ShowDirsOnly)
assert mocked_get_open_file_name.called is False
def test_on_browse_button_clicked_file(self): # 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'),
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files. widget.filters)
""" assert mocked_get_existing_directory.called is False
# 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')
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the default caption def test_on_browse_button_clicked_file_custom_caption(widget):
mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', Path('test', 'pat.h'), """
self.widget.filters) Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files and
assert mocked_get_existing_directory.called is False `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): # WHEN: Calling on_browse_button_clicked
""" widget.on_browse_button_clicked()
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 # THEN: The FileDialog.getOpenFileName should have been called with the custom caption
self.widget.on_browse_button_clicked() 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): 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 Test the `browse_button` `clicked` handler on_browse_button_clicked when the user cancels the FileDialog (an
empty str is returned) empty str is returned)
""" """
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the # GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the
# file path. # file path.
with patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \ with patch('openlp.core.widgets.edits.FileDialog.getOpenFileName', return_value=(None, '')) as \
mocked_get_open_file_name: mocked_get_open_file_name:
# WHEN: Calling on_browse_button_clicked # WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked() widget.on_browse_button_clicked()
# THEN: normpath should not have been called # THEN: normpath should not have been called
assert mocked_get_open_file_name.called is True 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 def test_on_browse_button_clicked_user_accepts(widget):
self.widget.on_browse_button_clicked() """
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 # WHEN: Calling on_browse_button_clicked
assert mocked_get_open_file_name.called is True widget.on_browse_button_clicked()
assert self.widget.on_new_path.called is True
def test_on_revert_button_clicked(self): # THEN: normpath and `on_new_path` should have been called
""" assert mocked_get_open_file_name.called is True
Test that the default path is set as the path when the `revert_button.clicked` handler is called. assert widget.on_new_path.called is True
"""
# 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')
# WHEN: Calling `on_revert_button_clicked`
self.widget.on_revert_button_clicked()
# THEN: on_new_path should have been called with the default path def test_on_revert_button_clicked(widget):
mocked_on_new_path.assert_called_once_with(Path('default', 'pat.h')) """
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): # WHEN: Calling `on_revert_button_clicked`
""" widget.on_revert_button_clicked()
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_line_edit_editing_finished` # THEN: on_new_path should have been called with the default path
self.widget.on_line_edit_editing_finished() 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): def test_on_line_edit_editing_finished(widget):
""" """
Test `on_new_path` when called with a path that is the same as the existing path. 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 test path and mocked `pathChanged` signal # GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
with patch('openlp.core.widgets.edits.PathEdit.path', new_callable=PropertyMock): with patch.object(widget, 'on_new_path') as mocked_on_new_path:
self.widget._path = Path('/old', 'test', 'pat.h') widget.line_edit = MagicMock(**{'text.return_value': 'test/pat.h'})
self.widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the same path as the existing path # WHEN: Calling `on_line_edit_editing_finished`
self.widget.on_new_path(Path('/old', 'test', 'pat.h')) widget.on_line_edit_editing_finished()
# THEN: The `pathChanged` signal should not be emitted # THEN: on_new_path should have been called with the path enetered in `line_edit`
assert self.widget.pathChanged.emit.called is False 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 def test_on_new_path_no_change(widget):
self.widget.on_new_path(Path('/new', 'test', 'pat.h')) """
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 # WHEN: Calling `on_new_path` with the same path as the existing path
self.widget.pathChanged.emit.assert_called_once_with(Path('/new', 'test', 'pat.h')) 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 os
import pytest import pytest
from types import GeneratorType from types import GeneratorType
from unittest import TestCase
from unittest.mock import MagicMock, call, patch from unittest.mock import MagicMock, call, patch
from PyQt5 import QtGui from PyQt5 import QtGui
@ -54,56 +53,53 @@ def preview_widget_env():
viewport_patcher.stop() 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): # 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})
Test handle_mime_data_urls when the data points to some files. mocked_path_instance_2 = MagicMock(**{'is_file.return_value': True})
""" with patch('openlp.core.widgets.views.Path',
# GIVEN: Some mocked objects that return True when is_file is called, and some mocked mime data side_effect=[mocked_path_instance_1, mocked_path_instance_2]) as mocked_path:
mocked_path_instance_1 = MagicMock(**{'is_file.return_value': True}) mocked_q_url_1 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path', '1.ext')})
mocked_path_instance_2 = MagicMock(**{'is_file.return_value': True}) mocked_q_url_2 = MagicMock(**{'toLocalFile.return_value': os.path.join('file', 'test', 'path', '2.ext')})
with patch('openlp.core.widgets.views.Path', mocked_q_mime_data = MagicMock(**{'urls.return_value': [mocked_q_url_1, mocked_q_url_2]})
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 # WHEN: Calling handle_mime_data_urls with the mocked mime data
result = handle_mime_data_urls(mocked_q_mime_data) result = handle_mime_data_urls(mocked_q_mime_data)
# THEN: Both mocked Path objects should be returned in the list # 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')), mocked_path.assert_has_calls([call(os.path.join('file', 'test', 'path', '1.ext')),
call(os.path.join('file', 'test', 'path', '2.ext'))]) call(os.path.join('file', 'test', 'path', '2.ext'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2] 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 def test_directory():
result = handle_mime_data_urls(mocked_q_mime_data) """
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 # WHEN: Calling handle_mime_data_urls with the mocked mime data
mocked_path.assert_has_calls([call(os.path.join('file', 'test', 'path')), result = handle_mime_data_urls(mocked_q_mime_data)
call(os.path.join('file', 'test', 'path'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2, mocked_path_instance_3] # 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): 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) 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): # GIVEN: An instance of ListWidgetWithDnD
""" widget = ListWidgetWithDnD()
Test the clear method when called without any arguments.
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# WHEN: Calling clear with out any arguments # WHEN: Calling clear with out any arguments
widget.clear() widget.clear()
# THEN: The results text should be the standard 'no results' text. # THEN: The results text should be the standard 'no results' text.
assert widget.no_results_text == UiStrings().NoResults 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')
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): # GIVEN: An instance of ListWidgetWithDnD
""" widget = ListWidgetWithDnD()
Test the constructor
"""
# GIVEN: A TreeWidgetWithDnD
# WHEN: An instance is created
widget = TreeWidgetWithDnD(name='Test')
# THEN: It should be initialised correctly # WHEN: Calling clear with search_while_typing set to True
assert widget.mime_data_text == 'Test' widget.clear(search_while_typing=True)
assert widget.allow_internal_dnd is False
assert widget.indentation() == 0 # THEN: The results text should be the 'short results' text.
assert widget.isAnimated() is True 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