Fix up the formatting of the contents of the help box

- Fix #380
- Fix some tests
- Add some tests

Fix some tests, add some tests
This commit is contained in:
Raoul Snyman 2020-04-01 14:21:27 -07:00
parent 73da7f8315
commit efd97644c8
Signed by: raoul
GPG Key ID: F55BCED79626AE9C
6 changed files with 154 additions and 33 deletions

View File

@ -250,7 +250,7 @@ def build_icon(icon):
pix_map = QtGui.QPixmap(icon) pix_map = QtGui.QPixmap(icon)
elif isinstance(icon, Path): elif isinstance(icon, Path):
pix_map = QtGui.QPixmap(str(icon)) pix_map = QtGui.QPixmap(str(icon))
elif isinstance(icon, QtGui.QImage): elif isinstance(icon, QtGui.QImage): # pragma: no cover
pix_map = QtGui.QPixmap.fromImage(icon) pix_map = QtGui.QPixmap.fromImage(icon)
if pix_map: if pix_map:
button_icon.addPixmap(pix_map, QtGui.QIcon.Normal, QtGui.QIcon.Off) button_icon.addPixmap(pix_map, QtGui.QIcon.Normal, QtGui.QIcon.Off)

View File

@ -154,17 +154,16 @@ class SongsTab(SettingsTab):
['ccli_number', translate('SongsPlugin.SongsTab', 'Song CCLI Number'), True, False], ['ccli_number', translate('SongsPlugin.SongsTab', 'Song CCLI Number'), True, False],
['topics', translate('SongsPlugin.SongsTab', 'Topics'), False, True], ['topics', translate('SongsPlugin.SongsTab', 'Topics'), False, True],
] ]
placeholder_info = '<table style="background: #eee">\n<tr><th><b>{ph}</b></th><th><b>{desc}</b></th></tr>\n'\ placeholder_info = '<table><tr><th><b>{ph}</b></th><th><b>{desc}</b></th></tr>'.format(
.format(ph=translate('SongsPlugin.SongsTab', 'Placeholder'), ph=translate('SongsPlugin.SongsTab', 'Placeholder'), desc=translate('SongsPlugin.SongsTab', 'Description'))
desc=translate('SongsPlugin.SongsTab', 'Description'))
for placeholder in placeholders: for placeholder in placeholders:
placeholder_info += '<tr><td>${{{pl}}}</td><td>{des}{opt}</td></tr>\n'\ placeholder_info += '<tr><td>${{{pl}}}</td><td>{des}{opt}</td></tr>'.format(
.format(pl=placeholder[0], des=placeholder[1], pl=placeholder[0], des=placeholder[1], opt=('&nbsp;<sup>1</sup>' if placeholder[2] else '') +
opt=('&nbsp;¹' if placeholder[2] else '') + ('&nbsp;<sup>2</sup>' if placeholder[3] else ''))
('&nbsp;²' if placeholder[3] else ''))
placeholder_info += '</table>' placeholder_info += '</table>'
placeholder_info += '\n<br/>¹ {}'.format(translate('SongsPlugin.SongsTab', 'can be empty')) placeholder_info += '<p><sup>1</sup> {}<br/>'.format(translate('SongsPlugin.SongsTab', 'can be empty'))
placeholder_info += '\n<br/>² {}'.format(translate('SongsPlugin.SongsTab', 'list of entries, can be empty')) placeholder_info += '<sup>2</sup> {}</p>'.format(
translate('SongsPlugin.SongsTab', 'list of entries, can be empty'))
self.footer_placeholder_info.setHtml(placeholder_info) self.footer_placeholder_info.setHtml(placeholder_info)
self.footer_placeholder_info.setReadOnly(True) self.footer_placeholder_info.setReadOnly(True)

View File

@ -113,6 +113,11 @@ def test_toggle_display_invalid_action(flask_client, settings):
assert res.status_code == 400 assert res.status_code == 400
def test_toggle_display_no_data(flask_client, settings):
res = flask_client.post('/api/v2/core/display', json={})
assert res.status_code == 400
def test_toggle_display_valid_action_updates_controller(flask_client, settings): def test_toggle_display_valid_action_updates_controller(flask_client, settings):
class FakeController: class FakeController:
class Emitter: class Emitter:

View File

@ -220,29 +220,30 @@ def test_build_icon_with_resource():
# best we can do is to assert that we get back a MagicMock object. # best we can do is to assert that we get back a MagicMock object.
assert isinstance(result, MagicMock), 'The result should be a MagicMock, because we mocked it out' assert isinstance(result, MagicMock), 'The result should be a MagicMock, because we mocked it out'
def test_image_to_byte(self):
"""
Test the image_to_byte() function
"""
with patch('openlp.core.lib.QtCore') as MockedQtCore:
# GIVEN: A set of mocked-out Qt classes
mocked_byte_array = MagicMock()
MockedQtCore.QByteArray.return_value = mocked_byte_array
mocked_buffer = MagicMock()
MockedQtCore.QBuffer.return_value = mocked_buffer
MockedQtCore.QIODevice.WriteOnly = 'writeonly'
mocked_image = MagicMock()
# WHEN: We convert an image to a byte array def test_image_to_byte():
result = image_to_byte(mocked_image, base_64=False) """
Test the image_to_byte() function
"""
with patch('openlp.core.lib.QtCore') as MockedQtCore:
# GIVEN: A set of mocked-out Qt classes
mocked_byte_array = MagicMock()
MockedQtCore.QByteArray.return_value = mocked_byte_array
mocked_buffer = MagicMock()
MockedQtCore.QBuffer.return_value = mocked_buffer
MockedQtCore.QIODevice.WriteOnly = 'writeonly'
mocked_image = MagicMock()
# THEN: We should receive the mocked_buffer # WHEN: We convert an image to a byte array
MockedQtCore.QByteArray.assert_called_with() result = image_to_byte(mocked_image, base_64=False)
MockedQtCore.QBuffer.assert_called_with(mocked_byte_array)
mocked_buffer.open.assert_called_with('writeonly') # THEN: We should receive the mocked_buffer
mocked_image.save.assert_called_with(mocked_buffer, "PNG") MockedQtCore.QByteArray.assert_called_with()
assert mocked_byte_array.toBase64.called is False MockedQtCore.QBuffer.assert_called_with(mocked_byte_array)
assert mocked_byte_array == result, 'The mocked out byte array should be returned' mocked_buffer.open.assert_called_with('writeonly')
mocked_image.save.assert_called_with(mocked_buffer, "PNG")
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(): def test_image_to_byte_base_64():
@ -498,6 +499,25 @@ def test_create_thumb_empty_img():
pass pass
@patch('openlp.core.lib.QtGui.QImageReader')
@patch('openlp.core.lib.build_icon')
def test_create_thumb_path_fails(mocked_build_icon, MockQImageReader):
"""
Test that build_icon() is run against the image_path when the thumbnail fails to be created
"""
# GIVEN: A bunch of mocks
image_path = RESOURCE_PATH / 'church.jpg'
thumb_path = Path('doesnotexist')
mocked_image_reader = MagicMock()
mocked_image_reader.size.return_value.isEmpty.return_value = True
# WHEN: Create the thumb
create_thumb(image_path, thumb_path)
# THEN: The image path should have been used
mocked_build_icon.assert_called_once_with(image_path)
@patch('openlp.core.lib.QtWidgets', MagicMock()) @patch('openlp.core.lib.QtWidgets', MagicMock())
def test_check_item_selected_true(): def test_check_item_selected_true():
""" """
@ -631,6 +651,42 @@ def test_resize_thumb_ignoring_aspect_ratio():
assert image.pixel(0, 0) == wanted_background_rgb, 'The background should be white.' assert image.pixel(0, 0) == wanted_background_rgb, 'The background should be white.'
def test_resize_thumb_width_aspect_ratio():
"""
Test the resize_thumb() function using the image's width as the reference
"""
# GIVEN: A path to an image.
image_path = str(RESOURCE_PATH / 'church.jpg')
wanted_width = 10
wanted_height = 1000
# WHEN: Resize the image and add a background.
image = resize_image(image_path, wanted_width, wanted_height)
# THEN: Check if the size is correct and the background was set.
result_size = image.size()
assert wanted_height == result_size.height(), 'The image should have the requested height.'
assert wanted_width == result_size.width(), 'The image should have the requested width.'
def test_resize_thumb_same_aspect_ratio():
"""
Test the resize_thumb() function when the image and the wanted aspect ratio are the same
"""
# GIVEN: A path to an image.
image_path = str(RESOURCE_PATH / 'church.jpg')
wanted_width = 1122
wanted_height = 1544
# WHEN: Resize the image and add a background.
image = resize_image(image_path, wanted_width, wanted_height)
# THEN: Check if the size is correct and the background was set.
result_size = image.size()
assert wanted_height == result_size.height(), 'The image should have the requested height.'
assert wanted_width == result_size.width(), 'The image should have the requested width.'
@patch('openlp.core.lib.QtCore.QLocale.createSeparatedList') @patch('openlp.core.lib.QtCore.QLocale.createSeparatedList')
def test_create_separated_list_qlocate(mocked_createSeparatedList): def test_create_separated_list_qlocate(mocked_createSeparatedList):
""" """

View File

@ -25,10 +25,11 @@ import pytest
from pathlib import Path from pathlib import Path
from unittest.mock import MagicMock, call, patch, DEFAULT from unittest.mock import MagicMock, call, patch, DEFAULT
from PyQt5 import QtWidgets from PyQt5 import QtCore, QtWidgets
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.core.ui.firsttimeform import FirstTimeForm, ThemeListWidgetItem from openlp.core.ui.firsttimeform import FirstTimeForm, ThemeListWidgetItem
from openlp.core.ui.firsttimewizard import ThemeListWidget
INVALID_CONFIG = """ INVALID_CONFIG = """
@ -364,3 +365,22 @@ def test_on_projectors_check_box_unchecked(mock_settings):
# THEN: The visibility of the projects panel should have been set # THEN: The visibility of the projects panel should have been set
mock_settings.value.assert_called_once_with('projector/show after wizard') mock_settings.value.assert_called_once_with('projector/show after wizard')
mock_settings.setValue.assert_called_once_with('projector/show after wizard', True) mock_settings.setValue.assert_called_once_with('projector/show after wizard', True)
def test_theme_list_widget_resize(ftf_app):
"""
Test that the resizeEvent() method in the ThemeListWidget works correctly
"""
# GIVEN: An instance of the ThemeListWidget
widget = ThemeListWidget(None)
# WHEN: resizeEvent() is called
with patch.object(widget, 'viewport') as mocked_viewport, \
patch.object(widget, 'setGridSize') as mocked_setGridSize:
mocked_viewport.return_value.width.return_value = 600
widget.resizeEvent(None)
# THEN: Check that the correct calculations were done
mocked_setGridSize.assert_called_once_with(QtCore.QSize(149, 140))
# THEN: everything resizes correctly

View File

@ -26,7 +26,7 @@ from unittest.mock import MagicMock, patch
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.plugins.bibles import lib from openlp.plugins.bibles import lib
from openlp.plugins.bibles.lib import SearchResults, get_reference_match from openlp.plugins.bibles.lib import SearchResults, get_reference_match, update_reference_separators
@pytest.yield_fixture @pytest.yield_fixture
@ -252,3 +252,44 @@ def test_reference_matched_range_separator(mocked_bible_test):
# THEN: The list of references should be as the expected results # THEN: The list of references should be as the expected results
assert references == ranges assert references == ranges
def test_update_reference_separators_custom_seps(request, settings):
"""
Test the update_reference_separators() function with custom separators
"""
# Clean up after the test
def cleanup_references():
lib.REFERENCE_SEPARATORS = {}
settings.remove('bibles/verse separator')
settings.remove('bibles/range separator')
settings.remove('bibles/list separator')
settings.remove('bibles/end separator')
update_reference_separators()
request.addfinalizer(cleanup_references)
# GIVEN: A custom set of separators
settings.setValue('bibles/verse separator', ':||v')
settings.setValue('bibles/range separator', '-')
settings.setValue('bibles/list separator', ',')
settings.setValue('bibles/end separator', '.')
# WHEN: update_reference_separators() is called
update_reference_separators()
# THEN: The reference separators should be updated and correct
expected_separators = {
'sep_e': '\\s*(?:\\.)\\s*',
'sep_e_default': 'end',
'sep_l': '\\s*(?:(?:[,]))\\s*',
'sep_l_default': ',|and',
'sep_l_display': ',',
'sep_r': '\\s*(?:(?:[-\xad‐‑‒——−﹣-]))\\s*',
'sep_r_default': '-|to',
'sep_r_display': '-',
'sep_v': '\\s*(?::|v)\\s*',
'sep_v_default': ':|v|V|verse|verses',
'sep_v_display': ':'
}
assert lib.REFERENCE_SEPARATORS == expected_separators