2
Package to test the openlp.core.lib.htmlbuilder module.
4
from unittest import TestCase
5
from unittest.mock import MagicMock, patch
7
from PyQt5 import QtCore, QtWebKit
9
from openlp.core.common.settings import Settings
10
from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \
11
build_lyrics_format_css, build_footer_css, webkit_version, build_chords_css
12
from openlp.core.lib.theme import HorizontalType, VerticalType
13
from tests.helpers.testmixin import TestMixin
19
<title>OpenLP Display</title>
26
-webkit-user-select: none;
40
background-color: black;
66
.chordline span.chord span {
69
.chordline span.chord span strong {
83
white-space: pre-wrap;
88
var transition = false;
91
function show_image(src){
92
var img = document.getElementById('image');
95
img.style.display = 'none';
97
img.style.display = 'block';
100
function show_blank(state){
113
document.getElementById('black').style.display = black;
114
document.getElementById('lyricsmain').style.visibility = lyrics;
115
document.getElementById('image').style.visibility = lyrics;
116
document.getElementById('footer').style.visibility = lyrics;
119
function show_footer(footertext){
120
document.getElementById('footer').innerHTML = footertext;
123
function show_text(new_text){
124
var match = /-webkit-text-fill-color:[^;\"]+/gi;
128
QtWebkit bug with outlines and justify causing outline alignment
129
problems. (Bug 859950) Surround each word with a <span> to workaround,
130
but only in this scenario.
132
var txt = document.getElementById('lyricsmain');
133
if(window.getComputedStyle(txt).textAlign == 'justify'){
134
if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
135
new_text = new_text.replace(/(\s| )+(?![^<]*>)/g,
137
return '</span>' + match + '<span>';
139
new_text = '<span>' + new_text + '</span>';
142
text_fade('lyricsmain', new_text);
145
function text_fade(id, new_text){
149
var text = document.getElementById(id);
150
if(text == null) return;
152
text.innerHTML = new_text;
155
// Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
156
text.style.opacity = '0.1';
157
// Fade new text in after the old text has finished fading out.
158
timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
161
function _show_text(text, new_text) {
163
Helper function to show the new_text delayed.
165
text.innerHTML = new_text;
166
text.style.opacity = '1';
167
// Wait until the text is completely visible. We want to save the timer id, to be able to call
168
// clearTimeout(timer) when the text has changed before finishing fading.
169
timer = window.setTimeout(function(){timer = null;}, 400);
172
function show_text_completed(){
173
return (timer == null);
178
<img id="bgimage" class="size" style="display:none;" />
179
<img id="image" class="size" style="display:none;" />
181
<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
182
<div id="footer" class="footer"></div>
183
<div id="black" class="size"></div>
187
BACKGROUND_CSS_RADIAL = 'background: -webkit-gradient(radial, 5 50%, 100, 5 50%, 5, from(#000000), to(#FFFFFF)) fixed'
193
left: 10px; top: 20px;
197
word-wrap: break-word;
198
-webkit-transition: opacity 0.4s ease;
202
text-shadow: #000000 5px 5px;
205
LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; '
206
LYRICS_FORMAT_CSS = """
207
word-wrap: break-word;
209
vertical-align: bottom;
216
padding-bottom: 0.5em;
223
FOOTER_CSS_BASE = """
233
FOOTER_CSS = FOOTER_CSS_BASE % ('nowrap')
234
FOOTER_CSS_WRAP = FOOTER_CSS_BASE % ('normal')
235
FOOTER_CSS_INVALID = ''
236
CHORD_CSS_ENABLED = """
240
.chordline span.chord span {
243
.chordline span.chord span strong {
257
white-space: pre-wrap;
260
__default_settings__ = {
261
'songs/mainview chords': False,
262
'songs/enable chords': True
266
class Htmbuilder(TestCase, TestMixin):
268
Test the functions in the Htmlbuilder module
274
self.build_settings()
275
Settings().extend_default_settings(__default_settings__)
279
Delete all the C++ objects at the end so that we don't have a segfault
281
self.destroy_settings()
283
def test_build_html(self):
285
Test the build_html() function
287
# GIVEN: Mocked arguments and function.
288
with patch('openlp.core.lib.htmlbuilder.build_background_css') as mocked_build_background_css, \
289
patch('openlp.core.lib.htmlbuilder.build_footer_css') as mocked_build_footer_css, \
290
patch('openlp.core.lib.htmlbuilder.build_lyrics_css') as mocked_build_lyrics_css:
292
mocked_build_background_css.return_value = ''
293
mocked_build_footer_css.return_value = 'dummy: dummy;'
294
mocked_build_lyrics_css.return_value = ''
297
item.bg_image_bytes = None
302
plugin.get_display_css.return_value = 'plugin CSS'
303
plugin.get_display_javascript.return_value = 'plugin JS'
304
plugin.get_display_html.return_value = 'plugin HTML'
307
# WHEN: Create the html.
308
html = build_html(item, screen, is_live, background, plugins=plugins)
310
# THEN: The returned html should match.
311
assert html == HTML, 'The returned html should match'
313
def test_build_background_css_radial(self):
315
Test the build_background_css() function with a radial background
317
# GIVEN: Mocked arguments.
319
item.theme_data.background_start_color = '#000000'
320
item.theme_data.background_end_color = '#FFFFFF'
323
# WHEN: Create the css.
324
css = build_background_css(item, width)
326
# THEN: The returned css should match.
327
assert BACKGROUND_CSS_RADIAL == css, 'The background css should be equal.'
329
def test_build_lyrics_css(self):
331
Test the build_lyrics_css() function
333
# GIVEN: Mocked method and arguments.
334
with patch('openlp.core.lib.htmlbuilder.build_lyrics_format_css') as mocked_build_lyrics_format_css, \
335
patch('openlp.core.lib.htmlbuilder.build_lyrics_outline_css') as mocked_build_lyrics_outline_css:
336
mocked_build_lyrics_format_css.return_value = 'lyrics_format_css'
337
mocked_build_lyrics_outline_css.return_value = ''
339
item.main = QtCore.QRect(10, 20, 10, 20)
340
item.theme_data.font_main_shadow = True
341
item.theme_data.font_main_shadow_color = '#000000'
342
item.theme_data.font_main_shadow_size = 5
344
# WHEN: Create the css.
345
css = build_lyrics_css(item)
347
# THEN: The css should be equal.
348
assert LYRICS_CSS == css, 'The lyrics css should be equal.'
350
def test_build_lyrics_outline_css(self):
352
Test the build_lyrics_outline_css() function
354
# GIVEN: The mocked theme data.
355
theme_data = MagicMock()
356
theme_data.font_main_outline = True
357
theme_data.font_main_outline_size = 2
358
theme_data.font_main_color = '#FFFFFF'
359
theme_data.font_main_outline_color = '#000000'
361
# WHEN: Create the css.
362
css = build_lyrics_outline_css(theme_data)
364
# THEN: The css should be equal.
365
assert LYRICS_OUTLINE_CSS == css, 'The outline css should be equal.'
367
def test_build_lyrics_format_css(self):
369
Test the build_lyrics_format_css() function
371
# GIVEN: Mocked arguments.
372
theme_data = MagicMock()
373
theme_data.display_horizontal_align = HorizontalType.Justify
374
theme_data.display_vertical_align = VerticalType.Bottom
375
theme_data.font_main_name = 'Arial'
376
theme_data.font_main_size = 40
377
theme_data.font_main_color = '#FFFFFF'
378
theme_data.font_main_italics = True
379
theme_data.font_main_bold = True
380
theme_data.font_main_line_adjustment = 8
385
css = build_lyrics_format_css(theme_data, width, height)
387
# THEN: They should be equal.
388
assert LYRICS_FORMAT_CSS == css, 'The lyrics format css should be equal.'
390
def test_build_footer_css(self):
392
Test the build_footer_css() function
394
# GIVEN: Create a theme.
396
item.footer = QtCore.QRect(10, 921, 1260, 103)
397
item.theme_data.font_footer_name = 'Arial'
398
item.theme_data.font_footer_size = 12
399
item.theme_data.font_footer_color = '#FFFFFF'
402
# WHEN: create the css with default settings.
403
css = build_footer_css(item, height)
405
# THEN: THE css should be the same.
406
assert FOOTER_CSS == css, 'The footer strings should be equal.'
408
def test_build_footer_css_wrap(self):
410
Test the build_footer_css() function
412
# GIVEN: Create a theme.
414
item.footer = QtCore.QRect(10, 921, 1260, 103)
415
item.theme_data.font_footer_name = 'Arial'
416
item.theme_data.font_footer_size = 12
417
item.theme_data.font_footer_color = '#FFFFFF'
420
# WHEN: Settings say that footer should wrap
421
Settings().setValue('themes/wrap footer', True)
422
css = build_footer_css(item, height)
424
# THEN: Footer should wrap
425
assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.'
427
def test_build_footer_invalid(self):
429
Test the build_footer_css() function
431
# GIVEN: Create a theme.
434
item.theme_data = None
438
# WHEN: Settings say that footer should wrap
439
css.append(build_footer_css(item, height))
440
item.theme_data = 'TEST'
442
css.append(build_footer_css(item, height))
444
# THEN: Footer should wrap
445
assert FOOTER_CSS_INVALID == css[0], 'The footer strings should be blank.'
446
assert FOOTER_CSS_INVALID == css[1], 'The footer strings should be blank.'
448
def test_webkit_version(self):
450
Test the webkit_version() function
453
webkit_ver = float(QtWebKit.qWebKitVersion())
454
# WHEN: Retrieving the webkit version
455
# THEN: Webkit versions should match
456
assert webkit_version() == webkit_ver, "The returned webkit version doesn't match the installed one"
458
def test_build_chords_css(self):
460
Test the build_chords_css() function
462
# GIVEN: A setting that activates chords on the mainview
463
Settings().setValue('songs/enable chords', True)
464
Settings().setValue('songs/mainview chords', True)
466
# WHEN: Building the chord CSS
467
chord_css = build_chords_css()
469
# THEN: The build css should look as expected
470
assert CHORD_CSS_ENABLED == chord_css, 'The chord CSS should look as expected'