4
4
###############################################################################
5
5
# OpenLP - Open Source Lyrics Projection #
6
6
# --------------------------------------------------------------------------- #
7
# Copyright (c) 2008-2017 OpenLP Developers #
7
# Copyright (c) 2008-2019 OpenLP Developers #
8
8
# --------------------------------------------------------------------------- #
9
9
# This program is free software; you can redistribute it and/or modify it #
10
10
# under the terms of the GNU General Public License as published by the Free #
26
26
from unittest import TestCase
27
27
from unittest.mock import MagicMock, patch
29
from openlp.core.state import State
29
30
from openlp.core.common import md5_hash
30
31
from openlp.core.common.path import Path
31
32
from openlp.core.common.registry import Registry
32
33
from openlp.core.common.settings import Settings
33
from openlp.core.lib import ItemCapabilities, ServiceItem, ServiceItemType, FormattingTags
34
from openlp.core.lib.formattingtags import FormattingTags
35
from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem, ServiceItemType
34
36
from tests.helpers.testmixin import TestMixin
35
from tests.utils import assert_length, convert_file_service_item
37
from tests.utils import convert_file_service_item
36
38
from tests.utils.constants import RESOURCE_PATH
38
41
VERSE = 'The Lord said to {r}Noah{/r}: \n'\
39
42
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n'\
40
43
'The Lord said to {g}Noah{/g}:\n'\
42
45
'Get those children out of the muddy, muddy \n'\
43
46
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}'\
44
47
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
45
CLEANED_VERSE = 'The Lord said to Noah: \n'\
46
'There\'s gonna be a floody, floody\n'\
47
'The Lord said to Noah:\n'\
48
'There\'s gonna be a floody, floody\n'\
49
'Get those children out of the muddy, muddy \n'\
50
'Children of the Lord\n'
48
CLEANED_VERSE = 'Amazing Grace! how sweet the sound\n'\
49
'That saved a wretch like me;\n'\
50
'I once was lost, but now am found,\n'\
51
'Was blind, but now I see.\n'
51
52
RENDERED_VERSE = 'The Lord said to <span style="-webkit-text-fill-color:red">Noah</span>: \n'\
52
53
'There's gonna be a <sup>floody</sup>, <sub>floody</sub>\n'\
53
54
'The Lord said to <span style="-webkit-text-fill-color:green">Noah</span>:\n'\
76
77
self.build_settings()
77
78
Settings().extend_default_settings(__default_settings__)
80
# Mock the renderer and its format_slide method
79
81
mocked_renderer = MagicMock()
80
mocked_renderer.format_slide.return_value = [VERSE]
83
def side_effect_return_arg(arg1, arg2):
85
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
86
mocked_renderer.format_slide = mocked_slide_formater
81
87
Registry().register('renderer', mocked_renderer)
82
88
Registry().register('image_manager', MagicMock())
109
115
service_item.add_icon = MagicMock()
110
116
FormattingTags.load_tags()
112
# WHEN: We add a custom from a saved service
118
# WHEN: We add a custom from a saved serviceand set the media state
113
119
line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj')
120
State().add_service("media", 0)
121
State().update_pre_conditions("media", True)
122
State().flush_preconditions()
114
123
service_item.set_from_service(line)
116
125
# THEN: We should get back a valid service item
117
126
assert service_item.is_valid is True, 'The new service item should be valid'
118
assert_length(0, service_item._display_frames, 'The service item should have no display frames')
119
assert_length(5, service_item.capabilities, 'There should be 5 default custom item capabilities')
121
# WHEN: We render the frames of the service item
122
service_item.render(True)
127
assert len(service_item.get_frames()) == 2, 'The service item should have 2 display frames'
128
assert len(service_item.capabilities) == 5, 'There should be 5 default custom item capabilities'
124
130
# THEN: The frames should also be valid
125
131
assert 'Test Custom' == service_item.get_display_title(), 'The title should be "Test Custom"'
126
assert CLEANED_VERSE[:-1] == service_item.get_frames()[0]['text'], \
127
'The returned text matches the input, except the last line feed'
128
assert RENDERED_VERSE.split('\n', 1)[0] == service_item.get_rendered_frame(1), \
129
'The first line has been returned'
132
assert 'Slide 1' == service_item.get_frames()[0]['text']
133
assert 'Slide 2' == service_item.get_rendered_frame(1)
130
134
assert 'Slide 1' == service_item.get_frame_title(0), '"Slide 1" has been returned as the title'
131
135
assert 'Slide 2' == service_item.get_frame_title(1), '"Slide 2" has been returned as the title'
132
136
assert '' == service_item.get_frame_title(2), 'Blank has been returned as the title of slide 3'
138
142
# GIVEN: A new service item and a mocked add icon function
139
143
image_name = 'image_1.jpg'
140
test_file = os.path.join(TEST_PATH, image_name)
144
test_file = TEST_PATH / image_name
141
145
frame_array = {'path': test_file, 'title': image_name}
143
147
service_item = ServiceItem(None)
149
153
patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \
150
154
mocked_get_section_data_path:
151
155
mocked_exists.return_value = True
152
mocked_get_section_data_path.return_value = os.path.normpath('/path/')
156
mocked_get_section_data_path.return_value = Path('/path/')
153
157
service_item.set_from_service(line, TEST_PATH)
155
159
# THEN: We should get back a valid service item
156
160
assert service_item.is_valid is True, 'The new service item should be valid'
157
assert os.path.normpath(test_file) == os.path.normpath(service_item.get_rendered_frame(0)), \
158
'The first frame should match the path to the image'
161
assert test_file == service_item.get_rendered_frame(0), 'The first frame should match the path to the image'
159
162
assert frame_array == service_item.get_frames()[0], 'The return should match frame array1'
160
assert test_file == service_item.get_frame_path(0), 'The frame path should match the full path to the image'
163
assert test_file == service_item.get_frame_path(0), \
164
'The frame path should match the full path to the image'
161
165
assert image_name == service_item.get_frame_title(0), 'The frame title should match the image name'
162
166
assert image_name == service_item.get_display_title(), 'The display title should match the first image name'
163
167
assert service_item.is_image() is True, 'This service item should be of an "image" type'
170
174
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
171
175
'This service item should be able to have new items added to it'
173
def test_service_item_load_image_from_local_service(self):
177
@patch('openlp.core.lib.serviceitem.os.path.exists')
178
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
179
def test_service_item_load_image_from_local_service(self, mocked_get_section_data_path, mocked_exists):
175
181
Test the Service Item - adding an image from a saved local service
177
183
# GIVEN: A new service item and a mocked add icon function
184
mocked_get_section_data_path.return_value = Path('/path')
185
mocked_exists.return_value = True
178
186
image_name1 = 'image_1.jpg'
179
187
image_name2 = 'image_2.jpg'
180
test_file1 = os.path.normpath(os.path.join('/home/openlp', image_name1))
181
test_file2 = os.path.normpath(os.path.join('/home/openlp', image_name2))
188
test_file1 = os.path.join('/home', 'openlp', image_name1)
189
test_file2 = os.path.join('/home', 'openlp', image_name2)
182
190
frame_array1 = {'path': test_file1, 'title': image_name1}
183
191
frame_array2 = {'path': test_file2, 'title': image_name2}
185
192
service_item = ServiceItem(None)
186
193
service_item.add_icon = MagicMock()
188
194
service_item2 = ServiceItem(None)
189
195
service_item2.add_icon = MagicMock()
191
197
# WHEN: adding an image from a saved Service and mocked exists
192
198
line = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj')
193
199
line2 = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj', 1)
195
with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists, \
196
patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \
197
mocked_get_section_data_path:
198
mocked_exists.return_value = True
199
mocked_get_section_data_path.return_value = os.path.normpath('/path/')
200
service_item2.set_from_service(line2)
201
service_item.set_from_service(line)
200
service_item2.set_from_service(line2)
201
service_item.set_from_service(line)
203
203
# THEN: We should get back a valid service item
205
# This test is copied from service_item.py, but is changed since to conform to
206
# new layout of service item. The layout use in serviceitem_image_2.osd is actually invalid now.
207
204
assert service_item.is_valid is True, 'The first service item should be valid'
208
205
assert service_item2.is_valid is True, 'The second service item should be valid'
209
206
# These test will fail on windows due to the difference in folder seperators
214
211
'The Second frame should match the path to the image'
215
212
assert frame_array1 == service_item.get_frames()[0], 'The return should match the frame array1'
216
213
assert frame_array2 == service_item2.get_frames()[0], 'The return should match the frame array2'
217
assert test_file1 == service_item.get_frame_path(0), \
214
assert test_file1 == str(service_item.get_frame_path(0)), \
218
215
'The frame path should match the full path to the image'
219
assert test_file2 == service_item2.get_frame_path(0), \
216
assert test_file2 == str(service_item2.get_frame_path(0)), \
220
217
'The frame path should match the full path to the image'
221
218
assert image_name1 == service_item.get_frame_title(0), 'The 1st frame title should match the image name'
222
219
assert image_name2 == service_item2.get_frame_title(0), 'The 2nd frame title should match the image name'
243
240
display_title = 'DisplayTitle'
244
241
notes = 'Note1\nNote2\n'
245
242
frame = {'title': presentation_name, 'image': image, 'path': TEST_PATH,
246
'display_title': display_title, 'notes': notes}
243
'display_title': display_title, 'notes': notes, 'thumbnail': image}
248
245
# WHEN: adding presentation to service_item
249
246
service_item.add_from_command(TEST_PATH, presentation_name, image, display_title, notes)
252
249
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
253
250
assert service_item.get_frames()[0] == frame, 'Frames should match'
255
def test_add_from_comamnd_without_display_title_and_notes(self):
252
def test_add_from_command_without_display_title_and_notes(self):
257
254
Test the Service Item - add from command, but not presentation
261
258
image_name = 'test.img'
262
259
image = MagicMock()
263
260
frame = {'title': image_name, 'image': image, 'path': TEST_PATH,
264
'display_title': None, 'notes': None}
261
'display_title': None, 'notes': None, 'thumbnail': image}
266
263
# WHEN: adding image to service_item
267
264
service_item.add_from_command(TEST_PATH, image_name, image)
277
274
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
279
276
# GIVEN: A service item, a mocked AppLocation and presentation data
280
mocked_get_section_data_path.return_value = os.path.join('mocked', 'section', 'path')
277
mocked_get_section_data_path.return_value = Path('mocked') / 'section' / 'path'
281
278
service_item = ServiceItem(None)
282
279
service_item.add_capability(ItemCapabilities.HasThumbnails)
283
280
service_item.has_original_files = False
284
281
service_item.name = 'presentations'
285
282
presentation_name = 'test.pptx'
286
thumb = os.path.join('tmp', 'test', 'thumb.png')
283
thumb = Path('tmp') / 'test' / 'thumb.png'
287
284
display_title = 'DisplayTitle'
288
285
notes = 'Note1\nNote2\n'
289
expected_thumb_path = os.path.join('mocked', 'section', 'path', 'thumbnails',
290
md5_hash(os.path.join(TEST_PATH, presentation_name).encode('utf-8')),
292
frame = {'title': presentation_name, 'image': expected_thumb_path, 'path': TEST_PATH,
293
'display_title': display_title, 'notes': notes}
286
expected_thumb_path = Path('mocked') / 'section' / 'path' / 'thumbnails' / \
287
md5_hash(str(TEST_PATH / presentation_name).encode('utf8')) / 'thumb.png'
288
frame = {'title': presentation_name, 'image': str(expected_thumb_path), 'path': str(TEST_PATH),
289
'display_title': display_title, 'notes': notes, 'thumbnail': str(expected_thumb_path)}
295
291
# WHEN: adding presentation to service_item
296
service_item.add_from_command(TEST_PATH, presentation_name, thumb, display_title, notes)
292
service_item.add_from_command(str(TEST_PATH), presentation_name, thumb, display_title, notes)
298
294
# THEN: verify that it is setup as a Command and that the frame data matches
299
295
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
300
296
assert service_item.get_frames()[0] == frame, 'Frames should match'
301
assert 1 == mocked_image_manager.add_image.call_count, 'image_manager should be used'
297
# assert 1 == mocked_image_manager.add_image.call_count, 'image_manager should be used'
303
299
def test_service_item_load_optical_media_from_service(self):
333
329
# WHEN: We add a custom from a saved service
334
330
line = convert_file_service_item(TEST_PATH, 'serviceitem-song-linked-audio.osj')
335
service_item.set_from_service(line, '/test/')
331
service_item.set_from_service(line, Path('/test/'))
337
333
# THEN: We should get back a valid service item
338
334
assert service_item.is_valid is True, 'The new service item should be valid'
339
assert 0 == len(service_item._display_frames), 'The service item should have no display frames'
340
assert 7 == len(service_item.capabilities), 'There should be 7 default custom item capabilities'
342
# WHEN: We render the frames of the service item
343
service_item.render(True)
345
# THEN: The frames should also be valid
335
assert len(service_item.display_slides) == 6, 'The service item should have 6 display slides'
336
assert len(service_item.capabilities) == 7, 'There should be 7 default custom item capabilities'
346
337
assert 'Amazing Grace' == service_item.get_display_title(), 'The title should be "Amazing Grace"'
347
338
assert CLEANED_VERSE[:-1] == service_item.get_frames()[0]['text'], \
348
339
'The returned text matches the input, except the last line feed'
349
assert RENDERED_VERSE.split('\n', 1)[0] == service_item.get_rendered_frame(1), \
350
'The first line has been returned'
351
340
assert 'Amazing Grace! how sweet the s' == service_item.get_frame_title(0), \
352
341
'"Amazing Grace! how sweet the s" has been returned as the title'
353
342
assert '’Twas grace that taught my hea' == service_item.get_frame_title(1), \