From 598d715de6821efed36b836059ddf189331bb560 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 3 Jun 2016 17:15:19 -0700 Subject: [PATCH 01/17] Initial string conversions for variable templates --- openlp/core/common/uistrings.py | 9 +- openlp/core/lib/__init__.py | 3 +- openlp/core/lib/filedialog.py | 4 +- openlp/core/lib/htmlbuilder.py | 152 +++++++++--------- openlp/core/lib/renderer.py | 17 +- openlp/core/lib/theme.py | 4 +- openlp/core/ui/exceptionform.py | 30 ++-- openlp/core/ui/firsttimeform.py | 16 +- openlp/core/ui/mainwindow.py | 2 +- openlp/core/ui/pluginform.py | 24 +-- openlp/core/ui/themeform.py | 6 +- openlp/core/ui/thememanager.py | 2 +- .../openlp_core_lib/test_file_dialog.py | 2 +- 13 files changed, 142 insertions(+), 129 deletions(-) diff --git a/openlp/core/common/uistrings.py b/openlp/core/common/uistrings.py index 91db10fcf..91d947ade 100644 --- a/openlp/core/common/uistrings.py +++ b/openlp/core/common/uistrings.py @@ -80,8 +80,9 @@ class UiStrings(object): self.Export = translate('OpenLP.Ui', 'Export') self.File = translate('OpenLP.Ui', 'File') self.FileNotFound = translate('OpenLP.Ui', 'File Not Found') - # TODO: Check before converting to python3 string - self.FileNotFoundMessage = translate('OpenLP.Ui', 'File %s not found.\nPlease try selecting it individually.') + # TODO: Passed nose - verify in real life example + self.FileNotFoundMessage = translate('OpenLP.Ui', + 'File {name} not found.\nPlease try selecting it individually.') self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit') self.Help = translate('OpenLP.Ui', 'Help') self.Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours') @@ -140,8 +141,8 @@ class UiStrings(object): self.Split = translate('OpenLP.Ui', 'Optional &Split') self.SplitToolTip = translate('OpenLP.Ui', 'Split a slide into two only if it does not fit on the screen as one slide.') - # TODO: Check before converting to python3 string - self.StartTimeCode = translate('OpenLP.Ui', 'Start %s') + # TODO: WHERE is this used at? cannot find where it's used at in code. + self.StartTimeCode = translate('OpenLP.Ui', 'Start {code}') self.StopPlaySlidesInLoop = translate('OpenLP.Ui', 'Stop Play Slides in Loop') self.StopPlaySlidesToEnd = translate('OpenLP.Ui', 'Stop Play Slides to End') self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular') diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index a7e01bd24..80da92cde 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -323,8 +323,7 @@ def create_separated_list(string_list): return '' elif len(string_list) == 1: return string_list[0] - # TODO: - # Cannot convert these strings to python3 yet until I can figure out how to mock translate() with the new format + # TODO: Verify mocking of translate() test before conversion elif len(string_list) == 2: return translate('OpenLP.core.lib', '%s and %s', 'Locale list separator: 2 items') % (string_list[0], string_list[1]) diff --git a/openlp/core/lib/filedialog.py b/openlp/core/lib/filedialog.py index 249f7959d..e976f9c15 100644 --- a/openlp/core/lib/filedialog.py +++ b/openlp/core/lib/filedialog.py @@ -51,9 +51,9 @@ class FileDialog(QtWidgets.QFileDialog): file = parse.unquote(file) if not os.path.exists(file): log.error('File {text} not found.'.format(text=file)) - # TODO: Test with UiStrings() before converting to python3 strings + # TODO: Should work - need to verify QtWidgets.QMessageBox.information(parent, UiStrings().FileNotFound, - UiStrings().FileNotFoundMessage % file) + UiStrings().FileNotFoundMessage.format(name=file)) continue file_list.append(file) return file_list diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index f0d8ddef2..ffe9f05cc 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -396,74 +396,74 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, Vertic log = logging.getLogger(__name__) -# TODO: Verify where this is used before converting to python3 +# TODO: Tested at home HTMLSRC = """ OpenLP Display - - -%s + + +{html_additions}
@@ -582,17 +582,17 @@ def build_html(item, screen, is_live, background, image=None, plugins=None): css_additions += plugin.get_display_css() js_additions += plugin.get_display_javascript() html_additions += plugin.get_display_html() - html = HTMLSRC % ( - build_background_css(item, width), - css_additions, - build_footer_css(item, height), - build_lyrics_css(item), - 'true' if theme_data and theme_data.display_slide_transition and is_live else 'false', - js_additions, - bgimage_src, - image_src, - html_additions - ) + html = HTMLSRC.format(background_css=build_background_css(item, width), + additions=css_additions, + footer_css=build_footer_css(item, height), + lyrics_css=build_lyrics_css(item), + transitions='true' if (theme_data and + theme_data.display_slide_transition and + is_live) else 'false', + js_additions=js_additions, + bgimage=bgimage_src, + image=image_src, + html_additions=html_additions) return html @@ -650,23 +650,23 @@ def build_lyrics_css(item): :param item: Service Item containing theme and location information """ - # TODO: Verify this before converting to python3 + # TODO: Tested at home style = """ -.lyricstable { +.lyricstable {{ z-index: 5; position: absolute; display: table; - %s -} -.lyricscell { + {stable} +}} +.lyricscell {{ display: table-cell; word-wrap: break-word; -webkit-transition: opacity 0.4s ease; - %s -} -.lyricsmain { - %s -} + {lyrics} +}} +.lyricsmain {{ + {main} +}} """ theme_data = item.theme_data lyricstable = '' @@ -680,7 +680,7 @@ def build_lyrics_css(item): lyricsmain += ' text-shadow: {theme} {shadow}px ' \ '{shadow}px;'.format(theme=theme_data.font_main_shadow_color, shadow=theme_data.font_main_shadow_size) - lyrics_css = style % (lyricstable, lyrics, lyricsmain) + lyrics_css = style.format(stable=lyricstable, lyrics=lyrics, main=lyricsmain) return lyrics_css diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 0d233a9c4..c42a55741 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -370,21 +370,22 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): self.web.resize(self.page_width, self.page_height) self.web_frame = self.web.page().mainFrame() # Adjust width and height to account for shadow. outline done in css. - # TODO: Verify before converting to python3 strings + # TODO: Tested at home html = """ -
""" % \ - (build_lyrics_format_css(theme_data, self.page_width, self.page_height), - build_lyrics_outline_css(theme_data)) + }} + +
""".format(format_css=build_lyrics_format_css(theme_data, + self.page_width, + self.page_height), + outline_css=build_lyrics_outline_css(theme_data)) self.web.setHtml(html) self.empty_height = self.web_frame.contentsSize().height() diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index 4e84d353b..8f29d9a3d 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -513,8 +513,8 @@ class ThemeXML(object): theme_strings = [] for key in dir(self): if key[0:1] != '_': - # TODO: Verify spacing format before converting to python3 string - theme_strings.append('%30s: %s' % (key, getattr(self, key))) + # TODO: Tested at home + theme_strings.append('{key:>30}: {value}'.format(key=key, value=getattr(self, key))) return '\n'.join(theme_strings) def _build_xml_from_attrs(self): diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 216780584..849ec291c 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -91,13 +91,13 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): super(ExceptionForm, self).__init__(None, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.setupUi(self) self.settings_section = 'crashreport' - # TODO: Need to see how to format strings when string with tags is actually a variable + # TODO: Should work - need to test self.report_text = '**OpenLP Bug Report**\n' \ - 'Version: %s\n\n' \ - '--- Details of the Exception. ---\n\n%s\n\n ' \ - '--- Exception Traceback ---\n%s\n' \ - '--- System information ---\n%s\n' \ - '--- Library Versions ---\n%s\n' + 'Version: {version}\n\n' \ + '--- Details of the Exception. ---\n\n{description}\n\n ' \ + '--- Exception Traceback ---\n{traceback}\n' \ + '--- System information ---\n{system}\n' \ + '--- Library Versions ---\n{libs}\n' def exec(self): """ @@ -133,7 +133,15 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): system += 'Desktop: GNOME\n' elif os.environ.get('DESKTOP_SESSION') == 'xfce': system += 'Desktop: Xfce\n' - return openlp_version, description, traceback, system, libraries + # NOTE: This needs to return a string that format() will use. See __init__.self.report_text for names. + return ("version='{version}', " + "description='{description}', " + "traceback='{traceback}', " + "libs='{libs}'").format(version=openlp_version, + description=description, + traceback=traceback, + system=system, + libs=libraries) def on_save_report_button_clicked(self): """ @@ -147,7 +155,8 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): if filename: filename = str(filename).replace('/', os.path.sep) Settings().setValue(self.settings_section + '/last directory', os.path.dirname(filename)) - report_text = self.report_text % self._create_report() + # NOTE: self._create_report() should return a string with the key names for format() + report_text = self.report_text.format(self._create_report()) try: report_file = open(filename, 'w') try: @@ -167,6 +176,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): """ Opening systems default email client and inserting exception log and system information. """ + # NOTE: self._create_report() should return a string with keys for format() content = self._create_report() source = '' exception = '' @@ -178,8 +188,8 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): subject = 'Bug report: {error} in {source}'.format(error=exception, source=source) mail_urlquery = QtCore.QUrlQuery() mail_urlquery.addQueryItem('subject', subject) - # TODO: Find out how to format() text that is in a variable - mail_urlquery.addQueryItem('body', self.report_text % content) + # TODO: Should be good - need to test + mail_urlquery.addQueryItem('body', self.report_text.format(content)) if self.file_attachment: mail_urlquery.addQueryItem('attach', self.file_attachment) mail_to_url = QtCore.QUrl('mailto:bugs@openlp.org') diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index cadb4814f..b9ba00f69 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -207,8 +207,8 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): trace_error_handler(log) self.update_screen_list_combo() self.application.process_events() - # TODO: Figure out how to use a variable with format() - self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...') + # TODO: Tested at home + self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading {name}...') if self.has_run_wizard: self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active()) self.bible_check_box.setChecked(self.plugin_manager.get_plugin_by_name('bibles').is_active()) @@ -564,7 +564,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): self.progress_bar.setValue(self.progress_bar.maximum()) if self.has_run_wizard: text = translate('OpenLP.FirstTimeWizard', - 'Download complete. Click the {button} button to return to OpenLP.' + 'Download complete. Click the {text} button to return to OpenLP.' ).format(text=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) self.progress_label.setText(text) else: @@ -632,7 +632,8 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): item = self.songs_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: filename, sha256 = item.data(QtCore.Qt.UserRole) - self._increment_progress_bar(self.downloading % filename, 0) + # TODO: Tested at home + self._increment_progress_bar(self.downloading.format(name=filename), 0) self.previous_size = 0 destination = os.path.join(songs_destination, str(filename)) if not self.url_get_file('{path}{name}'.format(path=self.songs_url, name=filename), @@ -644,7 +645,8 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): item = bibles_iterator.value() if item.parent() and item.checkState(0) == QtCore.Qt.Checked: bible, sha256 = item.data(0, QtCore.Qt.UserRole) - self._increment_progress_bar(self.downloading % bible, 0) + # TODO: Tested at home + self._increment_progress_bar(self.downloading.format(name=bible), 0) self.previous_size = 0 if not self.url_get_file('{path}{name}'.format(path=self.bibles_url, name=bible), os.path.join(bibles_destination, bible), @@ -656,8 +658,8 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): item = self.themes_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: theme, sha256 = item.data(QtCore.Qt.UserRole) - # TODO: Verify how to use format() with strings in a variable - self._increment_progress_bar(self.downloading % theme, 0) + # TODO: Tested at home + self._increment_progress_bar(self.downloading.format(name=theme), 0) self.previous_size = 0 if not self.url_get_file('{path}{name}'.format(path=self.themes_url, name=theme), os.path.join(themes_destination, theme), diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index ccd12727c..7187ab7e3 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -1334,7 +1334,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties): self.recent_files_menu.clear() for file_id, filename in enumerate(recent_files_to_display): log.debug('Recent file name: {name}'.format(name=filename)) - # TODO: Verify ''.format() before committing + # TODO: Should be good action = create_action(self, '', text='&{n} {name}'.format(n=file_id + 1, name=os.path.splitext(os.path.basename(str(filename)))[0]), diff --git a/openlp/core/ui/pluginform.py b/openlp/core/ui/pluginform.py index 4280bcd25..75bf9652d 100644 --- a/openlp/core/ui/pluginform.py +++ b/openlp/core/ui/pluginform.py @@ -60,7 +60,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties): self._clear_details() self.programatic_change = True plugin_list_width = 0 - # TODO: See how to use format() with variables + # TODO: Tested at home for plugin in self.plugin_manager.plugins: item = QtWidgets.QListWidgetItem(self.plugin_list_widget) # We do this just to make 100% sure the status is an integer as @@ -68,19 +68,19 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties): plugin.status = int(plugin.status) # Set the little status text in brackets next to the plugin name. if plugin.status == PluginStatus.Disabled: - status_text = translate('OpenLP.PluginForm', '%s (Disabled)') + status_text = translate('OpenLP.PluginForm', '{name} (Disabled)') elif plugin.status == PluginStatus.Active: - status_text = translate('OpenLP.PluginForm', '%s (Active)') + status_text = translate('OpenLP.PluginForm', '{name} (Active)') else: # PluginStatus.Inactive - status_text = translate('OpenLP.PluginForm', '%s (Inactive)') - item.setText(status_text % plugin.name_strings['singular']) + status_text = translate('OpenLP.PluginForm', '{name} (Inactive)') + item.setText(status_text.format(name=plugin.name_strings['singular'])) # If the plugin has an icon, set it! if plugin.icon: item.setIcon(plugin.icon) self.plugin_list_widget.addItem(item) plugin_list_width = max(plugin_list_width, self.fontMetrics().width( - translate('OpenLP.PluginForm', '%s (Inactive)') % plugin.name_strings['singular'])) + translate('OpenLP.PluginForm', '{name} (Inactive)').format(name=plugin.name_strings['singular']))) self.plugin_list_widget.setFixedWidth(plugin_list_width + self.plugin_list_widget.iconSize().width() + 48) def _clear_details(self): @@ -137,13 +137,13 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties): self.active_plugin.app_startup() else: self.active_plugin.toggle_status(PluginStatus.Inactive) - # TODO: Verify using format() with a variable - status_text = translate('OpenLP.PluginForm', '%s (Inactive)') + # TODO: Tested at home + status_text = translate('OpenLP.PluginForm', '{name} (Inactive)') if self.active_plugin.status == PluginStatus.Active: - status_text = translate('OpenLP.PluginForm', '%s (Active)') + status_text = translate('OpenLP.PluginForm', '{name} (Active)') elif self.active_plugin.status == PluginStatus.Inactive: - status_text = translate('OpenLP.PluginForm', '%s (Inactive)') + status_text = translate('OpenLP.PluginForm', '{name} (Inactive)') elif self.active_plugin.status == PluginStatus.Disabled: - status_text = translate('OpenLP.PluginForm', '%s (Disabled)') + status_text = translate('OpenLP.PluginForm', '{name} (Disabled)') self.plugin_list_widget.currentItem().setText( - status_text % self.active_plugin.name_strings['singular']) + status_text.format(name=self.active_plugin.name_strings['singular'])) diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 475bfc0b7..f6faee1ec 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -464,9 +464,9 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): """ Background video button pushed. """ - # TODO: Check this before converting - visible_formats = '(%s)' % '; '.join(VIDEO_EXT) - actual_formats = '(%s)' % ' '.join(VIDEO_EXT) + # TODO: Should work + visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT)) + actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT)) video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'), visible=visible_formats, actual=actual_formats) video_filter = '{video};;{ui} (*.*)'.format(video=video_filter, ui=UiStrings().AllFiles) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 70ca9fd88..928e3f6b3 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -769,7 +769,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage '{count} time(s) by {plugin}' ).format(name=used_count, plugin=plugin.name))) - plugin_usage = "%s\n" % plugin_usage + plugin_usage = "{text}\n".format(text=plugin_usage) if plugin_usage: critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'), translate('OpenLP.ThemeManager', diff --git a/tests/functional/openlp_core_lib/test_file_dialog.py b/tests/functional/openlp_core_lib/test_file_dialog.py index 252ce3190..238b398d3 100644 --- a/tests/functional/openlp_core_lib/test_file_dialog.py +++ b/tests/functional/openlp_core_lib/test_file_dialog.py @@ -60,7 +60,7 @@ class TestFileDialog(TestCase): self.mocked_os.path.exists.side_effect = lambda file_name: file_name in [ '/Valid File', '/url encoded file #1'] self.mocked_ui_strings().FileNotFound = 'File Not Found' - self.mocked_ui_strings().FileNotFoundMessage = 'File %s not found.\nPlease try selecting it individually.' + self.mocked_ui_strings().FileNotFoundMessage = 'File {name} not found.\nPlease try selecting it individually.' # WHEN: FileDialog.getOpenFileNames is called result = FileDialog.getOpenFileNames(self.mocked_parent) From ed7ea01f43b318526d06def9ec36d1d69db6a2dc Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 3 Jun 2016 22:38:51 -0700 Subject: [PATCH 02/17] Tests fixes and updates --- .../test_registryproperties.py | 1 - .../openlp_core_lib/test_projector_pjlink1.py | 20 +++---------------- .../openlp_core_lib/test_projectordb.py | 13 ++++++++++++ .../openlp_plugins/bibles/test_lib.py | 1 + .../openlp_plugins/songs/test_opsproimport.py | 1 - 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/tests/functional/openlp_core_common/test_registryproperties.py b/tests/functional/openlp_core_common/test_registryproperties.py index 98408b323..45eb4d45e 100644 --- a/tests/functional/openlp_core_common/test_registryproperties.py +++ b/tests/functional/openlp_core_common/test_registryproperties.py @@ -75,4 +75,3 @@ class TestRegistryProperties(TestCase, RegistryProperties): # THEN the application should be none self.assertEqual(self.application, application, 'The application value should match') - diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 4928e5d0c..01ddde060 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -29,26 +29,12 @@ from openlp.core.lib.projector.pjlink1 import PJLink1 from openlp.core.lib.projector.constants import E_PARAMETER, ERROR_STRING, S_OFF, S_STANDBY, S_WARMUP, S_ON, \ S_COOLDOWN, PJLINK_POWR_STATUS -from tests.functional import patch +from tests.functional import MagicMock, patch from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True) -class DummyTimer(object): - ''' - Dummy class to fake timers - ''' - def __init__(self, *args, **kwargs): - pass - - def start(self, *args, **kwargs): - pass - - def stop(self, *args, **kwargs): - pass - - class TestPJLink(TestCase): """ Tests for the PJLink module @@ -308,8 +294,8 @@ class TestPJLink(TestCase): pjlink.other_info = 'ANOTHER TEST' pjlink.send_queue = True pjlink.send_busy = True - pjlink.timer = DummyTimer() - pjlink.socket_timer = DummyTimer() + pjlink.timer = MagicMock() + pjlink.socket_timer = MagicMock() # WHEN: reset_information() is called with patch.object(pjlink.timer, 'stop') as mock_timer: diff --git a/tests/functional/openlp_core_lib/test_projectordb.py b/tests/functional/openlp_core_lib/test_projectordb.py index 61263042f..0b780acd2 100644 --- a/tests/functional/openlp_core_lib/test_projectordb.py +++ b/tests/functional/openlp_core_lib/test_projectordb.py @@ -284,3 +284,16 @@ class TestProjectorDB(TestCase): self.assertEqual(str(source), '', 'ProjectorSource.__repr__)_ should have returned a proper representation string') + + def test_get_projector_by_id_none(self): + """ + Test get_projector_by_id returns None if no db entry + """ + # GIVEN: Test object and data + projector = self.projector + + # WHEN: DB search for entry not saved + results = projector.get_projector_by_id(dbid=123134556409824506) + + # THEN: Verify return was None + self.assertEqual(results, None, 'Returned results should have equaled None') diff --git a/tests/functional/openlp_plugins/bibles/test_lib.py b/tests/functional/openlp_plugins/bibles/test_lib.py index a8dba0bd9..27d7f5e51 100644 --- a/tests/functional/openlp_plugins/bibles/test_lib.py +++ b/tests/functional/openlp_plugins/bibles/test_lib.py @@ -43,6 +43,7 @@ class TestLib(TestCase): separators = {'sep_r': '\\s*(?:e)\\s*', 'sep_e_default': 'end', 'sep_v_display': 'w', 'sep_l_display': 'r', 'sep_v_default': ':|v|V|verse|verses', 'sep_l': '\\s*(?:r)\\s*', 'sep_l_default': ',|and', 'sep_e': '\\s*(?:t)\\s*', 'sep_v': '\\s*(?:w)\\s*', 'sep_r_display': 'e', 'sep_r_default': '-|to'} + def _update_side_effect(): """ Update the references after mocking out the method diff --git a/tests/functional/openlp_plugins/songs/test_opsproimport.py b/tests/functional/openlp_plugins/songs/test_opsproimport.py index 239b77c30..8db69b609 100644 --- a/tests/functional/openlp_plugins/songs/test_opsproimport.py +++ b/tests/functional/openlp_plugins/songs/test_opsproimport.py @@ -171,4 +171,3 @@ class TestOpsProSongImport(TestCase): result_data = json.loads(result_file.read().decode()) self.assertListEqual(importer.verses, _get_item(result_data, 'verses')) self.assertListEqual(importer.verse_order_list_generated, _get_item(result_data, 'verse_order_list')) - From a4483af5b4c699142eff5658f7a3df073d219e59 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sat, 4 Jun 2016 01:03:25 -0700 Subject: [PATCH 03/17] Revert htmlbuilder for now --- openlp/core/lib/htmlbuilder.py | 152 ++++++++++++++++----------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index ffe9f05cc..f0d8ddef2 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -396,74 +396,74 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, Vertic log = logging.getLogger(__name__) -# TODO: Tested at home +# TODO: Verify where this is used before converting to python3 HTMLSRC = """ OpenLP Display - - -{html_additions} + + +%s
@@ -582,17 +582,17 @@ def build_html(item, screen, is_live, background, image=None, plugins=None): css_additions += plugin.get_display_css() js_additions += plugin.get_display_javascript() html_additions += plugin.get_display_html() - html = HTMLSRC.format(background_css=build_background_css(item, width), - additions=css_additions, - footer_css=build_footer_css(item, height), - lyrics_css=build_lyrics_css(item), - transitions='true' if (theme_data and - theme_data.display_slide_transition and - is_live) else 'false', - js_additions=js_additions, - bgimage=bgimage_src, - image=image_src, - html_additions=html_additions) + html = HTMLSRC % ( + build_background_css(item, width), + css_additions, + build_footer_css(item, height), + build_lyrics_css(item), + 'true' if theme_data and theme_data.display_slide_transition and is_live else 'false', + js_additions, + bgimage_src, + image_src, + html_additions + ) return html @@ -650,23 +650,23 @@ def build_lyrics_css(item): :param item: Service Item containing theme and location information """ - # TODO: Tested at home + # TODO: Verify this before converting to python3 style = """ -.lyricstable {{ +.lyricstable { z-index: 5; position: absolute; display: table; - {stable} -}} -.lyricscell {{ + %s +} +.lyricscell { display: table-cell; word-wrap: break-word; -webkit-transition: opacity 0.4s ease; - {lyrics} -}} -.lyricsmain {{ - {main} -}} + %s +} +.lyricsmain { + %s +} """ theme_data = item.theme_data lyricstable = '' @@ -680,7 +680,7 @@ def build_lyrics_css(item): lyricsmain += ' text-shadow: {theme} {shadow}px ' \ '{shadow}px;'.format(theme=theme_data.font_main_shadow_color, shadow=theme_data.font_main_shadow_size) - lyrics_css = style.format(stable=lyricstable, lyrics=lyrics, main=lyricsmain) + lyrics_css = style % (lyricstable, lyrics, lyricsmain) return lyrics_css From b627736e5e4c1041c19c135a8772d5cfe4011958 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Wed, 15 Jun 2016 08:05:05 -0700 Subject: [PATCH 04/17] Convert renderer string to Template() --- openlp/core/lib/renderer.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index c42a55741..ba4a5563e 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -22,6 +22,7 @@ import re +from string import Template from PyQt5 import QtGui, QtCore, QtWebKitWidgets from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, RegistryMixin, Settings @@ -371,22 +372,22 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): self.web_frame = self.web.page().mainFrame() # Adjust width and height to account for shadow. outline done in css. # TODO: Tested at home - html = """ -
""".format(format_css=build_lyrics_format_css(theme_data, - self.page_width, - self.page_height), - outline_css=build_lyrics_outline_css(theme_data)) - self.web.setHtml(html) + } + +
""") + self.web.setHtml(html.substitute(format_css=build_lyrics_format_css(theme_data, + self.page_width, + self.page_height), + outline_css=build_lyrics_outline_css(theme_data))) self.empty_height = self.web_frame.contentsSize().height() def _paginate_slide(self, lines, line_end): From 7a8b519b8c3559c11f4728bb1565d47e2fdc97d0 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 16 Jun 2016 07:44:32 -0700 Subject: [PATCH 05/17] Add test for renderer change to template string --- openlp/core/lib/renderer.py | 9 ++-- .../openlp_core_lib/test_renderer.py | 44 +++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index ba4a5563e..2646a7f40 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -381,9 +381,12 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): // returned value). return main.offsetHeight; } - -
""") + + +
""") self.web.setHtml(html.substitute(format_css=build_lyrics_format_css(theme_data, self.page_width, self.page_height), diff --git a/tests/functional/openlp_core_lib/test_renderer.py b/tests/functional/openlp_core_lib/test_renderer.py index a08fc8674..eac6a929b 100644 --- a/tests/functional/openlp_core_lib/test_renderer.py +++ b/tests/functional/openlp_core_lib/test_renderer.py @@ -29,6 +29,7 @@ from PyQt5 import QtCore from openlp.core.common import Registry from openlp.core.lib import Renderer, ScreenList, ServiceItem, FormattingTags from openlp.core.lib.renderer import words_split, get_start_tags +from openlp.core.lib.theme import ThemeXML from tests.functional import MagicMock, patch @@ -39,6 +40,24 @@ SCREEN = { } +# WARNING: Leave formatting alone - this is how it's returned in renderer.py +CSS_TEST_ONE = """ + +
'""" + + class TestRenderer(TestCase): def setUp(self): @@ -159,3 +178,28 @@ class TestRenderer(TestCase): # THEN: The blanks have been removed. self.assertListEqual(result_words, expected_words) + + @patch('openlp.core.lib.renderer.QtWebKitWidgets.QWebView.setHtml') + @patch('openlp.core.lib.renderer.build_lyrics_format_css') + @patch('openlp.core.lib.renderer.build_lyrics_outline_css') + def test_set_text_rectangle(self, mock_outline_css, mock_lyrics_css, mock_webview): + """ + Test set_set_text_rectangle returns a proper html string + """ + # GIVEN: test object and data + mock_lyrics_css.return_value = ' FORMAT CSS; ' + mock_outline_css.return_value = ' OUTLINE CSS; ' + theme_data = ThemeXML() + theme_data.font_main_name = 'Arial' + theme_data.font_main_size = 20 + theme_data.font_main_color = '#FFFFFF' + theme_data.font_main_outline_color = '#FFFFFF' + main = QtCore.QRect(10, 10, 1280, 900) + foot = QtCore.QRect(10, 1000, 1260, 24) + renderer = Renderer() + + # WHEN: Calling methd + renderer._set_text_rectangle(theme_data=theme_data, rect_main=main, rect_footer=foot) + + # THEN: QtWebKitWidgets should be called with the proper string + mock_webview.setHtml.called_with(CSS_TEST_ONE, 'Should be the same') From 018f6f8af5b998d7c0686c131db43fc6e38c1347 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 16 Jun 2016 08:07:34 -0700 Subject: [PATCH 06/17] Fix spelling --- tests/functional/openlp_core_lib/test_renderer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_renderer.py b/tests/functional/openlp_core_lib/test_renderer.py index eac6a929b..ebc95adc3 100644 --- a/tests/functional/openlp_core_lib/test_renderer.py +++ b/tests/functional/openlp_core_lib/test_renderer.py @@ -179,12 +179,12 @@ class TestRenderer(TestCase): # THEN: The blanks have been removed. self.assertListEqual(result_words, expected_words) - @patch('openlp.core.lib.renderer.QtWebKitWidgets.QWebView.setHtml') + @patch('openlp.core.lib.renderer.QtWebKitWidgets.QWebView') @patch('openlp.core.lib.renderer.build_lyrics_format_css') @patch('openlp.core.lib.renderer.build_lyrics_outline_css') def test_set_text_rectangle(self, mock_outline_css, mock_lyrics_css, mock_webview): """ - Test set_set_text_rectangle returns a proper html string + Test set_text_rectangle returns a proper html string """ # GIVEN: test object and data mock_lyrics_css.return_value = ' FORMAT CSS; ' @@ -198,7 +198,7 @@ class TestRenderer(TestCase): foot = QtCore.QRect(10, 1000, 1260, 24) renderer = Renderer() - # WHEN: Calling methd + # WHEN: Calling method renderer._set_text_rectangle(theme_data=theme_data, rect_main=main, rect_footer=foot) # THEN: QtWebKitWidgets should be called with the proper string From 29043f0789c22033e9ec427e871d2ab5e659e5e0 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 08:30:23 -0700 Subject: [PATCH 07/17] string format error --- openlp/plugins/songs/lib/openlyricsxml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/openlyricsxml.py b/openlp/plugins/songs/lib/openlyricsxml.py index 5adffb300..8629bbb6e 100644 --- a/openlp/plugins/songs/lib/openlyricsxml.py +++ b/openlp/plugins/songs/lib/openlyricsxml.py @@ -643,7 +643,7 @@ class OpenLyrics(object): # Append text from tail and add formatting end tag. # TODO: Verify format() with template variables if element.tag == NSMAP % 'tag' and use_endtag: - text += '{/{name}}}'.format(name=element.get('name')) + text += '{{/{name}}}'.format(name=element.get('name')) # Append text from tail. if element.tail: text += element.tail From 467c6723399f8360b82885ac68d78ced43e5de45 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Wed, 22 Jun 2016 08:07:50 -0700 Subject: [PATCH 08/17] Typo --- openlp/plugins/bibles/lib/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index d1465475d..1c55222f2 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -370,7 +370,7 @@ class BibleManager(RegistryProperties): """ log.debug('save_meta data {bible}, {version}, {copyright}, {perms}'.format(bible=bible, version=version, - cr=copyright, + copyright=copyright, perms=permissions)) self.db_cache[bible].save_meta('name', version) self.db_cache[bible].save_meta('copyright', copyright) From c2d884df485fb7ccf0dbc784b11b3d3738a487d5 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 23 Jun 2016 21:28:23 -0700 Subject: [PATCH 09/17] Missing format key --- openlp/core/ui/exceptionform.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 849ec291c..962ebcd93 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -135,6 +135,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): system += 'Desktop: Xfce\n' # NOTE: This needs to return a string that format() will use. See __init__.self.report_text for names. return ("version='{version}', " + "system='{system}', " "description='{description}', " "traceback='{traceback}', " "libs='{libs}'").format(version=openlp_version, From d878d8b8cb7efd64f6e38f95089ad78fe3fe893d Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 23 Jun 2016 21:38:18 -0700 Subject: [PATCH 10/17] Missed closing paren --- openlp/core/ui/exceptionform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 962ebcd93..6f9f441e5 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -142,7 +142,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): description=description, traceback=traceback, system=system, - libs=libraries) + libs=libraries)) def on_save_report_button_clicked(self): """ From de754e2cb1b3d2b3935965c16d2b388a23990556 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 24 Jun 2016 05:39:47 -0700 Subject: [PATCH 11/17] Convert exceptionform._create_report to return dict --- openlp/core/ui/exceptionform.py | 31 ++-- .../openlp_core_ui/test_exceptionform.py | 133 ++++++++++++++++++ 2 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 tests/functional/openlp_core_ui/test_exceptionform.py diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 6f9f441e5..279230911 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -91,7 +91,6 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): super(ExceptionForm, self).__init__(None, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.setupUi(self) self.settings_section = 'crashreport' - # TODO: Should work - need to test self.report_text = '**OpenLP Bug Report**\n' \ 'Version: {version}\n\n' \ '--- Details of the Exception. ---\n\n{description}\n\n ' \ @@ -133,16 +132,9 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): system += 'Desktop: GNOME\n' elif os.environ.get('DESKTOP_SESSION') == 'xfce': system += 'Desktop: Xfce\n' - # NOTE: This needs to return a string that format() will use. See __init__.self.report_text for names. - return ("version='{version}', " - "system='{system}', " - "description='{description}', " - "traceback='{traceback}', " - "libs='{libs}'").format(version=openlp_version, - description=description, - traceback=traceback, - system=system, - libs=libraries)) + # NOTE: Keys match the expected input for self.report_text.format() + return {'version': openlp_version, 'description': description, 'traceback': traceback, + 'system': system, 'libs': libraries} def on_save_report_button_clicked(self): """ @@ -156,8 +148,9 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): if filename: filename = str(filename).replace('/', os.path.sep) Settings().setValue(self.settings_section + '/last directory', os.path.dirname(filename)) - # NOTE: self._create_report() should return a string with the key names for format() - report_text = self.report_text.format(self._create_report()) + opts = self._create_report() + report_text = self.report_text.format(version=opts['version'], description=opts['description'], + traceback=opts['traceback'], libs=ops['libs']) try: report_file = open(filename, 'w') try: @@ -177,11 +170,10 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): """ Opening systems default email client and inserting exception log and system information. """ - # NOTE: self._create_report() should return a string with keys for format() content = self._create_report() source = '' exception = '' - for line in content[2].split('\n'): + for line in content['traceback'].split('\n'): if re.search(r'[/\\]openlp[/\\]', line): source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line) if ':' in line: @@ -189,8 +181,11 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): subject = 'Bug report: {error} in {source}'.format(error=exception, source=source) mail_urlquery = QtCore.QUrlQuery() mail_urlquery.addQueryItem('subject', subject) - # TODO: Should be good - need to test - mail_urlquery.addQueryItem('body', self.report_text.format(content)) + mail_urlquery.addQueryItem('body', self.report_text.format(version=content['version'], + description=content['description'], + traceback=content['traceback'], + system=content['system'], + libs=content['libs'])) if self.file_attachment: mail_urlquery.addQueryItem('attach', self.file_attachment) mail_to_url = QtCore.QUrl('mailto:bugs@openlp.org') @@ -220,7 +215,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): Settings().value(self.settings_section + '/last directory'), '{text} (*)'.format(text=UiStrings().AllFiles)) - log.info('New files(s) %s', str(files)) + log.info('New files(s) {files}'.format(str(files))) if files: self.file_attachment = str(files) diff --git a/tests/functional/openlp_core_ui/test_exceptionform.py b/tests/functional/openlp_core_ui/test_exceptionform.py new file mode 100644 index 000000000..85ad4c975 --- /dev/null +++ b/tests/functional/openlp_core_ui/test_exceptionform.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +Package to test the openlp.core.ui.exeptionform package. +""" + +import os +import socket +import tempfile +import urllib +from unittest import TestCase +from unittest.mock import mock_open + +from PyQt5.QtCore import QUrlQuery + +from openlp.core.common import Registry +from openlp.core.ui.firsttimeform import FirstTimeForm + +from tests.functional import MagicMock, patch +from tests.helpers.testmixin import TestMixin + +from openlp.core.ui import exceptionform + +exceptionform.WEBKIT_VERSION = 'Webkit Test' +exceptionform.MIGRATE_VERSION = 'Migrate Test' +exceptionform.CHARDET_VERSION = 'CHARDET Test' +exceptionform.ENCHANT_VERSION = 'Enchant Test' +exceptionform.MAKO_VERSION = 'Mako Test' +exceptionform.ICU_VERSION = 'ICU Test' +exceptionform.VLC_VERSION = 'VLC Test' + +MAIL_ITEM_TEXT = ('**OpenLP Bug Report**\nVersion: Trunk Test\n\n--- Details of the Exception. ---\n\n' + 'Description Test\n\n --- Exception Traceback ---\nopenlp: Traceback Test\n' + '--- System information ---\nPlatform: Nose Test\n\n--- Library Versions ---\n' + 'Python: Python Test\nQt5: Qt5 test\nPyQt5: PyQT5 Test\nQtWebkit: Webkit Test\n' + 'SQLAlchemy: SqlAlchemy Test\nSQLAlchemy Migrate: Migrate Test\nBeautifulSoup: BeautifulSoup Test\n' + 'lxml: ETree Test\nChardet: CHARDET Test\nPyEnchant: Enchant Test\nMako: Mako Test\n' + 'pyICU: ICU Test\npyUNO bridge: UNO Bridge Test\nVLC: VLC Test\n\n') + + +class TestExceptionForm(TestMixin, TestCase): + """ + Test functionality of exception form functions + """ + def setUp(self): + self.setup_application() + self.app.setApplicationVersion('0.0') + # Set up a fake "set_normal_cursor" method since we're not dealing with an actual OpenLP application object + self.app.set_normal_cursor = lambda: None + self.app.process_events = lambda: None + Registry.create() + Registry().register('application', self.app) + self.tempfile = os.path.join(tempfile.gettempdir(), 'testfile') + + def tearDown(self): + if os.path.isfile(self.tempfile): + os.remove(self.tempfile) + + @patch("openlp.core.ui.exceptionform.get_application_version") + @patch("openlp.core.ui.exceptionform.Ui_ExceptionDialog") + @patch("openlp.core.ui.exceptionform.QtWidgets.QFileDialog") + @patch("openlp.core.ui.exceptionform.QtCore.QUrl") + @patch("openlp.core.ui.exceptionform.QtCore.QUrlQuery.addQueryItem") + @patch("openlp.core.ui.exceptionform.QtGui.QDesktopServices.openUrl") + @patch("openlp.core.ui.exceptionform.is_linux") + @patch("openlp.core.ui.exceptionform.platform.python_version") + @patch("openlp.core.ui.exceptionform.platform.platform") + @patch("openlp.core.ui.exceptionform.Qt.qVersion") + @patch("openlp.core.ui.exceptionform.Qt") + @patch("openlp.core.ui.exceptionform.sqlalchemy") + @patch("openlp.core.ui.exceptionform.bs4") + @patch("openlp.core.ui.exceptionform.etree") + def test_on_send_report_button_clicked(self, + mocked_etree, + mocked_bs4, + mocked_sqlalchemy, + mocked_pyqt, + mocked_qversion, + mocked_platform, + mocked_python_version, + mocked_is_linux, + mocked_openlurl, + mocked_qurlquery, + mocked_qurl, + mocked_file_dialog, + mocked_ui_exception_dialog, + mocked_application_version): + """ + Test on_send_report_button_clicked creates the proper system information text + """ + # GIVEN: Test environment + mocked_etree.__version__ = 'ETree Test' + mocked_bs4.__version__ = 'BeautifulSoup Test' + mocked_sqlalchemy.__version__ = 'SqlAlchemy Test' + mocked_pyqt.PYQT_VERSION_STR = 'PyQT5 Test' + mocked_python_version.return_value = 'Python Test' + mocked_platform.return_value = 'Nose Test' + mocked_qversion.return_value = 'Qt5 test' + mocked_is_linux.return_value = False + mocked_application_version.return_value = 'Trunk Test' + test_form = exceptionform.ExceptionForm() + test_form.file_attachment = None + with patch.object(test_form, '_pyuno_import') as mock_pyuno: + with patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback: + with patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: + mock_pyuno.return_value = 'UNO Bridge Test' + mock_traceback.return_value = 'openlp: Traceback Test' + mock_description.return_value = 'Description Test' + + # WHEN: on_save_report_button_clicked called + test_form.on_send_report_button_clicked() + + # THEN: Verify strings were fomratted properly + mocked_qurlquery.assert_called_with('body', MAIL_ITEM_TEXT) From d3a2dd399afce71446217f2c4b020aa62ec1625f Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sat, 25 Jun 2016 04:39:57 -0700 Subject: [PATCH 12/17] Fix missing format key, updated test --- .coveragerc | 5 - openlp/core/ui/exceptionform.py | 2 +- .../openlp_core_ui/test_exceptionform.py | 129 ++++++++++++++---- 3 files changed, 105 insertions(+), 31 deletions(-) delete mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index f8f529f44..000000000 --- a/.coveragerc +++ /dev/null @@ -1,5 +0,0 @@ -[run] -source = openlp - -[html] -directory = coverage diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 279230911..432a4ee38 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -150,7 +150,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): Settings().setValue(self.settings_section + '/last directory', os.path.dirname(filename)) opts = self._create_report() report_text = self.report_text.format(version=opts['version'], description=opts['description'], - traceback=opts['traceback'], libs=ops['libs']) + traceback=opts['traceback'], libs=opts['libs'], system=opts['system']) try: report_file = open(filename, 'w') try: diff --git a/tests/functional/openlp_core_ui/test_exceptionform.py b/tests/functional/openlp_core_ui/test_exceptionform.py index 85ad4c975..00b3374c0 100644 --- a/tests/functional/openlp_core_ui/test_exceptionform.py +++ b/tests/functional/openlp_core_ui/test_exceptionform.py @@ -51,16 +51,49 @@ exceptionform.VLC_VERSION = 'VLC Test' MAIL_ITEM_TEXT = ('**OpenLP Bug Report**\nVersion: Trunk Test\n\n--- Details of the Exception. ---\n\n' 'Description Test\n\n --- Exception Traceback ---\nopenlp: Traceback Test\n' '--- System information ---\nPlatform: Nose Test\n\n--- Library Versions ---\n' - 'Python: Python Test\nQt5: Qt5 test\nPyQt5: PyQT5 Test\nQtWebkit: Webkit Test\n' + 'Python: Python Test\nQt5: Qt5 test\nPyQt5: PyQt5 Test\nQtWebkit: Webkit Test\n' 'SQLAlchemy: SqlAlchemy Test\nSQLAlchemy Migrate: Migrate Test\nBeautifulSoup: BeautifulSoup Test\n' 'lxml: ETree Test\nChardet: CHARDET Test\nPyEnchant: Enchant Test\nMako: Mako Test\n' 'pyICU: ICU Test\npyUNO bridge: UNO Bridge Test\nVLC: VLC Test\n\n') +@patch("openlp.core.ui.exceptionform.Qt.qVersion") +@patch("openlp.core.ui.exceptionform.QtGui.QDesktopServices.openUrl") +@patch("openlp.core.ui.exceptionform.get_application_version") +@patch("openlp.core.ui.exceptionform.sqlalchemy") +@patch("openlp.core.ui.exceptionform.bs4") +@patch("openlp.core.ui.exceptionform.etree") +@patch("openlp.core.ui.exceptionform.is_linux") +@patch("openlp.core.ui.exceptionform.platform.platform") +@patch("openlp.core.ui.exceptionform.platform.python_version") class TestExceptionForm(TestMixin, TestCase): """ Test functionality of exception form functions """ + def __method_template_for_class_patches(self, + __PLACEHOLDER_FOR_LOCAL_METHOD_PATCH_DECORATORS_GO_HERE__, + mocked_python_version, + mocked_platform, + mocked_is_linux, + mocked_etree, + mocked_bs4, + mocked_sqlalchemy, + mocked_application_version, + mocked_openlurl, + mocked_qversion, + ): + """ + Template so you don't have to remember the layout of class mock options for methods + """ + mocked_etree.__version__ = 'ETree Test' + mocked_bs4.__version__ = 'BeautifulSoup Test' + mocked_sqlalchemy.__version__ = 'SqlAlchemy Test' + mocked_python_version.return_value = 'Python Test' + mocked_platform.return_value = 'Nose Test' + mocked_qversion.return_value = 'Qt5 test' + mocked_is_linux.return_value = False + mocked_application_version.return_value = 'Trunk Test' + def setUp(self): self.setup_application() self.app.setApplicationVersion('0.0') @@ -75,50 +108,46 @@ class TestExceptionForm(TestMixin, TestCase): if os.path.isfile(self.tempfile): os.remove(self.tempfile) - @patch("openlp.core.ui.exceptionform.get_application_version") @patch("openlp.core.ui.exceptionform.Ui_ExceptionDialog") @patch("openlp.core.ui.exceptionform.QtWidgets.QFileDialog") @patch("openlp.core.ui.exceptionform.QtCore.QUrl") @patch("openlp.core.ui.exceptionform.QtCore.QUrlQuery.addQueryItem") - @patch("openlp.core.ui.exceptionform.QtGui.QDesktopServices.openUrl") - @patch("openlp.core.ui.exceptionform.is_linux") - @patch("openlp.core.ui.exceptionform.platform.python_version") - @patch("openlp.core.ui.exceptionform.platform.platform") - @patch("openlp.core.ui.exceptionform.Qt.qVersion") @patch("openlp.core.ui.exceptionform.Qt") - @patch("openlp.core.ui.exceptionform.sqlalchemy") - @patch("openlp.core.ui.exceptionform.bs4") - @patch("openlp.core.ui.exceptionform.etree") def test_on_send_report_button_clicked(self, - mocked_etree, - mocked_bs4, - mocked_sqlalchemy, - mocked_pyqt, - mocked_qversion, - mocked_platform, - mocked_python_version, - mocked_is_linux, - mocked_openlurl, - mocked_qurlquery, + mocked_qt, + mocked_add_query_item, mocked_qurl, mocked_file_dialog, mocked_ui_exception_dialog, - mocked_application_version): + mocked_python_version, + mocked_platform, + mocked_is_linux, + mocked_etree, + mocked_bs4, + mocked_sqlalchemy, + mocked_application_version, + mocked_openlurl, + mocked_qversion, + ): """ - Test on_send_report_button_clicked creates the proper system information text + Test send report creates the proper system information text """ # GIVEN: Test environment mocked_etree.__version__ = 'ETree Test' mocked_bs4.__version__ = 'BeautifulSoup Test' mocked_sqlalchemy.__version__ = 'SqlAlchemy Test' - mocked_pyqt.PYQT_VERSION_STR = 'PyQT5 Test' mocked_python_version.return_value = 'Python Test' mocked_platform.return_value = 'Nose Test' mocked_qversion.return_value = 'Qt5 test' mocked_is_linux.return_value = False mocked_application_version.return_value = 'Trunk Test' + mocked_qt.PYQT_VERSION_STR = 'PyQt5 Test' + mocked_is_linux.return_value = False + mocked_application_version.return_value = 'Trunk Test' + test_form = exceptionform.ExceptionForm() test_form.file_attachment = None + with patch.object(test_form, '_pyuno_import') as mock_pyuno: with patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback: with patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: @@ -129,5 +158,55 @@ class TestExceptionForm(TestMixin, TestCase): # WHEN: on_save_report_button_clicked called test_form.on_send_report_button_clicked() - # THEN: Verify strings were fomratted properly - mocked_qurlquery.assert_called_with('body', MAIL_ITEM_TEXT) + # THEN: Verify strings were formatted properly + mocked_add_query_item.assert_called_with('body', MAIL_ITEM_TEXT) + + @patch("openlp.core.ui.exceptionform.QtWidgets.QFileDialog.getSaveFileName") + @patch("openlp.core.ui.exceptionform.Qt") + def test_on_save_report_button_clicked(self, + mocked_qt, + mocked_save_filename, + mocked_python_version, + mocked_platform, + mocked_is_linux, + mocked_etree, + mocked_bs4, + mocked_sqlalchemy, + mocked_application_version, + mocked_openlurl, + mocked_qversion, + ): + """ + Test save report saves the correct information to a file + """ + mocked_etree.__version__ = 'ETree Test' + mocked_bs4.__version__ = 'BeautifulSoup Test' + mocked_sqlalchemy.__version__ = 'SqlAlchemy Test' + mocked_python_version.return_value = 'Python Test' + mocked_platform.return_value = 'Nose Test' + mocked_qversion.return_value = 'Qt5 test' + mocked_qt.PYQT_VERSION_STR = 'PyQt5 Test' + mocked_is_linux.return_value = False + mocked_application_version.return_value = 'Trunk Test' + mocked_save_filename.return_value = ['testfile.txt',] + + test_form = exceptionform.ExceptionForm() + test_form.file_attachment = None + + with patch.object(test_form, '_pyuno_import') as mock_pyuno: + with patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback: + with patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: + with patch("openlp.core.ui.exceptionform.open", mock_open(), create=True) as mocked_open: + mock_pyuno.return_value = 'UNO Bridge Test' + mock_traceback.return_value = 'openlp: Traceback Test' + mock_description.return_value = 'Description Test' + + # WHEN: on_save_report_button_clicked called + test_form.on_save_report_button_clicked() + + # THEN: Verify proper calls to save file + # self.maxDiff = None + check_text = "call().write({text})".format(text=MAIL_ITEM_TEXT.__repr__()) + write_text = "{text}".format(text=mocked_open.mock_calls[1]) + mocked_open.assert_called_with('testfile.txt', 'w') + self.assertEquals(check_text, write_text, "Saved information should match test text") From f7532b7896c859fb777fbb43a625b5c3989142bb Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sat, 25 Jun 2016 07:41:06 -0700 Subject: [PATCH 13/17] pep8 --- tests/functional/openlp_core_ui/test_exceptionform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_ui/test_exceptionform.py b/tests/functional/openlp_core_ui/test_exceptionform.py index 00b3374c0..452a8dee9 100644 --- a/tests/functional/openlp_core_ui/test_exceptionform.py +++ b/tests/functional/openlp_core_ui/test_exceptionform.py @@ -188,7 +188,7 @@ class TestExceptionForm(TestMixin, TestCase): mocked_qt.PYQT_VERSION_STR = 'PyQt5 Test' mocked_is_linux.return_value = False mocked_application_version.return_value = 'Trunk Test' - mocked_save_filename.return_value = ['testfile.txt',] + mocked_save_filename.return_value = ['testfile.txt', ] test_form = exceptionform.ExceptionForm() test_form.file_attachment = None From b41b4a591802928caab1183215f67f842ecfff3a Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 5 Aug 2016 12:18:47 -0700 Subject: [PATCH 14/17] Fix some todo notes --- openlp/core/common/uistrings.py | 1 - openlp/core/lib/filedialog.py | 1 - openlp/core/lib/renderer.py | 1 - openlp/core/lib/theme.py | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/openlp/core/common/uistrings.py b/openlp/core/common/uistrings.py index 91d947ade..ff7536f22 100644 --- a/openlp/core/common/uistrings.py +++ b/openlp/core/common/uistrings.py @@ -80,7 +80,6 @@ class UiStrings(object): self.Export = translate('OpenLP.Ui', 'Export') self.File = translate('OpenLP.Ui', 'File') self.FileNotFound = translate('OpenLP.Ui', 'File Not Found') - # TODO: Passed nose - verify in real life example self.FileNotFoundMessage = translate('OpenLP.Ui', 'File {name} not found.\nPlease try selecting it individually.') self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit') diff --git a/openlp/core/lib/filedialog.py b/openlp/core/lib/filedialog.py index e976f9c15..457bd663c 100644 --- a/openlp/core/lib/filedialog.py +++ b/openlp/core/lib/filedialog.py @@ -51,7 +51,6 @@ class FileDialog(QtWidgets.QFileDialog): file = parse.unquote(file) if not os.path.exists(file): log.error('File {text} not found.'.format(text=file)) - # TODO: Should work - need to verify QtWidgets.QMessageBox.information(parent, UiStrings().FileNotFound, UiStrings().FileNotFoundMessage.format(name=file)) continue diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 2646a7f40..40d974e53 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -371,7 +371,6 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): self.web.resize(self.page_width, self.page_height) self.web_frame = self.web.page().mainFrame() # Adjust width and height to account for shadow. outline done in css. - # TODO: Tested at home html = Template("""