Fix tests so they can run individually.

Fix for importing custom tags from openlyricsxml.
Fixed console popping up on windows when running mudraw.exe.
Added oxps as supported presentation filetype (by mudraw).

bzr-revno: 2425
This commit is contained in:
Tomas Groth 2014-10-21 22:06:02 +01:00 committed by Tim Bentley
commit 5ecbfa61fd
15 changed files with 160 additions and 22 deletions

View File

@ -374,7 +374,8 @@ class SlideController(DisplayController, RegistryProperties):
triggers=self._slide_shortcut_activated) for s in shortcuts])
self.shortcut_timer.timeout.connect(self._slide_shortcut_activated)
# Signals
self.preview_widget.itemSelectionChanged.connect(self.on_slide_selected)
self.preview_widget.clicked.connect(self.on_slide_selected)
self.preview_widget.verticalHeader().sectionClicked.connect(self.on_slide_selected)
if self.is_live:
# Need to use event as called across threads and UI is updated
QtCore.QObject.connect(self, QtCore.SIGNAL('slidecontroller_toggle_display'), self.toggle_display)

View File

@ -38,7 +38,7 @@ from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemConte
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
from openlp.core.utils import get_locale_key
from openlp.plugins.presentations.lib import MessageListener
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
log = logging.getLogger(__name__)
@ -260,11 +260,11 @@ class PresentationMediaItem(MediaManagerItem):
filename = presentation_file
if filename is None:
filename = items[0].data(QtCore.Qt.UserRole)
file_type = os.path.splitext(filename)[1][1:]
file_type = os.path.splitext(filename.lower())[1][1:]
if not self.display_type_combo_box.currentText():
return False
service_item.add_capability(ItemCapabilities.CanEditTitle)
if (file_type == 'pdf' or file_type == 'xps') and context != ServiceItemContext.Service:
if file_type in PDF_CONTROLLER_FILETYPES and context != ServiceItemContext.Service:
service_item.add_capability(ItemCapabilities.CanMaintain)
service_item.add_capability(ItemCapabilities.CanPreview)
service_item.add_capability(ItemCapabilities.CanLoop)

View File

@ -29,12 +29,14 @@
import logging
import copy
import os
from PyQt4 import QtCore
from openlp.core.common import Registry
from openlp.core.ui import HideMode
from openlp.core.lib import ServiceItemContext, ServiceItem
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
log = logging.getLogger(__name__)
@ -320,10 +322,11 @@ class MessageListener(object):
file = item.get_frame_path()
self.handler = item.processor
# When starting presentation from the servicemanager we convert
# PDF/XPS-serviceitems into image-serviceitems. When started from the mediamanager
# PDF/XPS/OXPS-serviceitems into image-serviceitems. When started from the mediamanager
# the conversion has already been done at this point.
if file.endswith('.pdf') or file.endswith('.xps'):
log.debug('Converting from pdf/xps to images for serviceitem with file %s', file)
file_type = os.path.splitext(file.lower())[1][1:]
if file_type in PDF_CONTROLLER_FILETYPES:
log.debug('Converting from pdf/xps/oxps to images for serviceitem with file %s', file)
# Create a copy of the original item, and then clear the original item so it can be filled with images
item_cpy = copy.copy(item)
item.__init__(None)
@ -338,7 +341,7 @@ class MessageListener(object):
item.image_border = item_cpy.image_border
item.main = item_cpy.main
item.theme_data = item_cpy.theme_data
# When presenting PDF or XPS, we are using the image presentation code,
# When presenting PDF/XPS/OXPS, we are using the image presentation code,
# so handler & processor is set to None, and we skip adding the handler.
self.handler = None
if self.handler == self.media_item.automatic:
@ -349,7 +352,7 @@ class MessageListener(object):
controller = self.live_handler
else:
controller = self.preview_handler
# When presenting PDF or XPS, we are using the image presentation code,
# When presenting PDF/XPS/OXPS, we are using the image presentation code,
# so handler & processor is set to None, and we skip adding the handler.
if self.handler is None:
self.controller = controller

View File

@ -34,12 +34,17 @@ import re
from subprocess import check_output, CalledProcessError, STDOUT
from openlp.core.utils import AppLocation
from openlp.core.common import Settings, is_win
from openlp.core.common import Settings, is_win, trace_error_handler
from openlp.core.lib import ScreenList
from .presentationcontroller import PresentationController, PresentationDocument
if is_win():
from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW
log = logging.getLogger(__name__)
PDF_CONTROLLER_FILETYPES = ['pdf', 'xps', 'oxps']
class PdfController(PresentationController):
"""
@ -74,11 +79,19 @@ class PdfController(PresentationController):
runlog = ''
log.debug('testing program_path: %s', program_path)
try:
runlog = check_output([program_path, '--help'], stderr=STDOUT)
# Setup startupinfo options for check_output to avoid console popping up on windows
if is_win():
startupinfo = STARTUPINFO()
startupinfo.dwFlags |= STARTF_USESHOWWINDOW
else:
startupinfo = None
runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo)
except CalledProcessError as e:
runlog = e.output
except Exception:
trace_error_handler(log)
runlog = ''
log.debug('check_output returned: %s' % runlog)
# Analyse the output to see it the program is mudraw, ghostscript or neither
for line in runlog.splitlines():
decoded_line = line.decode()
@ -148,7 +161,7 @@ class PdfController(PresentationController):
if os.path.isfile(os.path.join(application_path, 'mudraw')):
self.mudrawbin = os.path.join(application_path, 'mudraw')
if self.mudrawbin:
self.also_supports = ['xps']
self.also_supports = ['xps', 'oxps']
return True
elif self.gsbin:
return True
@ -182,6 +195,12 @@ class PdfDocument(PresentationDocument):
self.hidden = False
self.image_files = []
self.num_pages = -1
# Setup startupinfo options for check_output to avoid console popping up on windows
if is_win():
self.startupinfo = STARTUPINFO()
self.startupinfo.dwFlags |= STARTF_USESHOWWINDOW
else:
self.startupinfo = None
def gs_get_resolution(self, size):
"""
@ -199,7 +218,8 @@ class PdfDocument(PresentationDocument):
runlog = []
try:
runlog = check_output([self.controller.gsbin, '-dNOPAUSE', '-dNODISPLAY', '-dBATCH',
'-sFile=' + self.file_path, gs_resolution_script])
'-sFile=' + self.file_path, gs_resolution_script],
startupinfo=self.startupinfo)
except CalledProcessError as e:
log.debug(' '.join(e.cmd))
log.debug(e.output)
@ -248,13 +268,14 @@ class PdfDocument(PresentationDocument):
os.makedirs(self.get_temp_folder())
if self.controller.mudrawbin:
runlog = check_output([self.controller.mudrawbin, '-w', str(size.right()), '-h', str(size.bottom()),
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path])
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path],
startupinfo=self.startupinfo)
elif self.controller.gsbin:
resolution = self.gs_get_resolution(size)
runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m',
'-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4',
'-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'),
self.file_path])
self.file_path], startupinfo=self.startupinfo)
created_files = sorted(os.listdir(self.get_temp_folder()))
for fn in created_files:
if os.path.isfile(os.path.join(self.get_temp_folder(), fn)):

View File

@ -239,6 +239,7 @@ class OpenLyrics(object):
def __init__(self, manager):
self.manager = manager
FormattingTags.load_tags()
def song_to_xml(self, song):
"""
@ -582,18 +583,20 @@ class OpenLyrics(object):
# Some tags have only start html e.g. {br}
'end html': tag.close.text if hasattr(tag, 'close') else '',
'protected': False,
}
# Add 'temporary' key in case the formatting tag should not be saved otherwise it is supposed that
# formatting tag is permanent.
if temporary:
openlp_tag['temporary'] = temporary
'temporary': temporary
}
found_tags.append(openlp_tag)
existing_tag_ids = [tag['start tag'] for tag in FormattingTags.get_html_tags()]
new_tags = [tag for tag in found_tags if tag['start tag'] not in existing_tag_ids]
# Do not save an empty list.
if new_tags:
FormattingTags.add_html_tags(new_tags)
FormattingTags.save_html_tags()
if not temporary:
custom_tags = [tag for tag in FormattingTags.get_html_tags()
if not tag['protected'] and not tag['temporary']]
FormattingTags.save_html_tags(custom_tags)
def _process_lines_mixed_content(self, element, newlines=True):
"""

View File

@ -71,7 +71,7 @@ class TestMediaItem(TestCase, TestMixin):
pdf_controller = MagicMock()
pdf_controller.enabled.return_value = True
pdf_controller.supports = ['pdf']
pdf_controller.also_supports = ['xps']
pdf_controller.also_supports = ['xps', 'oxps']
# Mock the controllers.
self.media_item.controllers = {
'Impress': impress_controller,
@ -90,3 +90,4 @@ class TestMediaItem(TestCase, TestMixin):
self.assertIn('*.ppt', self.media_item.on_new_file_masks, 'The file mask should contain the ppt extension')
self.assertIn('*.pdf', self.media_item.on_new_file_masks, 'The file mask should contain the pdf extension')
self.assertIn('*.xps', self.media_item.on_new_file_masks, 'The file mask should contain the xps extension')
self.assertIn('*.oxps', self.media_item.on_new_file_masks, 'The file mask should contain the oxps extension')

View File

@ -132,6 +132,7 @@ class TestRouter(TestCase, TestMixin):
Test the main poll logic
"""
# GIVEN: a defined router with two slides
Registry.create()
Registry().register('live_controller', MagicMock)
router = HttpRouter()
router.send_response = MagicMock()

View File

@ -35,6 +35,7 @@ from unittest import TestCase
from tests.functional import MagicMock, patch
from openlp.core.common import Registry
from openlp.plugins.songs.lib.importers.easyworship import EasyWorshipSongImport, FieldDescEntry, FieldType
TEST_PATH = os.path.abspath(
@ -153,6 +154,11 @@ class TestEasyWorshipSongImport(TestCase):
"""
Test the functions in the :mod:`ewimport` module.
"""
def setUp(self):
"""
Create the registry
"""
Registry.create()
def create_field_desc_entry_test(self):
"""

View File

@ -31,11 +31,18 @@ This module contains tests for the OpenLyrics song importer.
"""
import os
import json
from unittest import TestCase
from lxml import etree, objectify
from tests.functional import MagicMock, patch
from tests.helpers.testmixin import TestMixin
from openlp.plugins.songs.lib.importers.openlyrics import OpenLyricsImport
from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
from openlp.core.common import Registry, Settings
from openlp.core.lib import FormattingTags
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', 'resources', 'openlyricssongs'))
@ -59,11 +66,33 @@ SONG_TEST_DATA = {
}
}
start_tags = [{"protected": False, "desc": "z", "start tag": "{z}", "end html": "</strong>", "temporary": False,
"end tag": "{/z}", "start html": "strong>"}]
result_tags = [{"temporary": False, "protected": False, "desc": "z", "start tag": "{z}", "start html": "strong>",
"end html": "</strong>", "end tag": "{/z}"},
{"temporary": False, "end tag": "{/c}", "desc": "c", "start tag": "{c}",
"start html": "<span class=\"chord\" style=\"display:none\"><strong>", "end html": "</strong></span>",
"protected": False}]
class TestOpenLyricsImport(TestCase):
class TestOpenLyricsImport(TestCase, TestMixin):
"""
Test the functions in the :mod:`openlyricsimport` module.
"""
def setUp(self):
"""
Create the registry
"""
self.get_application()
Registry.create()
self.build_settings()
def tearDown(self):
"""
Cleanup
"""
self.destroy_settings()
def create_importer_test(self):
"""
Test creating an instance of the OpenLyrics file importer
@ -97,3 +126,24 @@ class TestOpenLyricsImport(TestCase):
# THEN: The xml_to_song() method should have been called
self.assertTrue(importer.open_lyrics.xml_to_song.called)
def process_formatting_tags_test(self):
"""
Test that _process_formatting_tags works
"""
# GIVEN: A OpenLyric XML with formatting tags and a mocked out manager
mocked_manager = MagicMock()
Settings().setValue('formattingTags/html_tags', json.dumps(start_tags))
ol = OpenLyrics(mocked_manager)
parser = etree.XMLParser(remove_blank_text=True)
parsed_file = etree.parse(open(os.path.join(TEST_PATH, 'duchu-tags.xml'), 'rb'), parser)
xml = etree.tostring(parsed_file).decode()
song_xml = objectify.fromstring(xml)
# WHEN: processing the formatting tags
ol._process_formatting_tags(song_xml, False)
# THEN: New tags should have been saved
self.assertListEqual(json.loads(json.dumps(result_tags)),
json.loads(str(Settings().value('formattingTags/html_tags'))),
'The formatting tags should contain both the old and the new')

View File

@ -35,6 +35,7 @@ from unittest import TestCase
from tests.helpers.songfileimport import SongImportTestHelper
from openlp.plugins.songs.lib.importers.opensong import OpenSongImport
from openlp.core.common import Registry
from tests.functional import patch, MagicMock
TEST_PATH = os.path.abspath(
@ -64,6 +65,12 @@ class TestOpenSongImport(TestCase):
"""
Test the functions in the :mod:`opensongimport` module.
"""
def setUp(self):
"""
Create the registry
"""
Registry.create()
def create_importer_test(self):
"""
Test creating an instance of the OpenSong file importer

View File

@ -34,6 +34,7 @@ ProPresenter song files into the current installation database.
import os
from tests.helpers.songfileimport import SongImportTestHelper
from openlp.core.common import Registry
TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'powerpraisesongs'))

View File

@ -36,6 +36,7 @@ from unittest import TestCase
from tests.functional import MagicMock, patch
from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport
from openlp.plugins.songs.lib import VerseType
from openlp.core.common import Registry
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', 'resources', 'songbeamersongs'))
@ -59,6 +60,12 @@ class TestSongBeamerImport(TestCase):
"""
Test the functions in the :mod:`songbeamerimport` module.
"""
def setUp(self):
"""
Create the registry
"""
Registry.create()
def create_importer_test(self):
"""
Test creating an instance of the SongBeamer file importer

View File

@ -35,12 +35,19 @@ from unittest import TestCase
from tests.functional import MagicMock, patch
from openlp.plugins.songs.lib.importers.zionworx import ZionWorxImport
from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.core.common import Registry
class TestZionWorxImport(TestCase):
"""
Test the functions in the :mod:`zionworximport` module.
"""
def setUp(self):
"""
Create the registry
"""
Registry.create()
def create_importer_test(self):
"""
Test creating an instance of the ZionWorx file importer

View File

@ -34,6 +34,8 @@ import json
import logging
from unittest import TestCase
from openlp.plugins.songs.lib.importers.opensong import OpenSongImport
from openlp.core.common import Registry
from tests.functional import patch, MagicMock, call
log = logging.getLogger(__name__)
@ -53,6 +55,7 @@ class SongImportTestHelper(TestCase):
"""
Patch and set up the mocks required.
"""
Registry.create()
self.add_copyright_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_copyright' %
(self.importer_module_name, self.importer_class_name))
self.add_verse_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_verse' %

View File

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='utf-8'?>
<song xmlns="http://openlyrics.info/namespace/2009/song" version="0.8" createdIn="OpenLP 2.0.4" modifiedIn="OpenLP 2.0.4" modifiedDate="2014-06-27T09:55:49">
<properties>
<titles>
<title>Duchu svätý volám príď &lt;akordy&gt;</title>
</titles>
<authors>
<author>Author Unknown</author>
</authors>
</properties>
<format>
<tags application="OpenLP">
<tag name="c">
<open>&lt;span class="chord" style="display:none"&gt;&lt;strong&gt;</open>
<close>&lt;/strong&gt;&lt;/span&gt;</close>
</tag>
</tags>
</format>
<lyrics>
<verse name="v1">
<lines><tag name="c">[D]</tag>Duchu svätý volám príď, <tag name="c">[Ami]</tag>oheň mojej duši daj,<br/><tag name="c">[G]</tag>Oheň môjmu telu daj, <tag name="c">[D]</tag>rozpáľ ma.</lines>
</verse>
<verse name="c1">
<lines>Všemoh<tag name="c">[Ami]</tag>úci <tag name="c">[G]</tag>Boh tu s nami <tag name="c">[D]</tag>je,<br/>neko<tag name="c">[Ami]</tag>nečne <tag name="c">[G]</tag>milostivý <tag name="c">[D]</tag>je,<br/>Uka<tag name="c">[Ami]</tag>zuje <tag name="c">[G]</tag>dobrotivú <tag name="c">[D]</tag>tvár voči <tag name="c">[Ami]</tag>t<tag name="c">[G]</tag>ým,<br/>ktorí milovať ho <tag name="c">[D]</tag>chcú.</lines>
</verse>
</lyrics>
</song>