Tests 3 - Finish UI and Widgets

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

View File

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

View File

@ -23,8 +23,8 @@ Package to test the openlp.core.lib package.
"""
import io
import os
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtGui
@ -34,9 +34,7 @@ from openlp.core.lib import DataType, build_icon, check_item_selected, create_se
from tests.utils.constants import RESOURCE_PATH
class TestLib(TestCase):
def test_str_to_bool_with_bool_true(self):
def test_str_to_bool_with_bool_true():
"""
Test the str_to_bool function with boolean input of True
"""
@ -50,7 +48,8 @@ class TestLib(TestCase):
assert isinstance(true_result, bool), 'The result should be a boolean'
assert true_result is True, 'The result should be True'
def test_str_to_bool_with_bool_false(self):
def test_str_to_bool_with_bool_false():
"""
Test the str_to_bool function with boolean input of False
"""
@ -64,7 +63,8 @@ class TestLib(TestCase):
assert isinstance(false_result, bool), 'The result should be a boolean'
assert false_result is False, 'The result should be True'
def test_str_to_bool_with_integer(self):
def test_str_to_bool_with_integer():
"""
Test the str_to_bool function with an integer input
"""
@ -77,7 +77,8 @@ class TestLib(TestCase):
# THEN: we should get back a false
assert int_result is False, 'The result should be False'
def test_str_to_bool_with_invalid_string(self):
def test_str_to_bool_with_invalid_string():
"""
Test the str_to_bool function with an invalid string
"""
@ -90,7 +91,8 @@ class TestLib(TestCase):
# THEN: we should get back a false
assert str_result is False, 'The result should be False'
def test_str_to_bool_with_string_false(self):
def test_str_to_bool_with_string_false():
"""
Test the str_to_bool function with a string saying "false"
"""
@ -103,7 +105,8 @@ class TestLib(TestCase):
# THEN: we should get back a false
assert false_result is False, 'The result should be False'
def test_str_to_bool_with_string_no(self):
def test_str_to_bool_with_string_no():
"""
Test the str_to_bool function with a string saying "NO"
"""
@ -116,7 +119,8 @@ class TestLib(TestCase):
# THEN: we should get back a false
assert str_result is False, 'The result should be False'
def test_str_to_bool_with_true_string_value(self):
def test_str_to_bool_with_true_string_value():
"""
Test the str_to_bool function with a string set to "True"
"""
@ -129,7 +133,8 @@ class TestLib(TestCase):
# THEN: we should get back a true
assert true_result is True, 'The result should be True'
def test_str_to_bool_with_yes_string_value(self):
def test_str_to_bool_with_yes_string_value():
"""
Test the str_to_bool function with a string set to "yes"
"""
@ -142,7 +147,8 @@ class TestLib(TestCase):
# THEN: we should get back a true
assert str_result is True, 'The result should be True'
def test_get_text_file_string_no_file(self):
def test_get_text_file_string_no_file():
"""
Test the get_text_file_string() function when a file does not exist
"""
@ -157,7 +163,8 @@ class TestLib(TestCase):
file_path.is_file.assert_called_with()
assert result is False, 'False should be returned if no file exists'
def test_get_text_file_string_read_error(self):
def test_get_text_file_string_read_error():
"""
Test the get_text_file_string() method when a read error happens
"""
@ -176,13 +183,8 @@ class TestLib(TestCase):
file_path.open.assert_called_once_with('r', encoding='utf-8')
assert result is None, 'None should be returned if the file cannot be opened'
def test_get_text_file_string_decode_error(self):
"""
Test the get_text_file_string() method when the contents cannot be decoded
"""
self.skipTest('Impossible to test due to conflicts when mocking out the "open" function')
def test_build_icon_with_qicon(self):
def test_build_icon_with_qicon():
"""
Test the build_icon() function with a QIcon instance
"""
@ -195,7 +197,8 @@ class TestLib(TestCase):
# THEN: The result should be the same icon as we passed in
assert icon is result, 'The result should be the same icon as we passed in'
def test_build_icon_with_resource(self):
def test_build_icon_with_resource():
"""
Test the build_icon() function with a resource URI
"""
@ -241,7 +244,8 @@ class TestLib(TestCase):
assert mocked_byte_array.toBase64.called is False
assert mocked_byte_array == result, 'The mocked out byte array should be returned'
def test_image_to_byte_base_64(self):
def test_image_to_byte_base_64():
"""
Test the image_to_byte() function
"""
@ -266,7 +270,8 @@ class TestLib(TestCase):
mocked_byte_array.toBase64.assert_called_with()
assert 'base64mock' == result, 'The result should be the return value of the mocked out base64 method'
def test_create_thumb_with_size(self):
def test_create_thumb_with_size():
"""
Test the create_thumb() function with a given size.
"""
@ -300,7 +305,8 @@ class TestLib(TestCase):
except Exception:
pass
def test_create_thumb_no_size(self):
def test_create_thumb_no_size():
"""
Test the create_thumb() function with no size specified.
"""
@ -334,7 +340,8 @@ class TestLib(TestCase):
except Exception:
pass
def test_create_thumb_invalid_size(self):
def test_create_thumb_invalid_size():
"""
Test the create_thumb() function with invalid size specified.
"""
@ -369,7 +376,8 @@ class TestLib(TestCase):
except Exception:
pass
def test_create_thumb_width_only(self):
def test_create_thumb_width_only():
"""
Test the create_thumb() function with a size of only width specified.
"""
@ -404,7 +412,8 @@ class TestLib(TestCase):
except Exception:
pass
def test_create_thumb_height_only(self):
def test_create_thumb_height_only():
"""
Test the create_thumb() function with a size of only height specified.
"""
@ -439,7 +448,8 @@ class TestLib(TestCase):
except Exception:
pass
def test_create_thumb_empty_img(self):
def test_create_thumb_empty_img():
"""
Test the create_thumb() function with a size of only height specified.
"""
@ -487,8 +497,9 @@ class TestLib(TestCase):
except Exception:
pass
@patch('openlp.core.lib.QtWidgets', MagicMock())
def test_check_item_selected_true(self):
@patch('openlp.core.lib.QtWidgets', MagicMock())
def test_check_item_selected_true():
"""
Test that the check_item_selected() function returns True when there are selected indexes
"""
@ -504,7 +515,8 @@ class TestLib(TestCase):
mocked_list_widget.selectedIndexes.assert_called_with()
assert result is True, 'The result should be True'
def test_check_item_selected_false(self):
def test_check_item_selected_false():
"""
Test that the check_item_selected() function returns False when there are no selected indexes.
"""
@ -525,7 +537,8 @@ class TestLib(TestCase):
MockedQtWidgets.QMessageBox.information.assert_called_with('parent', 'mocked translate', 'message')
assert result is False, 'The result should be False'
def test_validate_thumb_file_does_not_exist(self):
def test_validate_thumb_file_does_not_exist():
"""
Test the validate_thumb() function when the thumbnail does not exist
"""
@ -541,7 +554,8 @@ class TestLib(TestCase):
thumb_path.exists.assert_called_once_with()
assert result is False, 'The result should be False'
def test_validate_thumb_file_exists_and_newer(self):
def test_validate_thumb_file_exists_and_newer():
"""
Test the validate_thumb() function when the thumbnail exists and has a newer timestamp than the file
"""
@ -556,7 +570,8 @@ class TestLib(TestCase):
# THEN: `validate_thumb` should return True
assert result is True
def test_validate_thumb_file_exists_and_older(self):
def test_validate_thumb_file_exists_and_older():
"""
Test the validate_thumb() function when the thumbnail exists but is older than the file
"""
@ -571,7 +586,8 @@ class TestLib(TestCase):
thumb_path.stat.assert_called_once_with()
assert result is False, 'The result should be False'
def test_resize_thumb(self):
def test_resize_thumb():
"""
Test the resize_thumb() function
"""
@ -592,7 +608,8 @@ class TestLib(TestCase):
assert wanted_width == result_size.width(), 'The image should have the requested width.'
assert image.pixel(0, 0) == wanted_background_rgb, 'The background should be white.'
def test_resize_thumb_ignoring_aspect_ratio(self):
def test_resize_thumb_ignoring_aspect_ratio():
"""
Test the resize_thumb() function ignoring aspect ratio
"""
@ -613,8 +630,9 @@ class TestLib(TestCase):
assert wanted_width == result_size.width(), 'The image should have the requested width.'
assert image.pixel(0, 0) == wanted_background_rgb, 'The background should be white.'
@patch('openlp.core.lib.QtCore.QLocale.createSeparatedList')
def test_create_separated_list_qlocate(self, mocked_createSeparatedList):
@patch('openlp.core.lib.QtCore.QLocale.createSeparatedList')
def test_create_separated_list_qlocate(mocked_createSeparatedList):
"""
Test the create_separated_list function using the Qt provided method
"""
@ -629,7 +647,8 @@ class TestLib(TestCase):
assert string_result == 'Author 1, Author 2 and Author 3', \
'The string should be "Author 1, Author 2, and Author 3".'
def test_create_separated_list_empty_list(self):
def test_create_separated_list_empty_list():
"""
Test the create_separated_list function with an empty list
"""
@ -642,7 +661,8 @@ class TestLib(TestCase):
# THEN: We shoud have an emptry string.
assert string_result == '', 'The string sould be empty.'
def test_create_separated_list_with_one_item(self):
def test_create_separated_list_with_one_item():
"""
Test the create_separated_list function with a list consisting of only one entry
"""
@ -655,7 +675,8 @@ class TestLib(TestCase):
# THEN: We should have "Author 1"
assert string_result == 'Author 1', 'The string should be "Author 1".'
def test_create_separated_list_with_two_items(self):
def test_create_separated_list_with_two_items():
"""
Test the create_separated_list function with a list of two entries
"""
@ -668,7 +689,8 @@ class TestLib(TestCase):
# THEN: We should have "Author 1 and Author 2"
assert string_result == 'Author 1 and Author 2', 'The string should be "Author 1 and Author 2".'
def test_create_separated_list_with_three_items(self):
def test_create_separated_list_with_three_items():
"""
Test the create_separated_list function with a list of three items
"""
@ -682,7 +704,8 @@ class TestLib(TestCase):
assert string_result == 'Author 1, Author 2 and Author 3', \
'The string should be "Author 1, Author 2, and Author 3".'
def test_read_or_fail_fail(self):
def test_read_or_fail_fail():
"""
Test the :func:`read_or_fail` function when attempting to read more data than the buffer contains.
"""
@ -691,10 +714,11 @@ class TestLib(TestCase):
# WHEN: Attempting to read past the end of the buffer
# THEN: An OSError should be raised.
with self.assertRaises(OSError):
with pytest.raises(OSError):
read_or_fail(test_data, 15)
def test_read_or_fail_success(self):
def test_read_or_fail_success():
"""
Test the :func:`read_or_fail` function when reading data that is in the buffer.
"""
@ -707,7 +731,8 @@ class TestLib(TestCase):
# THEN: The data of the requested length should be returned
assert result == b'test'
def test_read_int_u8_big(self):
def test_read_int_u8_big():
"""
Test the :func:`read_int` function when reading an unsigned 8-bit int using 'big' endianness.
"""
@ -720,7 +745,8 @@ class TestLib(TestCase):
# THEN: The an int should have been returned of the expected value
assert result == 15
def test_read_int_u8_little(self):
def test_read_int_u8_little():
"""
Test the :func:`read_int` function when reading an unsigned 8-bit int using 'little' endianness.
"""
@ -733,7 +759,8 @@ class TestLib(TestCase):
# THEN: The an int should have been returned of the expected value
assert result == 15
def test_read_int_u16_big(self):
def test_read_int_u16_big():
"""
Test the :func:`read_int` function when reading an unsigned 16-bit int using 'big' endianness.
"""
@ -746,7 +773,8 @@ class TestLib(TestCase):
# THEN: The an int should have been returned of the expected value
assert result == 4080
def test_read_int_u16_little(self):
def test_read_int_u16_little():
"""
Test the :func:`read_int` function when reading an unsigned 16-bit int using 'little' endianness.
"""
@ -759,7 +787,8 @@ class TestLib(TestCase):
# THEN: The an int should have been returned of the expected value
assert result == 61455
def test_read_int_u32_big(self):
def test_read_int_u32_big():
"""
Test the :func:`read_int` function when reading an unsigned 32-bit int using 'big' endianness.
"""
@ -772,7 +801,8 @@ class TestLib(TestCase):
# THEN: The an int should have been returned of the expected value
assert result == 267390960
def test_read_int_u32_little(self):
def test_read_int_u32_little():
"""
Test the :func:`read_int` function when reading an unsigned 32-bit int using 'little' endianness.
"""
@ -785,7 +815,8 @@ class TestLib(TestCase):
# THEN: The an int should have been returned of the expected value
assert result == 4027576335
def test_seek_or_fail_default_method(self):
def test_seek_or_fail_default_method():
"""
Test the :func:`seek_or_fail` function when using the default value for the :arg:`how`
"""
@ -798,17 +829,19 @@ class TestLib(TestCase):
# THEN: seek should be called using the os.SEEK_SET constant
mocked_file_like_object.seek.assert_called_once_with(5, os.SEEK_SET)
def test_seek_or_fail_os_end(self):
def test_seek_or_fail_os_end():
"""
Test the :func:`seek_or_fail` function when called with an unsupported seek operation.
"""
# GIVEN: A Mocked object
# WHEN: Attempting to seek relative to the end
# THEN: An NotImplementedError should have been raised
with self.assertRaises(NotImplementedError):
with pytest.raises(NotImplementedError):
seek_or_fail(MagicMock(), 1, os.SEEK_END)
def test_seek_or_fail_valid_seek_set(self):
def test_seek_or_fail_valid_seek_set():
"""
Test that :func:`seek_or_fail` successfully seeks to the correct position.
"""
@ -821,7 +854,8 @@ class TestLib(TestCase):
# THEN: The new position should be 5 from the beginning
assert result == 5
def test_seek_or_fail_invalid_seek_set(self):
def test_seek_or_fail_invalid_seek_set():
"""
Test that :func:`seek_or_fail` raises an exception when seeking past the end.
"""
@ -830,10 +864,11 @@ class TestLib(TestCase):
# WHEN: Attempting to seek from the beginning past the end
# THEN: An OSError should have been raised
with self.assertRaises(OSError):
with pytest.raises(OSError):
seek_or_fail(mocked_file_like_object, 15, os.SEEK_SET)
def test_seek_or_fail_valid_seek_cur(self):
def test_seek_or_fail_valid_seek_cur():
"""
Test that :func:`seek_or_fail` successfully seeks to the correct position.
"""
@ -846,7 +881,8 @@ class TestLib(TestCase):
# THEN: The new position should be 8 (5 from its starting position)
assert result == 8
def test_seek_or_fail_invalid_seek_cur(self):
def test_seek_or_fail_invalid_seek_cur():
"""
Test that :func:`seek_or_fail` raises an exception when seeking past the end.
"""
@ -855,5 +891,5 @@ class TestLib(TestCase):
# WHEN: Attempting to seek from the current position pas the end.
# THEN: An OSError should have been raised
with self.assertRaises(OSError):
with pytest.raises(OSError):
seek_or_fail(mocked_file_like_object, 15, os.SEEK_CUR)

View File

@ -21,29 +21,23 @@
"""
Package to test the openlp.core.lib.mediamanageritem package.
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, patch
from openlp.core.common.registry import Registry
from openlp.core.lib.mediamanageritem import MediaManagerItem
from tests.helpers.testmixin import TestMixin
class TestMediaManagerItem(TestCase, TestMixin):
"""
Test the MediaManagerItem class
"""
def setUp(self):
"""
Mock out stuff for all the tests
"""
Registry.create()
self.setup_patcher = patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup')
self.mocked_setup = self.setup_patcher.start()
self.addCleanup(self.setup_patcher.stop)
@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(self, mocked_on_preview_click):
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked(mocked_on_preview_click, media_env, registry):
"""
Test that when an item is double-clicked then the item is previewed
"""
@ -62,7 +56,8 @@ class TestMediaManagerItem(TestCase, TestMixin):
# 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
"""
@ -80,8 +75,9 @@ class TestMediaManagerItem(TestCase, TestMixin):
assert mmi.can_make_live is True, 'There should be a make live by default'
assert mmi.can_add_to_service is True, 'There should be a add to service icon by default'
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
def test_on_double_clicked_go_live(self, mocked_on_live_click):
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
def test_on_double_clicked_go_live(mocked_on_live_click, media_env, registry):
"""
Test that when "Double-click to go live" is enabled that the item goes live
"""
@ -100,9 +96,10 @@ class TestMediaManagerItem(TestCase, TestMixin):
# THEN: on_live_click() should have been called
mocked_on_live_click.assert_called_with()
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked_single_click_preview(self, mocked_on_preview_click, mocked_on_live_click):
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
@patch('openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def test_on_double_clicked_single_click_preview(mocked_on_preview_click, mocked_on_live_click, media_env, registry):
"""
Test that when "Single-click preview" is enabled then nothing happens on double-click
"""

View File

@ -21,7 +21,7 @@
"""
Package to test the openlp.core.lib.pluginmanager package.
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, patch
from openlp.core.state import State
@ -31,28 +31,20 @@ from openlp.core.lib.plugin import PluginStatus
from openlp.core.lib.pluginmanager import PluginManager
class TestPluginManager(TestCase):
"""
Test the PluginManager class
"""
def setUp(self):
"""
Some pre-test setup required.
"""
self.mocked_main_window = MagicMock()
self.mocked_main_window.file_import_menu.return_value = None
self.mocked_main_window.file_export_menu.return_value = None
self.mocked_main_window.file_export_menu.return_value = None
self.mocked_settings_form = MagicMock()
Registry.create()
State().load_settings()
@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', self.mocked_main_window)
Registry().register('settings_form', self.mocked_settings_form)
Registry().register('main_window', mocked_main_window)
Registry().register('settings_form', mocked_settings_form)
Registry().register('settings', MagicMock())
def test_bootstrap_initialise(self):
def test_bootstrap_initialise(settings, state):
"""
Test the PluginManager.bootstrap_initialise() method
"""
@ -77,7 +69,8 @@ class TestPluginManager(TestCase):
mocked_hook_tools_menu.assert_called_with()
mocked_initialise_plugins.assert_called_with()
def test_hook_media_manager_with_disabled_plugin(self):
def test_hook_media_manager_with_disabled_plugin(registry, state):
"""
Test running the hook_media_manager() method with a disabled plugin
"""
@ -96,7 +89,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.'
def test_hook_media_manager_with_active_plugin(self):
def test_hook_media_manager_with_active_plugin(registry, state):
"""
Test running the hook_media_manager() method with an active plugin
"""
@ -114,7 +108,8 @@ class TestPluginManager(TestCase):
# THEN: The create_media_manager_item() method should have been called
mocked_plugin.create_media_manager_item.assert_called_with()
def test_hook_settings_tabs_with_disabled_plugin_and_no_form(self):
def test_hook_settings_tabs_with_disabled_plugin_and_no_form(registry, state):
"""
Test running the hook_settings_tabs() method with a disabled plugin and no form
"""
@ -133,7 +128,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.create_media_manager_item.call_count, \
'The create_media_manager_item() method should not have been called.'
def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(self):
def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(registry, state):
"""
Test running the hook_settings_tabs() method with a disabled plugin and a mocked form
"""
@ -157,7 +153,8 @@ class TestPluginManager(TestCase):
assert mocked_settings_form.plugin_manager.plugins == plugin_manager.plugins, \
'The plugins on the settings form should be the same as the plugins in the plugin manager'
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(self):
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(registry, state):
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
"""
@ -181,7 +178,8 @@ class TestPluginManager(TestCase):
assert plugin_manager.plugins == mocked_settings_form.plugin_manager.plugins, \
'The plugins on the settings form should be the same as the plugins in the plugin manager'
def test_hook_settings_tabs_with_active_plugin_and_no_form(self):
def test_hook_settings_tabs_with_active_plugin_and_no_form(plugin_manager_env):
"""
Test running the hook_settings_tabs() method with an active plugin and no settings form
"""
@ -197,9 +195,10 @@ class TestPluginManager(TestCase):
plugin_manager.hook_settings_tabs()
# THEN: The create_settings_tab() method should have been called
mocked_plugin.create_settings_tab.assert_called_with(self.mocked_settings_form)
mocked_plugin.create_settings_tab.assert_called_with(Registry().get('settings_form'))
def test_hook_import_menu_with_disabled_plugin(self):
def test_hook_import_menu_with_disabled_plugin(registry, state):
"""
Test running the hook_import_menu() method with a disabled plugin
"""
@ -218,7 +217,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.add_import_menu_item.call_count, \
'The add_import_menu_item() method should not have been called.'
def test_hook_import_menu_with_active_plugin(self):
def test_hook_import_menu_with_active_plugin(plugin_manager_env):
"""
Test running the hook_import_menu() method with an active plugin
"""
@ -234,9 +234,10 @@ class TestPluginManager(TestCase):
plugin_manager.hook_import_menu()
# THEN: The add_import_menu_item() method should have been called
mocked_plugin.add_import_menu_item.assert_called_with(self.mocked_main_window.file_import_menu)
mocked_plugin.add_import_menu_item.assert_called_with(Registry().get('main_window').file_import_menu)
def test_hook_export_menu_with_disabled_plugin(self):
def test_hook_export_menu_with_disabled_plugin(registry, state):
"""
Test running the hook_export_menu() method with a disabled plugin
"""
@ -255,7 +256,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.add_export_menu_item.call_count, \
'The add_export_menu_item() method should not have been called.'
def test_hook_export_menu_with_active_plugin(self):
def test_hook_export_menu_with_active_plugin(plugin_manager_env):
"""
Test running the hook_export_menu() method with an active plugin
"""
@ -271,9 +273,10 @@ class TestPluginManager(TestCase):
plugin_manager.hook_export_menu()
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.add_export_menu_item.assert_called_with(self.mocked_main_window.file_export_menu)
mocked_plugin.add_export_menu_item.assert_called_with(Registry().get('main_window').file_export_menu)
def test_hook_upgrade_plugin_settings_with_disabled_plugin(self):
def test_hook_upgrade_plugin_settings_with_disabled_plugin(registry, state):
"""
Test running the hook_upgrade_plugin_settings() method with a disabled plugin
"""
@ -293,7 +296,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.upgrade_settings.call_count, \
'The upgrade_settings() method should not have been called.'
def test_hook_upgrade_plugin_settings_with_active_plugin(self):
def test_hook_upgrade_plugin_settings_with_active_plugin(registry, state):
"""
Test running the hook_upgrade_plugin_settings() method with an active plugin
"""
@ -312,7 +316,8 @@ class TestPluginManager(TestCase):
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.upgrade_settings.assert_called_with(settings)
def test_hook_tools_menu_with_disabled_plugin(self):
def test_hook_tools_menu_with_disabled_plugin(registry, state):
"""
Test running the hook_tools_menu() method with a disabled plugin
"""
@ -331,7 +336,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.add_tools_menu_item.call_count, \
'The add_tools_menu_item() method should not have been called.'
def test_hook_tools_menu_with_active_plugin(self):
def test_hook_tools_menu_with_active_plugin(plugin_manager_env):
"""
Test running the hook_tools_menu() method with an active plugin
"""
@ -347,9 +353,10 @@ class TestPluginManager(TestCase):
plugin_manager.hook_tools_menu()
# THEN: The add_tools_menu_item() method should have been called
mocked_plugin.add_tools_menu_item.assert_called_with(self.mocked_main_window.tools_menu)
mocked_plugin.add_tools_menu_item.assert_called_with(Registry().get('main_window').tools_menu)
def test_initialise_plugins_with_disabled_plugin(self):
def test_initialise_plugins_with_disabled_plugin(registry, state):
"""
Test running the initialise_plugins() method with a disabled plugin
"""
@ -369,7 +376,8 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.'
def test_initialise_plugins_with_active_plugin(self):
def test_initialise_plugins_with_active_plugin(registry, state):
"""
Test running the initialise_plugins() method with an active plugin
"""
@ -389,7 +397,8 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
mocked_plugin.initialise.assert_called_with()
def test_finalise_plugins_with_disabled_plugin(self):
def test_finalise_plugins_with_disabled_plugin(registry, state):
"""
Test running the finalise_plugins() method with a disabled plugin
"""
@ -409,7 +418,8 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
assert 0 == mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.'
def test_finalise_plugins_with_active_plugin(self):
def test_finalise_plugins_with_active_plugin(registry, state):
"""
Test running the finalise_plugins() method with an active plugin
"""
@ -429,7 +439,8 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
mocked_plugin.finalise.assert_called_with()
def test_get_plugin_by_name_does_not_exist(self):
def test_get_plugin_by_name_does_not_exist(registry, state):
"""
Test running the get_plugin_by_name() method to find a plugin that does not exist
"""
@ -447,7 +458,8 @@ class TestPluginManager(TestCase):
# THEN: The is_active() and finalise() methods should have been called
assert result is None, 'The result for get_plugin_by_name should be None'
def test_get_plugin_by_name_exists(self):
def test_get_plugin_by_name_exists(registry, state):
"""
Test running the get_plugin_by_name() method to find a plugin that exists
"""
@ -465,7 +477,8 @@ class TestPluginManager(TestCase):
# THEN: The is_active() and finalise() methods should have been called
assert result == mocked_plugin, 'The result for get_plugin_by_name should be the mocked plugin'
def test_new_service_created_with_disabled_plugin(self):
def test_new_service_created_with_disabled_plugin(registry, state):
"""
Test running the new_service_created() method with a disabled plugin
"""
@ -486,7 +499,8 @@ class TestPluginManager(TestCase):
assert 0 == mocked_plugin.new_service_created.call_count, \
'The new_service_created() method should not have been called.'
def test_new_service_created_with_active_plugin(self):
def test_new_service_created_with_active_plugin(registry, state):
"""
Test running the new_service_created() method with an active plugin
"""

View File

@ -22,18 +22,16 @@
Package to test the openlp.core.lib package.
"""
import os
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import Mock, MagicMock, patch
from openlp.core.state import State
from openlp.core.common import ThemeLevel, md5_hash
from openlp.core.common.enum import ServiceItemType
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib.formattingtags import FormattingTags
from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem
from tests.helpers.testmixin import TestMixin
from tests.utils import convert_file_service_item
from tests.utils.constants import RESOURCE_PATH
@ -63,39 +61,29 @@ RENDERED_VERSE = 'The Lord said to <span style="-webkit-text-fill-color:red">Noa
FOOTER = ['Arky Arky (Unknown)', 'Public Domain', 'CCLI 123456']
TEST_PATH = RESOURCE_PATH / 'service'
__default_settings__ = {
'songs/enable chords': True,
}
@pytest.fixture()
def state_env(state):
State().add_service("media", 0)
State().update_pre_conditions("media", True)
State().flush_preconditions()
class TestServiceItem(TestCase, TestMixin):
def setUp(self):
"""
Set up the Registry
"""
self.build_settings()
self.setting.extend_default_settings(__default_settings__)
self.setting.setValue('songs/chord notation', 'english')
Registry.create()
Registry().register('settings', self.setting)
@pytest.fixture()
def service_item_env(state):
# Mock the renderer and its format_slide method
mocked_renderer = MagicMock()
def side_effect_return_arg(arg1, arg2):
return [arg1]
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
mocked_renderer.format_slide = mocked_slide_formater
Registry().register('renderer', mocked_renderer)
Registry().register('image_manager', MagicMock())
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
"""
@ -108,7 +96,8 @@ class TestServiceItem(TestCase, TestMixin):
assert service_item.is_valid is True, 'The new service item should be valid'
assert service_item.missing_frames() is True, 'There should not be any frames in the service item'
def test_service_item_load_custom_from_service(self):
def test_service_item_load_custom_from_service(state_env, settings, service_item_env):
"""
Test the Service Item - adding a custom slide from a saved service
"""
@ -137,7 +126,8 @@ class TestServiceItem(TestCase, TestMixin):
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):
def test_service_item_load_image_from_service(state_env, settings):
"""
Test the Service Item - adding an image from a saved service
"""
@ -176,9 +166,10 @@ class TestServiceItem(TestCase, TestMixin):
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(self, mocked_get_section_data_path, mocked_exists):
@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
"""
@ -231,7 +222,8 @@ class TestServiceItem(TestCase, TestMixin):
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):
def test_add_from_command_for_a_presentation():
"""
Test the Service Item - adding a presentation
"""
@ -251,7 +243,8 @@ class TestServiceItem(TestCase, TestMixin):
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(self):
def test_add_from_command_without_display_title_and_notes():
"""
Test the Service Item - add from command, but not presentation
"""
@ -269,9 +262,10 @@ class TestServiceItem(TestCase, TestMixin):
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(self, mocked_get_section_data_path, mocked_image_manager):
@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
"""
@ -298,7 +292,8 @@ class TestServiceItem(TestCase, TestMixin):
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_load_optical_media_from_service(state_env):
"""
Test the Service Item - load an optical media item
"""
@ -319,7 +314,8 @@ class TestServiceItem(TestCase, TestMixin):
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):
def test_service_item_load_song_and_audio_from_service(state_env, settings, service_item_env):
"""
Test the Service Item - adding a song slide from a saved service
"""
@ -346,7 +342,8 @@ class TestServiceItem(TestCase, TestMixin):
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):
def test_service_item_get_theme_data_global_level(settings):
"""
Test the service item - get theme data when set to global theme level
"""
@ -357,8 +354,8 @@ class TestServiceItem(TestCase, TestMixin):
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)
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()
@ -366,7 +363,8 @@ class TestServiceItem(TestCase, TestMixin):
# THEN: theme should be the global theme
assert theme == mocked_theme_manager.global_theme
def test_service_item_get_theme_data_service_level_service_undefined(self):
def test_service_item_get_theme_data_service_level_service_undefined(settings):
"""
Test the service item - get theme data when set to service theme level
"""
@ -377,8 +375,8 @@ class TestServiceItem(TestCase, TestMixin):
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)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Service)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
@ -386,7 +384,8 @@ class TestServiceItem(TestCase, TestMixin):
# 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_service_level_service_defined(settings):
"""
Test the service item - get theme data when set to service theme level
"""
@ -398,16 +397,17 @@ class TestServiceItem(TestCase, TestMixin):
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)
settings.setValue('servicemanager/service theme', 'service_theme')
settings.setValue('themes/theme level', ThemeLevel.Service)
# WHEN: Get theme data is run
theme = service_item.get_theme_data()
# THEN: theme should be the service 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):
def test_service_item_get_theme_data_song_level(settings):
"""
Test the service item - get theme data when set to song theme level
"""
@ -418,8 +418,8 @@ class TestServiceItem(TestCase, TestMixin):
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)
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()
@ -427,7 +427,8 @@ class TestServiceItem(TestCase, TestMixin):
# THEN: theme should be the song theme
assert theme == service_item.theme
def test_service_item_get_theme_data_song_level_service_fallback(self):
def test_service_item_get_theme_data_song_level_service_fallback(settings):
"""
Test the service item - get theme data when set to song theme level
but the song theme doesn't exist
@ -439,16 +440,17 @@ class TestServiceItem(TestCase, TestMixin):
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)
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')
assert theme == settings.value('servicemanager/service theme')
def test_service_item_get_theme_data_song_level_global_fallback(self):
def test_service_item_get_theme_data_song_level_global_fallback(settings):
"""
Test the service item - get theme data when set to song theme level
but the song and service theme don't exist
@ -459,8 +461,8 @@ class TestServiceItem(TestCase, TestMixin):
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)
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()

View File

@ -22,17 +22,12 @@
Package to test the openlp.core.lib.theme package.
"""
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, TransitionType, TransitionSpeed, Theme
class ThemeEnumerationTypes(TestCase):
"""
Test the theme enum methods.
"""
def test_background_type_to_string(self):
def test_background_type_to_string():
"""
Test the to_string method of :class:`BackgroundType`
"""
@ -53,7 +48,8 @@ class ThemeEnumerationTypes(TestCase):
assert BackgroundType.to_string(background_type_video) == 'video'
assert BackgroundType.to_string(background_type_stream) == 'stream'
def test_background_type_from_string(self):
def test_background_type_from_string():
"""
Test the from_string method of :class:`BackgroundType`
"""
@ -74,7 +70,8 @@ class ThemeEnumerationTypes(TestCase):
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):
def test_background_gradient_type_to_string():
"""
Test the to_string method of :class:`BackgroundGradientType`
"""
@ -93,7 +90,8 @@ class ThemeEnumerationTypes(TestCase):
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):
def test_background_gradient_type_from_string():
"""
Test the from_string method of :class:`BackgroundGradientType`
"""
@ -112,7 +110,8 @@ class ThemeEnumerationTypes(TestCase):
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):
def test_transition_type_to_string():
"""
Test the to_string method of :class:`TransitionType`
"""
@ -131,7 +130,8 @@ class ThemeEnumerationTypes(TestCase):
assert TransitionType.to_string(transition_type_concave) == 'concave'
assert TransitionType.to_string(transition_type_zoom) == 'zoom'
def test_transition_type_from_string(self):
def test_transition_type_from_string():
"""
Test the from_string method of :class:`TransitionType`
"""
@ -150,7 +150,8 @@ class ThemeEnumerationTypes(TestCase):
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):
def test_transition_speed_to_string():
"""
Test the to_string method of :class:`TransitionSpeed`
"""
@ -165,7 +166,8 @@ class ThemeEnumerationTypes(TestCase):
assert TransitionSpeed.to_string(transition_speed_fast) == 'fast'
assert TransitionSpeed.to_string(transition_speed_slow) == 'slow'
def test_transition_speed_from_string(self):
def test_transition_speed_from_string():
"""
Test the from_string method of :class:`TransitionSpeed`
"""
@ -181,11 +183,7 @@ class ThemeEnumerationTypes(TestCase):
assert TransitionSpeed.from_string(transition_speed_slow) == TransitionSpeed.Slow
class TestTheme(TestCase):
"""
Test the Theme class
"""
def test_new_theme(self):
def test_new_theme():
"""
Test the Theme constructor
"""
@ -194,9 +192,10 @@ class TestTheme(TestCase):
default_theme = Theme()
# THEN: The default values should be correct
self.check_theme(default_theme)
check_theme(default_theme)
def test_expand_json(self):
def test_expand_json():
"""
Test the expand_json method
"""
@ -224,9 +223,10 @@ class TestTheme(TestCase):
theme.expand_json(theme_json)
# THEN: The attributes should be set on the object
self.check_theme(theme)
check_theme(theme)
def test_extend_image_filename(self):
def test_extend_image_filename():
"""
Test the extend_image_filename method
"""
@ -245,7 +245,8 @@ class TestTheme(TestCase):
assert expected_filename == theme.background_filename
assert 'MyBeautifulTheme' == theme.theme_name
def test_save_retrieve(self):
def test_save_retrieve():
"""
Load a dummy theme, save it and reload it
"""
@ -256,10 +257,11 @@ class TestTheme(TestCase):
save_theme_json = default_theme.export_theme()
lt = Theme()
lt.load_theme(save_theme_json)
self.check_theme(lt)
check_theme(lt)
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_footer(self, mock_geometry):
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_footer(mock_geometry):
"""
Test the set_default_footer function sets the footer back to default
(reletive to the screen)
@ -285,8 +287,9 @@ class TestTheme(TestCase):
assert theme.font_footer_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert theme.font_footer_height == 60, 'height should have been reset to (screen_size_height / 10)'
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header(self, mock_geometry):
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header(mock_geometry):
"""
Test the set_default_header function sets the header back to default
(reletive to the screen)
@ -312,8 +315,9 @@ class TestTheme(TestCase):
assert theme.font_main_width == 380, 'width should have been reset to (screen_size_width - 20)'
assert theme.font_main_height == 540, 'height should have been reset to (screen_size_height * 9 / 10)'
@patch('openlp.core.display.screens.ScreenList.current')
def test_set_default_header_footer(self, mock_geometry):
@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)
@ -331,7 +335,8 @@ class TestTheme(TestCase):
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(self, theme):
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'

View File

@ -21,7 +21,6 @@
"""
Package to test the openlp.core.lib.ui package.
"""
from unittest import TestCase
from unittest.mock import MagicMock, call, patch
from PyQt5 import QtCore, QtGui, QtWidgets
@ -32,12 +31,7 @@ from openlp.core.lib.ui import add_welcome_page, create_action, create_button, c
critical_error_message_box, find_and_set_in_combo_box, set_case_insensitive_completer
class TestUi(TestCase):
"""
Test the functions in the ui module
"""
def test_add_welcome_page(self):
def test_add_welcome_page():
"""
Test appending a welcome page to a wizard
"""
@ -51,7 +45,8 @@ class TestUi(TestCase):
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
"""
@ -79,8 +74,9 @@ class TestUi(TestCase):
assert 1 == len(btnbox.buttons())
assert QtWidgets.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0])
@patch('openlp.core.lib.ui.Registry')
def test_critical_error_message_box(self, MockRegistry):
@patch('openlp.core.lib.ui.Registry')
def test_critical_error_message_box(MockRegistry):
"""
Test the critical_error_message_box() function
"""
@ -91,8 +87,9 @@ class TestUi(TestCase):
# 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):
@patch('openlp.core.lib.ui.QtWidgets.QMessageBox.critical')
def test_critical_error_question(mocked_critical):
"""
Test the critical_error_message_box() function
"""
@ -107,7 +104,8 @@ class TestUi(TestCase):
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No))
def test_create_horizontal_adjusting_combo_box(self):
def test_create_horizontal_adjusting_combo_box():
"""
Test creating a horizontal adjusting combo box
"""
@ -122,8 +120,9 @@ class TestUi(TestCase):
assert combo.objectName() == 'combo1'
assert QtWidgets.QComboBox.AdjustToMinimumContentsLength == combo.sizeAdjustPolicy()
@patch('openlp.core.lib.ui.log')
def test_create_button(self, mocked_log):
@patch('openlp.core.lib.ui.log')
def test_create_button(mocked_log):
"""
Test creating a button
"""
@ -142,7 +141,8 @@ class TestUi(TestCase):
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):
def test_create_tool_button():
"""
Test creating a toolbutton
"""
@ -157,8 +157,9 @@ class TestUi(TestCase):
assert btn.objectName() == 'my_btn'
assert btn.isEnabled() is True
@patch('openlp.core.lib.ui.log')
def test_create_action(self, mocked_log):
@patch('openlp.core.lib.ui.log')
def test_create_action(mocked_log):
"""
Test creating an action
"""
@ -178,7 +179,8 @@ class TestUi(TestCase):
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_action_on_mac_osx():
"""
Test creating an action on OS X calls the correct method
"""
@ -196,7 +198,8 @@ class TestUi(TestCase):
# THEN: setIconVisibleInMenu should be called
mocked_action.setIconVisibleInMenu.assert_called_with(False)
def test_create_action_not_on_mac_osx(self):
def test_create_action_not_on_mac_osx():
"""
Test creating an action on something other than OS X doesn't call the method
"""
@ -215,7 +218,8 @@ class TestUi(TestCase):
assert 0 == mocked_action.setIconVisibleInMenu.call_count, \
'setIconVisibleInMenu should not have been called'
def test_create_checked_disabled_invisible_action(self):
def test_create_checked_disabled_invisible_action():
"""
Test that an invisible, disabled, checked action is created correctly
"""
@ -230,7 +234,8 @@ class TestUi(TestCase):
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):
def test_create_action_separator():
"""
Test creating an action as separator
"""
@ -243,7 +248,8 @@ class TestUi(TestCase):
# 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_valign_selection_widgets():
"""
Test creating a combo box for valign selection
"""
@ -260,7 +266,8 @@ class TestUi(TestCase):
for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]:
assert combo.findText(text) >= 0
def test_find_and_set_in_combo_box(self):
def test_find_and_set_in_combo_box():
"""
Test finding a string in a combo box and setting it as the selected item if present
"""
@ -287,7 +294,8 @@ class TestUi(TestCase):
# THEN: The index should have changed
assert 2 == combo.currentIndex()
def test_create_widget_action(self):
def test_create_widget_action():
"""
Test creating an action for a widget
"""
@ -301,7 +309,8 @@ class TestUi(TestCase):
assert isinstance(action, QtWidgets.QAction)
assert action.objectName() == 'some action'
def test_set_case_insensitive_completer(self):
def test_set_case_insensitive_completer():
"""
Test setting a case insensitive completer on a widget
"""

View File

@ -21,56 +21,56 @@
"""
This module contains tests for the openlp.core.widgets.buttons module
"""
from unittest import TestCase
import pytest
from unittest.mock import MagicMock, call, patch
from openlp.core.widgets.buttons import ColorButton
class TestColorDialog(TestCase):
"""
Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class
"""
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()
@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(self, mocked_set_tool_tip):
@patch('openlp.core.widgets.buttons.ColorButton.setToolTip')
def test_constructor(mocked_set_tool_tip, buttons_env):
"""
Test that constructing a ColorButton object works correctly
"""
# GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
# WHEN: The ColorButton object is instantiated
mocked_clicked = buttons_env[0]
mocked_change_color = buttons_env[3]
widget = ColorButton()
# 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_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)
mocked_clicked.connect.assert_called_once_with(widget.on_clicked)
@patch('openlp.core.widgets.buttons.ColorButton.setStyleSheet')
def test_change_color(self, mocked_set_style_sheet):
@patch('openlp.core.widgets.buttons.ColorButton.setStyleSheet')
def test_change_color(mocked_set_style_sheet):
"""
Test that change_color sets the new color and the stylesheet
"""
self.change_color_patcher.stop()
# GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet
widget = ColorButton()
@ -82,9 +82,8 @@ class TestColorDialog(TestCase):
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(self):
def test_color():
"""
Test that the color property method returns the set color
"""
@ -98,79 +97,89 @@ class TestColorDialog(TestCase):
# THEN: The value set in _color should be returned
assert value == '#000000', 'The value returned should be equal to the one we set'
# @patch('openlp.core.widgets.buttons.ColorButton.__init__', **{'return_value': None})
def test_color_setter(self):
def test_color_setter(buttons_env):
"""
Test that the color property setter method sets the color
"""
# GIVEN: An instance of ColorButton, with a mocked __init__
mocked_change_color = buttons_env[3]
widget = ColorButton()
# WHEN: Setting the color property
widget.color = '#000000'
# 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):
def test_on_clicked_invalid_color(buttons_env):
"""
Test the on_click method when an invalid color has been supplied
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
mocked_color_changed = buttons_env[1]
mocked_qt_widgets = buttons_env[2]
mocked_change_color = buttons_env[3]
widget = ColorButton()
self.mocked_change_color.reset_mock()
self.mocked_color_changed.reset_mock()
mocked_change_color.reset_mock()
mocked_color_changed.reset_mock()
widget._color = '#000000'
# WHEN: The on_clicked method is called, and the color is invalid
self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
widget.on_clicked()
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted
assert self.mocked_change_color.called is False, \
assert mocked_change_color.called is False, \
'change_color should not have been called with an invalid color'
assert self.mocked_color_changed.emit.called is False, \
assert mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted with an invalid color'
def test_on_clicked_same_color(self):
def test_on_clicked_same_color(buttons_env):
"""
Test the on_click method when a new color has not been chosen
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
mocked_color_changed = buttons_env[1]
mocked_qt_widgets = buttons_env[2]
mocked_change_color = buttons_env[3]
widget = ColorButton()
self.mocked_change_color.reset_mock()
self.mocked_color_changed.reset_mock()
mocked_change_color.reset_mock()
mocked_color_changed.reset_mock()
widget._color = '#000000'
# WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color
self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#000000'})
widget.on_clicked()
# THEN: change_color should not have been called and the colorChanged signal should not have been emitted
assert self.mocked_change_color.called is False, \
assert mocked_change_color.called is False, \
'change_color should not have been called when the color has not changed'
assert self.mocked_color_changed.emit.called is False, \
assert mocked_color_changed.emit.called is False, \
'colorChange signal should not have been emitted when the color has not changed'
def test_on_clicked_new_color(self):
def test_on_clicked_new_color(buttons_env):
"""
Test the on_click method when a new color has been chosen and is valid
"""
# GIVEN: An instance of ColorButton, and a set _color attribute
mocked_color_changed = buttons_env[1]
mocked_qt_widgets = buttons_env[2]
mocked_change_color = buttons_env[3]
widget = ColorButton()
self.mocked_change_color.reset_mock()
self.mocked_color_changed.reset_mock()
mocked_change_color.reset_mock()
mocked_color_changed.reset_mock()
widget._color = '#000000'
# WHEN: The on_clicked method is called, and the color is valid, and different to the existing color
self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
**{'isValid.return_value': True, 'name.return_value': '#ffffff'})
widget.on_clicked()
# THEN: change_color should have been called and the colorChanged signal should have been emitted
self.mocked_change_color.assert_called_once_with('#ffffff')
self.mocked_color_changed.emit.assert_called_once_with('#ffffff')
mocked_change_color.assert_called_once_with('#ffffff')
mocked_color_changed.emit.assert_called_once_with('#ffffff')

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
@ -20,7 +19,6 @@
##########################################################################
import os
from pathlib import Path
from unittest import TestCase
from unittest.mock import patch
from PyQt5 import QtWidgets
@ -28,12 +26,7 @@ from PyQt5 import QtWidgets
from openlp.core.widgets.dialogs import FileDialog
class TestFileDialogPatches(TestCase):
"""
Tests for the :mod:`openlp.core.widgets.dialogs` module
"""
def test_file_dialog(self):
def test_file_dialog():
"""
Test that the :class:`FileDialog` instantiates correctly
"""
@ -44,7 +37,8 @@ class TestFileDialogPatches(TestCase):
# 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
"""
@ -56,7 +50,8 @@ class TestFileDialogPatches(TestCase):
# THEN: The result should be None
assert result is None
def test_get_existing_directory_user_accepts(self):
def test_get_existing_directory_user_accepts():
"""
Test that `getExistingDirectory` handles the case when the user accepts the dialog
"""
@ -69,7 +64,8 @@ class TestFileDialogPatches(TestCase):
# THEN: getExistingDirectory() should return a Path object pointing to the chosen file
assert result == Path('test', 'dir')
def test_get_existing_directory_param_order(self):
def test_get_existing_directory_param_order():
"""
Test that `getExistingDirectory` passes the parameters to `QFileDialog.getExistingDirectory` in the correct
order
@ -86,7 +82,8 @@ class TestFileDialogPatches(TestCase):
mocked_get_existing_directory.assert_called_once_with('Parent', 'Caption', os.path.join('test', 'dir'),
'Options')
def test_get_open_file_name_user_abort(self):
def test_get_open_file_name_user_abort():
"""
Test that `getOpenFileName` handles the case when the user cancels the dialog
"""
@ -99,7 +96,8 @@ class TestFileDialogPatches(TestCase):
# THEN: First value should be None
assert result[0] is None
def test_get_open_file_name_user_accepts(self):
def test_get_open_file_name_user_accepts():
"""
Test that `getOpenFileName` handles the case when the user accepts the dialog
"""
@ -114,7 +112,8 @@ class TestFileDialogPatches(TestCase):
# chosen file
assert result[0] == Path('test', 'chosen.file')
def test_get_open_file_name_selected_filter(self):
def test_get_open_file_name_selected_filter():
"""
Test that `getOpenFileName` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileName`
"""
@ -126,7 +125,8 @@ class TestFileDialogPatches(TestCase):
# 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_names_user_abort():
"""
Test that `getOpenFileNames` handles the case when the user cancels the dialog
"""
@ -139,7 +139,8 @@ class TestFileDialogPatches(TestCase):
# THEN: First value should be an empty list
assert result[0] == []
def test_get_open_file_names_user_accepts(self):
def test_get_open_file_names_user_accepts():
"""
Test that `getOpenFileNames` handles the case when the user accepts the dialog
"""
@ -154,7 +155,8 @@ class TestFileDialogPatches(TestCase):
# to the chosen file
assert result[0] == [Path('test', 'chosen.file1'), Path('test', 'chosen.file2')]
def test_get_open_file_names_selected_filter(self):
def test_get_open_file_names_selected_filter():
"""
Test that `getOpenFileNames` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileNames`
"""
@ -167,7 +169,8 @@ class TestFileDialogPatches(TestCase):
# 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_save_file_name_user_abort():
"""
Test that `getSaveFileName` handles the case when the user cancels the dialog
"""
@ -180,7 +183,8 @@ class TestFileDialogPatches(TestCase):
# THEN: First value should be None
assert result[0] is None
def test_get_save_file_name_user_accepts(self):
def test_get_save_file_name_user_accepts():
"""
Test that `getSaveFileName` handles the case when the user accepts the dialog
"""
@ -195,7 +199,8 @@ class TestFileDialogPatches(TestCase):
# chosen file
assert result[0] == Path('test', 'chosen.file')
def test_get_save_file_name_selected_filter(self):
def test_get_save_file_name_selected_filter():
"""
Test that `getSaveFileName` does not modify the selectedFilter as returned by `QFileDialog.getSaveFileName`
"""

View File

@ -22,8 +22,8 @@
This module contains tests for the openlp.core.widgets.edits module
"""
import os
import pytest
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, PropertyMock, patch
from openlp.core.widgets.dialogs import FileDialog
@ -31,116 +31,121 @@ from openlp.core.widgets.edits import PathEdit
from openlp.core.widgets.enums import PathEditType
class TestPathEdit(TestCase):
"""
Test the :class:`~openlp.core.widgets.edits.PathEdit` class
"""
def setUp(self):
@pytest.fixture()
def widget():
with patch('openlp.core.widgets.edits.PathEdit._setup'):
self.widget = PathEdit()
return PathEdit()
def test_path_getter(self):
def test_path_getter(widget):
"""
Test the `path` property getter.
"""
# GIVEN: An instance of PathEdit with the `_path` instance variable set
self.widget._path = Path('getter', 'test', 'pat.h')
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')
assert widget.path == Path('getter', 'test', 'pat.h')
def test_path_setter(self):
def test_path_setter(widget):
"""
Test the `path` property setter.
"""
# 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
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
# should have also been set.
assert self.widget._path == Path('setter', 'test', 'pat.h')
self.widget.line_edit.setToolTip.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
self.widget.line_edit.setText.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
assert widget._path == Path('setter', 'test', 'pat.h')
widget.line_edit.setToolTip.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
widget.line_edit.setText.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
def test_path_type_getter(self):
def test_path_type_getter(widget):
"""
Test the `path_type` property getter.
"""
# GIVEN: An instance of PathEdit
# WHEN: Reading the `path` property
# THEN: The default value should be returned
assert self.widget.path_type == PathEditType.Files
assert widget.path_type == PathEditType.Files
def test_path_type_setter(self):
def test_path_type_setter(widget):
"""
Test the `path_type` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `update_button_tool_tips` method.
with patch.object(self.widget, 'update_button_tool_tips') as mocked_update_button_tool_tips:
with patch.object(widget, 'update_button_tool_tips') as mocked_update_button_tool_tips:
# WHEN: Writing to a different value than default to the `path_type` property
self.widget.path_type = PathEditType.Directories
widget.path_type = PathEditType.Directories
# THEN: The `_path_type` instance variable should be set with the test data and not the default. The
# update_button_tool_tips should have been called.
assert self.widget._path_type == PathEditType.Directories
assert widget._path_type == PathEditType.Directories
mocked_update_button_tool_tips.assert_called_once_with()
def test_update_button_tool_tips_directories(self):
def test_update_button_tool_tips_directories(widget):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories`
self.widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock()
self.widget._path_type = PathEditType.Directories
widget.browse_button = MagicMock()
widget.revert_button = MagicMock()
widget._path_type = PathEditType.Directories
# WHEN: Calling update_button_tool_tips
self.widget.update_button_tool_tips()
widget.update_button_tool_tips()
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.')
widget.browse_button.setToolTip.assert_called_once_with('Browse for directory.')
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_files(widget):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files`
self.widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock()
self.widget._path_type = PathEditType.Files
widget.browse_button = MagicMock()
widget.revert_button = MagicMock()
widget._path_type = PathEditType.Files
# 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.')
self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default file.')
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(self, mocked_get_open_file_name, mocked_get_existing_directory):
@patch('openlp.core.widgets.edits.FileDialog.getExistingDirectory', return_value=None)
@patch('openlp.core.widgets.edits.FileDialog.getOpenFileName')
def test_on_browse_button_clicked_directory(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
self.widget._path_type = PathEditType.Directories
self.widget._path = Path('test', 'path')
widget._path_type = PathEditType.Directories
widget._path = Path('test', 'path')
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the default caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory',
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(self):
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.
@ -150,20 +155,21 @@ class TestPathEdit(TestCase):
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'
widget._path_type = PathEditType.Directories
widget._path = Path('test', 'path')
widget.dialog_caption = 'Directory Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption',
mocked_get_existing_directory.assert_called_once_with(widget, 'Directory Caption',
Path('test', 'path'),
FileDialog.ShowDirsOnly)
assert mocked_get_open_file_name.called is False
def test_on_browse_button_clicked_file(self):
def test_on_browse_button_clicked_file(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files.
"""
@ -171,18 +177,19 @@ class TestPathEdit(TestCase):
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')
widget._path_type = PathEditType.Files
widget._path = Path('test', 'pat.h')
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the default caption
mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', Path('test', 'pat.h'),
self.widget.filters)
mocked_get_open_file_name.assert_called_once_with(widget, 'Select File', Path('test', 'pat.h'),
widget.filters)
assert mocked_get_existing_directory.called is False
def test_on_browse_button_clicked_file_custom_caption(self):
def test_on_browse_button_clicked_file_custom_caption(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files and
`dialog_caption` is set.
@ -192,19 +199,20 @@ class TestPathEdit(TestCase):
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'
widget._path_type = PathEditType.Files
widget._path = Path('test', 'pat.h')
widget.dialog_caption = 'File Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the custom caption
mocked_get_open_file_name.assert_called_once_with(self.widget, 'File Caption', Path('test', 'pat.h'),
self.widget.filters)
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
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
empty str is returned)
@ -215,12 +223,13 @@ class TestPathEdit(TestCase):
mocked_get_open_file_name:
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: normpath should not have been called
assert mocked_get_open_file_name.called is True
def test_on_browse_button_clicked_user_accepts(self):
def test_on_browse_button_clicked_user_accepts(widget):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user accepts the FileDialog (a path
is returned)
@ -229,69 +238,73 @@ class TestPathEdit(TestCase):
# 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'):
patch.object(widget, 'on_new_path'):
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
widget.on_browse_button_clicked()
# THEN: normpath and `on_new_path` should have been called
assert mocked_get_open_file_name.called is True
assert self.widget.on_new_path.called is True
assert widget.on_new_path.called is True
def test_on_revert_button_clicked(self):
def test_on_revert_button_clicked(widget):
"""
Test that the default path is set as the path when the `revert_button.clicked` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `on_new_path`, and the `default_path` set.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
self.widget.default_path = Path('default', 'pat.h')
with patch.object(widget, 'on_new_path') as mocked_on_new_path:
widget.default_path = Path('default', 'pat.h')
# WHEN: Calling `on_revert_button_clicked`
self.widget.on_revert_button_clicked()
widget.on_revert_button_clicked()
# THEN: on_new_path should have been called with the default path
mocked_on_new_path.assert_called_once_with(Path('default', 'pat.h'))
def test_on_line_edit_editing_finished(self):
def test_on_line_edit_editing_finished(widget):
"""
Test that the new path is set as the path when the `line_edit.editingFinished` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
self.widget.line_edit = MagicMock(**{'text.return_value': 'test/pat.h'})
with patch.object(widget, 'on_new_path') as mocked_on_new_path:
widget.line_edit = MagicMock(**{'text.return_value': 'test/pat.h'})
# WHEN: Calling `on_line_edit_editing_finished`
self.widget.on_line_edit_editing_finished()
widget.on_line_edit_editing_finished()
# 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_new_path_no_change(widget):
"""
Test `on_new_path` when called with a path that is the same as the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.widgets.edits.PathEdit.path', new_callable=PropertyMock):
self.widget._path = Path('/old', 'test', 'pat.h')
self.widget.pathChanged = MagicMock()
widget._path = Path('/old', 'test', 'pat.h')
widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the same path as the existing path
self.widget.on_new_path(Path('/old', 'test', 'pat.h'))
widget.on_new_path(Path('/old', 'test', 'pat.h'))
# THEN: The `pathChanged` signal should not be emitted
assert self.widget.pathChanged.emit.called is False
assert widget.pathChanged.emit.called is False
def test_on_new_path_change(self):
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):
self.widget._path = Path('/old', 'test', 'pat.h')
self.widget.pathChanged = MagicMock()
widget._path = Path('/old', 'test', 'pat.h')
widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the a new path
self.widget.on_new_path(Path('/new', 'test', 'pat.h'))
widget.on_new_path(Path('/new', 'test', 'pat.h'))
# THEN: The `pathChanged` signal should be emitted
self.widget.pathChanged.emit.assert_called_once_with(Path('/new', 'test', 'pat.h'))
widget.pathChanged.emit.assert_called_once_with(Path('/new', 'test', 'pat.h'))

View File

@ -24,7 +24,6 @@ Package to test the openlp.core.widgets.views package.
import os
import pytest
from types import GeneratorType
from unittest import TestCase
from unittest.mock import MagicMock, call, patch
from PyQt5 import QtGui
@ -54,11 +53,7 @@ def preview_widget_env():
viewport_patcher.stop()
class TestHandleMimeDataUrls(TestCase):
"""
Test the :func:`openlp.core.widgets.views.handle_mime_data_urls` function.
"""
def test_files(self):
def test_files():
"""
Test handle_mime_data_urls when the data points to some files.
"""
@ -79,7 +74,8 @@ class TestHandleMimeDataUrls(TestCase):
call(os.path.join('file', 'test', 'path', '2.ext'))])
assert result == [mocked_path_instance_1, mocked_path_instance_2]
def test_directory(self):
def test_directory():
"""
Test handle_mime_data_urls when the data points to some directories.
"""
@ -578,11 +574,7 @@ def test_autoscroll_normal(mocked_slide_count, mocked_item, mocked_scrollToItem,
mocked_item.assert_has_calls(calls)
class TestListWidgetWithDnD(TestCase):
"""
Test the :class:`~openlp.core.widgets.views.ListWidgetWithDnD` class
"""
def test_clear(self):
def test_treewidgetwithdnd_clear():
"""
Test the clear method when called without any arguments.
"""
@ -595,7 +587,8 @@ class TestListWidgetWithDnD(TestCase):
# THEN: The results text should be the standard 'no results' text.
assert widget.no_results_text == UiStrings().NoResults
def test_clear_search_while_typing(self):
def test_clear_search_while_typing():
"""
Test the clear method when called with the search_while_typing argument set to True
"""
@ -608,7 +601,8 @@ class TestListWidgetWithDnD(TestCase):
# 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):
def test_all_items_no_list_items():
"""
Test allItems when there are no items in the list widget
"""
@ -624,7 +618,8 @@ class TestListWidgetWithDnD(TestCase):
assert isinstance(result, GeneratorType)
assert list(result) == []
def test_all_items_list_items(self):
def test_all_items_list_items():
"""
Test allItems when the list widget contains some items.
"""
@ -640,7 +635,8 @@ class TestListWidgetWithDnD(TestCase):
assert isinstance(result, GeneratorType)
assert list(result) == [5, 3]
def test_paint_event(self):
def test_paint_event():
"""
Test the paintEvent method when the list is not empty
"""
@ -659,7 +655,8 @@ class TestListWidgetWithDnD(TestCase):
mocked_paint_event.assert_called_once_with(mocked_event)
assert mocked_viewport.called is False
def test_paint_event_no_items(self):
def test_paint_event_no_items():
"""
Test the paintEvent method when the list is empty
"""
@ -685,11 +682,7 @@ class TestListWidgetWithDnD(TestCase):
mocked_painter_instance.drawText.assert_called_once_with(mocked_qrect, 4100, 'No Search Results')
class TestTreeWidgetWithDnD(TestCase):
"""
Test the :class:`~openlp.core.widgets.views.TreeWidgetWithDnD` class
"""
def test_constructor(self):
def test_treewidgetwithdnd_constructor():
"""
Test the constructor
"""