Merge head

This commit is contained in:
Felipe Polo-Wood 2013-12-28 12:06:29 -05:00
commit 1ef910463c
25 changed files with 1014 additions and 230 deletions

View File

@ -83,6 +83,8 @@ class UiStrings(object):
self.Error = translate('OpenLP.Ui', 'Error')
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FileNotFound = translate('OpenLP.Ui', 'File Not Found')
self.FileNotFoundMessage = translate('OpenLP.Ui', 'File %s 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')

View File

@ -336,6 +336,7 @@ def create_separated_list(string_list):
from .registry import Registry
from .filedialog import FileDialog
from .screen import ScreenList
from .listwidgetwithdnd import ListWidgetWithDnD
from .treewidgetwithdnd import TreeWidgetWithDnD
@ -351,4 +352,3 @@ from .dockwidget import OpenLPDockWidget
from .imagemanager import ImageManager
from .renderer import Renderer
from .mediamanageritem import MediaManagerItem

View File

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Provide a work around for a bug in QFileDialog <https://bugs.launchpad.net/openlp/+bug/1209515>
"""
import logging
import os
from urllib import parse
from PyQt4 import QtGui
from openlp.core.common import UiStrings
log = logging.getLogger(__name__)
class FileDialog(QtGui.QFileDialog):
"""
Subclass QFileDialog to work round a bug
"""
@staticmethod
def getOpenFileNames(parent, *args, **kwargs):
"""
Reimplement getOpenFileNames to fix the way it returns some file names that url encoded when selecting multiple
files
"""
files = QtGui.QFileDialog.getOpenFileNames(parent, *args, **kwargs)
file_list = []
for file in files:
if not os.path.exists(file):
log.info('File %s not found. Attempting to unquote.')
file = parse.unquote(file)
if not os.path.exists(file):
log.error('File %s not found.' % file)
QtGui.QMessageBox.information(parent, UiStrings().FileNotFound,
UiStrings().FileNotFoundMessage % file)
continue
log.info('File %s found.')
file_list.append(file)
return file_list

View File

@ -36,7 +36,7 @@ import re
from PyQt4 import QtCore, QtGui
from openlp.core.common import Settings, UiStrings, translate
from openlp.core.lib import OpenLPToolbar, ServiceItem, StringContent, ListWidgetWithDnD, \
from openlp.core.lib import FileDialog, OpenLPToolbar, ServiceItem, StringContent, ListWidgetWithDnD, \
ServiceItemContext, Registry
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
@ -319,7 +319,7 @@ class MediaManagerItem(QtGui.QWidget):
"""
Add a file to the list widget to make it available for showing
"""
files = QtGui.QFileDialog.getOpenFileNames(self, self.on_new_prompt,
files = FileDialog.getOpenFileNames(self, self.on_new_prompt,
Settings().value(self.settings_section + '/last directory'), self.on_new_file_masks)
log.info('New files(s) %s', files)
if files:

View File

@ -37,7 +37,7 @@ import urllib.request
import urllib.parse
import urllib.error
from tempfile import gettempdir
from configparser import SafeConfigParser
from configparser import ConfigParser
from PyQt4 import QtCore, QtGui
@ -68,7 +68,7 @@ class ThemeScreenshotThread(QtCore.QThread):
filename = config.get('theme_%s' % theme, 'filename')
screenshot = config.get('theme_%s' % theme, 'screenshot')
urllib.request.urlretrieve('%s%s' % (self.parent().web, screenshot),
os.path.join(gettempdir(), 'openlp', screenshot))
os.path.join(gettempdir(), 'openlp', screenshot))
item = QtGui.QListWidgetItem(title, self.parent().themes_list_widget)
item.setData(QtCore.Qt.UserRole, filename)
item.setCheckState(QtCore.Qt.Unchecked)
@ -90,14 +90,16 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.screens = screens
# check to see if we have web access
self.web = 'http://openlp.org/files/frw/'
self.config = SafeConfigParser()
self.web_access = get_web_page('%s%s' % (self.web, 'download.cfg'))
self.config = ConfigParser()
user_agent = 'OpenLP/' + Registry().get('application').applicationVersion()
self.web_access = get_web_page('%s%s' % (self.web, 'download.cfg'), header=('User-Agent', user_agent))
if self.web_access:
files = self.web_access.read()
self.config.read_string(files.decode())
self.update_screen_list_combo()
self.was_download_cancelled = False
self.theme_screenshot_thread = None
self.has_run_wizard = False
self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...')
self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
self.no_internet_finish_button.clicked.connect(self.on_no_internet_finish_button_clicked)

View File

@ -74,7 +74,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
if event.key() == QtCore.Qt.Key_Space:
self.keyReleaseEvent(event)
elif self.primaryPushButton.isChecked() or self.alternatePushButton.isChecked():
event.ignore()
self.keyReleaseEvent(event)
elif event.key() == QtCore.Qt.Key_Escape:
event.accept()
self.close()

View File

@ -33,13 +33,12 @@ import os
import zipfile
import shutil
import logging
import re
from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui
from openlp.core.common import AppLocation, Settings, check_directory_exists, UiStrings, translate
from openlp.core.lib import ImageSource, OpenLPToolbar, Registry, get_text_file_string, build_icon, \
from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, Registry, get_text_file_string, build_icon, \
check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.theme import ThemeXML, BackgroundType
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
@ -59,7 +58,7 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
"""
super(ThemeManager, self).__init__(parent)
Registry().register('theme_manager', self)
Registry().register_function('bootstrap_initialise', self.load_first_time_themes)
Registry().register_function('bootstrap_initialise', self.initialise)
Registry().register_function('bootstrap_post_set_up', self._push_themes)
self.settings_section = 'themes'
self.theme_form = ThemeForm(self)
@ -135,15 +134,7 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
Registry().register_function('theme_update_global', self.change_global_from_tab)
# Variables
self.theme_list = []
self.path = AppLocation.get_section_data_path(self.settings_section)
check_directory_exists(self.path)
self.thumb_path = os.path.join(self.path, 'thumbnails')
check_directory_exists(self.thumb_path)
self.theme_form.path = self.path
self.old_background_image = None
self.bad_v1_name_chars = re.compile(r'[%+\[\]]')
# Last little bits of setting up
self.global_theme = Settings().value(self.settings_section + '/global theme')
def check_list_state(self, item):
"""
@ -374,7 +365,7 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
Opens a file dialog to select the theme file(s) to import before attempting to extract OpenLP themes from
those files. This process will load both OpenLP version 1 and version 2 themes.
"""
files = QtGui.QFileDialog.getOpenFileNames(self,
files = FileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
Settings().value(self.settings_section + '/last directory import'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.theme *.otz)'))
@ -392,6 +383,7 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
"""
Imports any themes on start up and makes sure there is at least one theme
"""
log.debug('load_first_time_themes called')
self.application.set_busy_cursor()
files = AppLocation.get_files(self.settings_section, '.otz')
for theme_file in files:
@ -410,8 +402,8 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
def load_themes(self):
"""
Loads the theme lists and triggers updates across the whole system
using direct calls or core functions and events for the plugins.
Loads the theme lists and triggers updates across the whole system using direct calls or core functions and
events for the plugins.
The plugins will call back in to get the real list if they want it.
"""
log.debug('Load themes from dir')
@ -636,18 +628,18 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
self.main_window.finished_progress_bar()
self.load_themes()
def generate_image(self, theme_data, forcePage=False):
def generate_image(self, theme_data, force_page=False):
"""
Call the renderer to build a Sample Image
``theme_data``
The theme to generated a preview for.
``forcePage``
``force_page``
Flag to tell message lines per page need to be generated.
"""
log.debug('generate_image \n%s ', theme_data)
return self.renderer.generate_preview(theme_data, forcePage)
return self.renderer.generate_preview(theme_data, force_page)
def get_preview_image(self, theme):
"""
@ -672,7 +664,7 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
theme.extend_image_filename(path)
return theme
def _validate_theme_action(self, select_text, confirm_title, confirm_text, testPlugin=True, confirm=True):
def _validate_theme_action(self, select_text, confirm_title, confirm_text, test_plugin=True, confirm=True):
"""
Check to see if theme has been selected and the destructive action
is allowed.
@ -694,7 +686,7 @@ class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
message=translate('OpenLP.ThemeManager', 'You are unable to delete the default theme.'))
return False
# check for use in the system else where.
if testPlugin:
if test_plugin:
for plugin in self.plugin_manager.plugins:
if plugin.uses_theme(theme):
critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),

View File

@ -29,10 +29,34 @@
"""
The Theme Controller helps manages adding, deleteing and modifying of themes.
"""
import logging
import os
from openlp.core.common import AppLocation, Settings, check_directory_exists
log = logging.getLogger(__name__)
class ThemeManagerHelper(object):
"""
Manages the non ui theme functions.
"""
pass
def initialise(self):
"""
Setup the manager
"""
log.debug('initialise called')
self.global_theme = Settings().value(self.settings_section + '/global theme')
self.build_theme_path()
self.load_first_time_themes()
def build_theme_path(self):
"""
Set up the theme path variables
"""
log.debug('build theme path called')
self.path = AppLocation.get_section_data_path(self.settings_section)
check_directory_exists(self.path)
self.thumb_path = os.path.join(self.path, 'thumbnails')
check_directory_exists(self.thumb_path)
self.theme_form.path = self.path

View File

@ -40,6 +40,7 @@ import sys
import urllib.request
import urllib.error
import urllib.parse
from random import randint
from PyQt4 import QtGui, QtCore
@ -61,10 +62,29 @@ APPLICATION_VERSION = {}
IMAGES_FILTER = None
ICU_COLLATOR = None
UNO_CONNECTION_TYPE = 'pipe'
#UNO_CONNECTION_TYPE = u'socket'
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
USER_AGENTS = {
'win32': [
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36'
],
'darwin': [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11',
],
'linux2': [
'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22',
'Mozilla/5.0 (X11; CrOS armv7l 2913.260.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.99 Safari/537.11',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.27 (KHTML, like Gecko) Chrome/26.0.1389.0 Safari/537.27'
],
'default': [
'Mozilla/5.0 (X11; NetBSD amd64; rv:18.0) Gecko/20130120 Firefox/18.0'
]
}
class VersionThread(QtCore.QThread):
@ -298,6 +318,17 @@ def delete_file(file_path_name):
return False
def _get_user_agent():
"""
Return a user agent customised for the platform the user is on.
"""
browser_list = USER_AGENTS.get(sys.platform, None)
if not browser_list:
browser_list = USER_AGENTS['default']
random_index = randint(0, len(browser_list) - 1)
return browser_list[random_index]
def get_web_page(url, header=None, update_openlp=False):
"""
Attempts to download the webpage at url and returns that page or None.
@ -318,6 +349,9 @@ def get_web_page(url, header=None, update_openlp=False):
if not url:
return None
req = urllib.request.Request(url)
if not header or header[0].lower() != 'user-agent':
user_agent = _get_user_agent()
req.add_header('User-Agent', user_agent)
if header:
req.add_header(header[0], header[1])
page = None

View File

@ -379,7 +379,7 @@ class BSExtract(object):
send_error_message('parse')
return None
content = content.find_all('li')
return [book.contents[0].contents[0] for book in content]
return [book.contents[0].contents[0] for book in content if len(book.contents[0].contents)]
def _get_application(self):
"""

View File

@ -281,7 +281,7 @@ class Controller(object):
class MessageListener(object):
"""
This is the Presentation listener who acts on events from the slide controller and passes the messages on the the
This is the Presentation listener who acts on events from the slide controller and passes the messages on the
correct presentation handlers
"""
log.info('Message Listener loaded')

View File

@ -337,8 +337,8 @@ class PresentationDocument(object):
class PresentationController(object):
"""
This class is used to control interactions with presentation applications by creating a runtime environment. This is
a base class for presentation controllers to inherit from.
This class is used to control interactions with presentation applications by creating a runtime environment.
This is a base class for presentation controllers to inherit from.
To create a new controller, take a copy of this file and name it so it ends with ``controller.py``, i.e.
``foobarcontroller.py``. Make sure it inherits
@ -386,8 +386,7 @@ class PresentationController(object):
"""
log.info('PresentationController loaded')
def __init__(self, plugin=None, name='PresentationController',
document_class=PresentationDocument):
def __init__(self, plugin=None, name='PresentationController', document_class=PresentationDocument):
"""
This is the constructor for the presentationcontroller object. This provides an easy way for descendent plugins
to populate common data. This method *must* be overridden, like so::

View File

@ -39,7 +39,7 @@ import shutil
from PyQt4 import QtCore, QtGui
from openlp.core.common import AppLocation, UiStrings, check_directory_exists, translate
from openlp.core.lib import Registry, PluginStatus, MediaType, create_separated_list
from openlp.core.lib import FileDialog, Registry, PluginStatus, MediaType, create_separated_list
from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_message_box, find_and_set_in_combo_box
from openlp.plugins.songs.lib import VerseType, clean_song
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic, MediaFile
@ -758,7 +758,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
Loads file(s) from the filesystem.
"""
filters = '%s (*)' % UiStrings().AllFiles
filenames = QtGui.QFileDialog.getOpenFileNames(self,
filenames = FileDialog.getOpenFileNames(self,
translate('SongsPlugin.EditSongForm', 'Open File(s)'), '', filters)
for filename in filenames:
item = QtGui.QListWidgetItem(os.path.split(str(filename))[1])

View File

@ -37,7 +37,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.common import UiStrings, translate
from openlp.core.common import Settings
from openlp.core.lib import Registry
from openlp.core.lib import FileDialog, Registry
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect
@ -246,7 +246,7 @@ class SongImportForm(OpenLPWizard):
if filters:
filters += ';;'
filters += '%s (*)' % UiStrings().AllFiles
filenames = QtGui.QFileDialog.getOpenFileNames(self, title,
filenames = FileDialog.getOpenFileNames(self, title,
Settings().value(self.plugin.settings_section + '/last directory import'), filters)
if filenames:
listbox.addItems(filenames)

View File

@ -11,9 +11,9 @@ import sys
from PyQt4 import QtGui
if sys.version_info[1] >= 3:
from unittest.mock import patch, MagicMock
from unittest.mock import MagicMock, patch, mock_open
else:
from mock import patch, MagicMock
from mock import MagicMock, patch, mock_open
# Only one QApplication can be created. Use QtGui.QApplication.instance() when you need to "create" a QApplication.
application = QtGui.QApplication([])

View File

@ -1 +1,28 @@
__author__ = 'tim'
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################

View File

@ -59,7 +59,6 @@ class TestAppLocation(TestCase):
# WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_data_path()
print(data_path)
# THEN: check that all the correct methods were called, and the result is correct
mocked_settings.contains.assert_called_with('advanced/data path')

View File

@ -0,0 +1,73 @@
"""
Package to test the openlp.core.lib.filedialog package.
"""
from unittest import TestCase
from openlp.core.common import UiStrings
from openlp.core.lib.filedialog import FileDialog
from tests.functional import MagicMock, patch
class TestFileDialog(TestCase):
"""
Test the functions in the :mod:`filedialog` module.
"""
def setUp(self):
self.os_patcher = patch('openlp.core.lib.filedialog.os')
self.qt_gui_patcher = patch('openlp.core.lib.filedialog.QtGui')
self.ui_strings_patcher = patch('openlp.core.lib.filedialog.UiStrings')
self.mocked_os = self.os_patcher.start()
self.mocked_qt_gui = self.qt_gui_patcher.start()
self.mocked_ui_strings = self.ui_strings_patcher.start()
self.mocked_parent = MagicMock()
def tearDown(self):
self.os_patcher.stop()
self.qt_gui_patcher.stop()
self.ui_strings_patcher.stop()
def get_open_file_names_canceled_test(self):
"""
Test that FileDialog.getOpenFileNames() returns and empty QStringList when QFileDialog is canceled
(returns an empty QStringList)
"""
self.mocked_os.reset()
# GIVEN: An empty QStringList as a return value from QFileDialog.getOpenFileNames
self.mocked_qt_gui.QFileDialog.getOpenFileNames.return_value = []
# WHEN: FileDialog.getOpenFileNames is called
result = FileDialog.getOpenFileNames(self.mocked_parent)
# THEN: The returned value should be an empty QStringList and os.path.exists should not have been called
assert not self.mocked_os.path.exists.called
self.assertEqual(result, [],
'FileDialog.getOpenFileNames should return and empty list when QFileDialog.getOpenFileNames is canceled')
def returned_file_list_test(self):
"""
Test that FileDialog.getOpenFileNames handles a list of files properly when QFileList.getOpenFileNames
returns a good file name, a urlencoded file name and a non-existing file
"""
self.mocked_os.rest()
self.mocked_qt_gui.reset()
# GIVEN: A List of known values as a return value from QFileDialog.getOpenFileNames and a list of valid
# file names.
self.mocked_qt_gui.QFileDialog.getOpenFileNames.return_value = [
'/Valid File', '/url%20encoded%20file%20%231', '/non-existing']
self.mocked_os.path.exists.side_effect = lambda file_name: file_name in [
'/Valid File', '/url encoded file #1']
# WHEN: FileDialog.getOpenFileNames is called
result = FileDialog.getOpenFileNames(self.mocked_parent)
# THEN: os.path.exists should have been called with known args. QmessageBox.information should have been
# called. The returned result should corrilate with the input.
self.mocked_os.path.exists.assert_callde_with('/Valid File')
self.mocked_os.path.exists.assert_callde_with('/url%20encoded%20file%20%231')
self.mocked_os.path.exists.assert_callde_with('/url encoded file #1')
self.mocked_os.path.exists.assert_callde_with('/non-existing')
self.mocked_os.path.exists.assert_callde_with('/non-existing')
self.mocked_qt_gui.QmessageBox.information.called_with(self.mocked_parent, UiStrings().FileNotFound,
UiStrings().FileNotFoundMessage % '/non-existing')
self.assertEqual(result, ['/Valid File', '/url encoded file #1'], 'The returned file list is incorrect')

View File

@ -3,13 +3,13 @@ Package to test the openlp.core.lib.htmlbuilder module.
"""
from unittest import TestCase
from mock import MagicMock, patch
from PyQt4 import QtCore
from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \
build_lyrics_format_css, build_footer_css
from openlp.core.lib.theme import HorizontalType, VerticalType
from tests.functional import MagicMock, patch
HTML = """

View File

@ -62,9 +62,11 @@ class TestTheme(TestCase):
# THEN: We should get some default behaviours
self.assertTrue(default_theme.background_border_color == '#000000', 'The theme should have a black border')
self.assertTrue(default_theme.background_type == 'solid', 'There theme should have a solid backgrounds')
self.assertTrue(default_theme.background_type == 'solid', 'The theme should have a solid backgrounds')
self.assertTrue(default_theme.display_vertical_align == 0,
'There theme should have display_vertical_align of 0')
'The theme should have a display_vertical_align of 0')
self.assertTrue(default_theme.font_footer_name == "Arial",
'There theme should has font_footer_name of Arial')
self.assertTrue(default_theme.font_main_bold is False, 'There theme should has font_main_bold of false')
'The theme should have a font_footer_name of Arial')
self.assertTrue(default_theme.font_main_bold is False, 'The theme should have a font_main_bold of false')
self.assertTrue(len(default_theme.__dict__) == 47, 'The theme should have 47 variables')

View File

@ -32,14 +32,74 @@ Functional tests to test the AppLocation class and related methods.
from unittest import TestCase
from openlp.core.utils import clean_filename, get_filesystem_encoding, get_locale_key, \
get_natural_key, split_filename
from tests.functional import patch
get_natural_key, split_filename, _get_user_agent, get_web_page, get_uno_instance, add_actions
from tests.functional import MagicMock, patch
class TestUtils(TestCase):
"""
A test suite to test out various methods around the AppLocation class.
"""
def add_actions_empty_list_test(self):
"""
Test that no actions are added when the list is empty
"""
# GIVEN: a mocked action list, and an empty list
mocked_target = MagicMock()
empty_list = []
# WHEN: The empty list is added to the mocked target
add_actions(mocked_target, empty_list)
# THEN: The add method on the mocked target is never called
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
def add_actions_none_action_test(self):
"""
Test that a separator is added when a None action is in the list
"""
# GIVEN: a mocked action list, and a list with None in it
mocked_target = MagicMock()
separator_list = [None]
# WHEN: The list is added to the mocked target
add_actions(mocked_target, separator_list)
# THEN: The addSeparator method is called, but the addAction method is never called
mocked_target.addSeparator.assert_called_with()
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
def add_actions_add_action_test(self):
"""
Test that an action is added when a valid action is in the list
"""
# GIVEN: a mocked action list, and a list with an action in it
mocked_target = MagicMock()
action_list = ['action']
# WHEN: The list is added to the mocked target
add_actions(mocked_target, action_list)
# THEN: The addSeparator method is not called, and the addAction method is called
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
mocked_target.addAction.assert_called_with('action')
def add_actions_action_and_none_test(self):
"""
Test that an action and a separator are added when a valid action and None are in the list
"""
# GIVEN: a mocked action list, and a list with an action and None in it
mocked_target = MagicMock()
action_list = ['action', None]
# WHEN: The list is added to the mocked target
add_actions(mocked_target, action_list)
# THEN: The addSeparator method is called, and the addAction method is called
mocked_target.addSeparator.assert_called_with()
mocked_target.addAction.assert_called_with('action')
def get_filesystem_encoding_sys_function_not_called_test(self):
"""
Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function
@ -153,3 +213,211 @@ class TestUtils(TestCase):
# THEN: We get a properly sorted list
self.assertEqual(['1st item', 'item 3b', 'item 10a'], sorted_list, 'Numbers should be sorted naturally')
def get_uno_instance_pipe_test(self):
"""
Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI
"""
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "pipe"
mock_resolver = MagicMock()
# WHEN: get_uno_instance() is called
get_uno_instance(mock_resolver)
# THEN: the resolve method is called with the correct argument
mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
def get_user_agent_linux_test(self):
"""
Test that getting a user agent on Linux returns a user agent suitable for Linux
"""
with patch('openlp.core.utils.sys') as mocked_sys:
# GIVEN: The system is Linux
mocked_sys.platform = 'linux2'
# WHEN: We call _get_user_agent()
user_agent = _get_user_agent()
# THEN: The user agent is a Linux (or ChromeOS) user agent
result = 'Linux' in user_agent or 'CrOS' in user_agent
self.assertTrue(result, u'The user agent should be a valid Linux user agent')
def get_user_agent_windows_test(self):
"""
Test that getting a user agent on Windows returns a user agent suitable for Windows
"""
with patch('openlp.core.utils.sys') as mocked_sys:
# GIVEN: The system is Linux
mocked_sys.platform = 'win32'
# WHEN: We call _get_user_agent()
user_agent = _get_user_agent()
# THEN: The user agent is a Linux (or ChromeOS) user agent
self.assertIn('Windows', user_agent, u'The user agent should be a valid Windows user agent')
def get_user_agent_macos_test(self):
"""
Test that getting a user agent on OS X returns a user agent suitable for OS X
"""
with patch('openlp.core.utils.sys') as mocked_sys:
# GIVEN: The system is Linux
mocked_sys.platform = 'darwin'
# WHEN: We call _get_user_agent()
user_agent = _get_user_agent()
# THEN: The user agent is a Linux (or ChromeOS) user agent
self.assertIn('Mac OS X', user_agent, u'The user agent should be a valid OS X user agent')
def get_user_agent_default_test(self):
"""
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
"""
with patch('openlp.core.utils.sys') as mocked_sys:
# GIVEN: The system is Linux
mocked_sys.platform = 'freebsd'
# WHEN: We call _get_user_agent()
user_agent = _get_user_agent()
# THEN: The user agent is a Linux (or ChromeOS) user agent
self.assertIn('NetBSD', user_agent, u'The user agent should be the default user agent')
def get_web_page_no_url_test(self):
"""
Test that sending a URL of None to the get_web_page method returns None
"""
# GIVEN: A None url
test_url = None
# WHEN: We try to get the test URL
result = get_web_page(test_url)
# THEN: None should be returned
self.assertIsNone(result, 'The return value of get_web_page should be None')
def get_web_page_test(self):
"""
Test that the get_web_page method works correctly
"""
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent, \
patch('openlp.core.utils.Registry') as MockRegistry:
# GIVEN: Mocked out objects and a fake URL
mocked_request_object = MagicMock()
MockRequest.return_value = mocked_request_object
mocked_page_object = MagicMock()
mock_urlopen.return_value = mocked_page_object
mock_get_user_agent.return_value = 'user_agent'
fake_url = 'this://is.a.fake/url'
# WHEN: The get_web_page() method is called
returned_page = get_web_page(fake_url)
# THEN: The correct methods are called with the correct arguments and a web page is returned
MockRequest.assert_called_with(fake_url)
mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent')
self.assertEqual(1, mocked_request_object.add_header.call_count,
'There should only be 1 call to add_header')
mock_get_user_agent.assert_called_with()
mock_urlopen.assert_called_with(mocked_request_object)
mocked_page_object.geturl.assert_called_with()
self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called')
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
def get_web_page_with_header_test(self):
"""
Test that adding a header to the call to get_web_page() adds the header to the request
"""
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent:
# GIVEN: Mocked out objects, a fake URL and a fake header
mocked_request_object = MagicMock()
MockRequest.return_value = mocked_request_object
mocked_page_object = MagicMock()
mock_urlopen.return_value = mocked_page_object
mock_get_user_agent.return_value = 'user_agent'
fake_url = 'this://is.a.fake/url'
fake_header = ('Fake-Header', 'fake value')
# WHEN: The get_web_page() method is called
returned_page = get_web_page(fake_url, header=fake_header)
# THEN: The correct methods are called with the correct arguments and a web page is returned
MockRequest.assert_called_with(fake_url)
mocked_request_object.add_header.assert_called_with(fake_header[0], fake_header[1])
self.assertEqual(2, mocked_request_object.add_header.call_count,
'There should only be 2 calls to add_header')
mock_get_user_agent.assert_called_with()
mock_urlopen.assert_called_with(mocked_request_object)
mocked_page_object.geturl.assert_called_with()
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
def get_web_page_with_user_agent_in_headers_test(self):
"""
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
"""
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent:
# GIVEN: Mocked out objects, a fake URL and a fake header
mocked_request_object = MagicMock()
MockRequest.return_value = mocked_request_object
mocked_page_object = MagicMock()
mock_urlopen.return_value = mocked_page_object
fake_url = 'this://is.a.fake/url'
user_agent_header = ('User-Agent', 'OpenLP/2.1.0')
# WHEN: The get_web_page() method is called
returned_page = get_web_page(fake_url, header=user_agent_header)
# THEN: The correct methods are called with the correct arguments and a web page is returned
MockRequest.assert_called_with(fake_url)
mocked_request_object.add_header.assert_called_with(user_agent_header[0], user_agent_header[1])
self.assertEqual(1, mocked_request_object.add_header.call_count,
'There should only be 1 call to add_header')
self.assertEqual(0, mock_get_user_agent.call_count, '_get_user_agent should not have been called')
mock_urlopen.assert_called_with(mocked_request_object)
mocked_page_object.geturl.assert_called_with()
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
def get_web_page_update_openlp_test(self):
"""
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
"""
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent, \
patch('openlp.core.utils.Registry') as MockRegistry:
# GIVEN: Mocked out objects, a fake URL
mocked_request_object = MagicMock()
MockRequest.return_value = mocked_request_object
mocked_page_object = MagicMock()
mock_urlopen.return_value = mocked_page_object
mock_get_user_agent.return_value = 'user_agent'
mocked_registry_object = MagicMock()
mocked_application_object = MagicMock()
mocked_registry_object.get.return_value = mocked_application_object
MockRegistry.return_value = mocked_registry_object
fake_url = 'this://is.a.fake/url'
# WHEN: The get_web_page() method is called
returned_page = get_web_page(fake_url, update_openlp=True)
# THEN: The correct methods are called with the correct arguments and a web page is returned
MockRequest.assert_called_with(fake_url)
mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent')
self.assertEqual(1, mocked_request_object.add_header.call_count,
'There should only be 1 call to add_header')
mock_urlopen.assert_called_with(mocked_request_object)
mocked_page_object.geturl.assert_called_with()
mocked_registry_object.get.assert_called_with('application')
mocked_application_object.process_events.assert_called_with()
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')

View File

@ -0,0 +1,180 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
This module contains tests for the http module of the Bibles plugin.
"""
from unittest import TestCase
from bs4 import BeautifulSoup
from tests.functional import patch, MagicMock
from openlp.plugins.bibles.lib.http import BSExtract
#TODO: Items left to test
# BGExtract
# __init__
# _remove_elements
# _extract_verse
# _clean_soup
# _extract_verses
# _extract_verses_old
# get_bible_chapter
# get_books_from_http
# _get_application
# CWExtract
# __init__
# get_bible_chapter
# get_books_from_http
# _get_application
# HTTPBible
# __init__
# do_import
# get_verses
# get_chapter
# get_books
# get_chapter_count
# get_verse_count
# _get_application
# get_soup_for_bible_ref
# send_error_message
class TestBSExtract(TestCase):
"""
Test the BSExtractClass
"""
#TODO: Items left to test
# BSExtract
# __init__
# get_bible_chapter
# get_books_from_http
# _get_application
def setUp(self):
self.get_soup_for_bible_ref_patcher = patch('openlp.plugins.bibles.lib.http.get_soup_for_bible_ref')
self.log_patcher = patch('openlp.plugins.bibles.lib.http.log')
self.send_error_message_patcher = patch('openlp.plugins.bibles.lib.http.send_error_message')
self.socket_patcher = patch('openlp.plugins.bibles.lib.http.socket')
self.urllib_patcher = patch('openlp.plugins.bibles.lib.http.urllib')
self.mock_get_soup_for_bible_ref = self.get_soup_for_bible_ref_patcher.start()
self.mock_log = self.log_patcher.start()
self.mock_send_error_message = self.send_error_message_patcher.start()
self.mock_socket = self.socket_patcher.start()
self.mock_soup = MagicMock()
self.mock_urllib = self.urllib_patcher.start()
def tearDown(self):
self.get_soup_for_bible_ref_patcher.stop()
self.log_patcher.stop()
self.send_error_message_patcher.stop()
self.socket_patcher.stop()
self.urllib_patcher.stop()
def get_books_from_http_no_soup_test(self):
"""
Test the get_books_from_http method when get_soup_for_bible_ref returns a falsey value
"""
# GIVEN: An instance of BSExtract, and reset log, urllib & get_soup_for_bible_ref mocks
instance = BSExtract()
self.mock_log.debug.reset_mock()
self.mock_urllib.reset_mock()
self.mock_get_soup_for_bible_ref.reset_mock()
# WHEN: get_books_from_http is called with 'NIV' and get_soup_for_bible_ref returns a None value
self.mock_urllib.parse.quote.return_value = 'NIV'
self.mock_get_soup_for_bible_ref.return_value = None
result = instance.get_books_from_http('NIV')
# THEN: The rest mocks should be called with known values and get_books_from_http should return None
self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("%s")', 'NIV')
self.mock_urllib.parse.quote.assert_called_once_with(b'NIV')
self.mock_get_soup_for_bible_ref.assert_called_once_with(
'http://m.bibleserver.com/overlay/selectBook?translation=NIV')
self.assertIsNone(result,
'BSExtract.get_books_from_http should return None when get_soup_for_bible_ref returns a false value')
def get_books_from_http_no_content_test(self):
"""
Test the get_books_from_http method when the specified element cannot be found in the tag object returned from
get_soup_for_bible_ref
"""
# GIVEN: An instance of BSExtract, and reset log, urllib, get_soup_for_bible_ref & soup mocks
instance = BSExtract()
self.mock_log.reset_mock()
self.mock_urllib.reset_mock()
self.mock_get_soup_for_bible_ref.reset_mock()
self.mock_soup.reset_mock()
# WHEN: get_books_from_http is called with 'NIV', get_soup_for_bible_ref returns a mocked_soup object and
# mocked_soup.find returns None
self.mock_urllib.parse.quote.return_value = 'NIV'
self.mock_soup.find.return_value = None
self.mock_get_soup_for_bible_ref.return_value = self.mock_soup
result = instance.get_books_from_http('NIV')
# THEN: The rest mocks should be called with known values and get_books_from_http should return None
self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("%s")', 'NIV')
self.mock_urllib.parse.quote.assert_called_once_with(b'NIV')
self.mock_get_soup_for_bible_ref.assert_called_once_with(
'http://m.bibleserver.com/overlay/selectBook?translation=NIV')
self.mock_soup.find.assert_called_once_with('ul')
self.mock_log.error.assert_called_once_with('No books found in the Bibleserver response.')
self.mock_send_error_message.assert_called_once_with('parse')
self.assertIsNone(result,
'BSExtract.get_books_from_http should return None when get_soup_for_bible_ref returns a false value')
def get_books_from_http_content_test(self):
"""
Test the get_books_from_http method with sample HTML
Also a regression test for bug #1184869. (The anchor tag in the second list item is empty)
"""
# GIVEN: An instance of BSExtract, and reset log, urllib & get_soup_for_bible_ref mocks and sample HTML data
self.test_html = '<ul><li><a href="/overlay/selectChapter?tocBook=1">Genesis</a></li>' \
'<li><a href="/overlay/selectChapter?tocBook=2"></a></li>' \
'<li><a href="/overlay/selectChapter?tocBook=3">Leviticus</a></li></ul>'
self.test_soup = BeautifulSoup(self.test_html)
instance = BSExtract()
self.mock_log.reset_mock()
self.mock_urllib.reset_mock()
self.mock_get_soup_for_bible_ref.reset_mock()
self.mock_send_error_message.reset_mock()
# WHEN: get_books_from_http is called with 'NIV' and get_soup_for_bible_ref returns tag object based on the
# supplied test data.
self.mock_urllib.parse.quote.return_value = 'NIV'
self.mock_get_soup_for_bible_ref.return_value = self.test_soup
result = instance.get_books_from_http('NIV')
# THEN: The rest mocks should be called with known values and get_books_from_http should return the two books
# in the test data
self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("%s")', 'NIV')
self.mock_urllib.parse.quote.assert_called_once_with(b'NIV')
self.mock_get_soup_for_bible_ref.assert_called_once_with(
'http://m.bibleserver.com/overlay/selectBook?translation=NIV')
self.assertFalse(self.mock_log.error.called, 'log.error should not have been called')
self.assertFalse(self.mock_send_error_message.called, 'send_error_message should not have been called')
self.assertEquals(result, ['Genesis', 'Leviticus'])

View File

@ -1,165 +1,181 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Functional tests to test the PresentationController and PresentationDocument
classes and related methods.
"""
from unittest import TestCase
import os
from mock import MagicMock, patch, mock_open
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
class TestLibModule(TestCase):
def setUp(self):
mocked_plugin = MagicMock()
mocked_plugin.settings_section = 'presentations'
self.presentation = PresentationController(mocked_plugin)
self.document = PresentationDocument(self.presentation, '')
def save_titles_and_notes_test(self):
"""
Test PresentationDocument.save_titles_and_notes method with two valid lists
"""
# GIVEN: two lists of length==2 and a mocked open and get_thumbnail_folder
mocked_open = mock_open()
with patch('builtins.open', mocked_open), \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder:
titles = ['uno', 'dos']
notes = ['one', 'two']
# WHEN: calling save_titles_and_notes
mocked_get_thumbnail_folder.return_value = 'test'
self.document.save_titles_and_notes(titles, notes)
# THEN: the last call to open should have been for slideNotes2.txt
mocked_open.assert_any_call(
os.path.join('test', 'titles.txt'), mode='w')
mocked_open.assert_any_call(
os.path.join('test', 'slideNotes1.txt'), mode='w')
mocked_open.assert_any_call(
os.path.join('test', 'slideNotes2.txt'), mode='w')
self.assertEqual(mocked_open.call_count, 3,
'There should be exactly three files opened')
mocked_open().writelines.assert_called_once_with(['uno', 'dos'])
mocked_open().write.assert_called_any('one')
mocked_open().write.assert_called_any('two')
def save_titles_and_notes_with_None_test(self):
"""
Test PresentationDocument.save_titles_and_notes method with no data
"""
# GIVEN: None and an empty list and a mocked open and get_thumbnail_folder
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder:
titles = None
notes = None
# WHEN: calling save_titles_and_notes
mocked_get_thumbnail_folder.return_value = 'test'
self.document.save_titles_and_notes(titles, notes)
# THEN: No file should have been created
self.assertEqual(mocked_open.call_count, 0,
'No file should be created')
def get_titles_and_notes_test(self):
"""
Test PresentationDocument.get_titles_and_notes method
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('builtins.open', mock_open(read_data='uno\ndos\n')) as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = 'test'
mocked_exists.return_value = True
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two items for the titles and two empty strings for the notes
self.assertIs(type(result_titles), list,
'result_titles should be of type list')
self.assertEqual(len(result_titles), 2,
'There should be two items in the titles')
self.assertIs(type(result_notes), list,
'result_notes should be of type list')
self.assertEqual(len(result_notes), 2,
'There should be two items in the notes')
self.assertEqual(mocked_open.call_count, 3,
'Three files should be opened')
mocked_open.assert_any_call(os.path.join('test', 'titles.txt'))
mocked_open.assert_any_call(os.path.join('test', 'slideNotes1.txt'))
mocked_open.assert_any_call(os.path.join('test', 'slideNotes2.txt'))
self.assertEqual(mocked_exists.call_count, 3,
'Three files should have been checked')
def get_titles_and_notes_with_file_not_found_test(self):
"""
Test PresentationDocument.get_titles_and_notes method with file not found
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = 'test'
mocked_exists.return_value = False
#WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two empty lists
self.assertIs(type(result_titles), list,
'result_titles should be of type list')
self.assertEqual(len(result_titles), 0,
'there be no titles')
self.assertIs(type(result_notes), list,
'result_notes should be a list')
self.assertEqual(len(result_notes), 0,
'but the list should be empty')
self.assertEqual(mocked_open.call_count, 0,
'No calls to open files')
self.assertEqual(mocked_exists.call_count, 1,
'There should be one call to file exists')
def get_titles_and_notes_with_file_error_test(self):
"""
Test PresentationDocument.get_titles_and_notes method with file errors
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = 'test'
mocked_exists.return_value = True
mocked_open.side_effect = IOError()
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two empty lists
self.assertIs(type(result_titles), list,
'result_titles should be a list')
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Functional tests to test the PresentationController and PresentationDocument
classes and related methods.
"""
from unittest import TestCase
import os
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
from tests.functional import MagicMock, patch, mock_open
class TestPresentationController(TestCase):
def setUp(self):
mocked_plugin = MagicMock()
mocked_plugin.settings_section = 'presentations'
self.presentation = PresentationController(mocked_plugin)
self.document = PresentationDocument(self.presentation, '')
"""
Test the PresentationController.
"""
def constructor_test(self):
"""
Test the Constructor
"""
# GIVEN: A mocked plugin
# WHEN: The PresentationController is created
# THEN: The name of the presentation controller should be correct
self.assertEqual('PresentationController', self.presentation.name,
'The name of the presentation controller should be correct')
def save_titles_and_notes_test(self):
"""
Test PresentationDocument.save_titles_and_notes method with two valid lists
"""
# GIVEN: two lists of length==2 and a mocked open and get_thumbnail_folder
mocked_open = mock_open()
with patch('builtins.open', mocked_open), \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder:
titles = ['uno', 'dos']
notes = ['one', 'two']
# WHEN: calling save_titles_and_notes
mocked_get_thumbnail_folder.return_value = 'test'
self.document.save_titles_and_notes(titles, notes)
# THEN: the last call to open should have been for slideNotes2.txt
mocked_open.assert_any_call(
os.path.join('test', 'titles.txt'), mode='w')
mocked_open.assert_any_call(
os.path.join('test', 'slideNotes1.txt'), mode='w')
mocked_open.assert_any_call(
os.path.join('test', 'slideNotes2.txt'), mode='w')
self.assertEqual(mocked_open.call_count, 3,
'There should be exactly three files opened')
mocked_open().writelines.assert_called_once_with(['uno', 'dos'])
mocked_open().write.assert_called_any('one')
mocked_open().write.assert_called_any('two')
def save_titles_and_notes_with_None_test(self):
"""
Test PresentationDocument.save_titles_and_notes method with no data
"""
# GIVEN: None and an empty list and a mocked open and get_thumbnail_folder
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder:
titles = None
notes = None
# WHEN: calling save_titles_and_notes
mocked_get_thumbnail_folder.return_value = 'test'
self.document.save_titles_and_notes(titles, notes)
# THEN: No file should have been created
self.assertEqual(mocked_open.call_count, 0,
'No file should be created')
def get_titles_and_notes_test(self):
"""
Test PresentationDocument.get_titles_and_notes method
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('builtins.open', mock_open(read_data='uno\ndos\n')) as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = 'test'
mocked_exists.return_value = True
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two items for the titles and two empty strings for the notes
self.assertIs(type(result_titles), list,
'result_titles should be of type list')
self.assertEqual(len(result_titles), 2,
'There should be two items in the titles')
self.assertIs(type(result_notes), list,
'result_notes should be of type list')
self.assertEqual(len(result_notes), 2,
'There should be two items in the notes')
self.assertEqual(mocked_open.call_count, 3,
'Three files should be opened')
mocked_open.assert_any_call(os.path.join('test', 'titles.txt'))
mocked_open.assert_any_call(os.path.join('test', 'slideNotes1.txt'))
mocked_open.assert_any_call(os.path.join('test', 'slideNotes2.txt'))
self.assertEqual(mocked_exists.call_count, 3,
'Three files should have been checked')
def get_titles_and_notes_with_file_not_found_test(self):
"""
Test PresentationDocument.get_titles_and_notes method with file not found
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = 'test'
mocked_exists.return_value = False
#WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two empty lists
self.assertIs(type(result_titles), list,
'result_titles should be of type list')
self.assertEqual(len(result_titles), 0,
'there be no titles')
self.assertIs(type(result_notes), list,
'result_notes should be a list')
self.assertEqual(len(result_notes), 0,
'but the list should be empty')
self.assertEqual(mocked_open.call_count, 0,
'No calls to open files')
self.assertEqual(mocked_exists.call_count, 1,
'There should be one call to file exists')
def get_titles_and_notes_with_file_error_test(self):
"""
Test PresentationDocument.get_titles_and_notes method with file errors
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') \
as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = 'test'
mocked_exists.return_value = True
mocked_open.side_effect = IOError()
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two empty lists
self.assertIs(type(result_titles), list,
'result_titles should be a list')

View File

@ -39,9 +39,8 @@ from PyQt4 import QtGui
from openlp.core.lib import Registry
from openlp.core.common import Settings
from openlp.plugins.remotes.lib.httpserver import HttpRouter
from tests.functional import MagicMock, patch
from mock import mock_open
from urllib.parse import urlparse
from tests.functional import MagicMock, patch, mock_open
__default_settings__ = {
'remotes/twelve hour': True,
@ -56,6 +55,7 @@ __default_settings__ = {
TEST_PATH = os.path.abspath(os.path.dirname(__file__))
class TestRouter(TestCase):
"""
Test the functions in the :mod:`lib` module.
@ -94,7 +94,7 @@ class TestRouter(TestCase):
# THEN: the function should return the correct password
self.assertEqual(router.auth, test_value,
'The result for make_sha_hash should return the correct encrypted password')
'The result for make_sha_hash should return the correct encrypted password')
def process_http_request_test(self):
"""
@ -112,10 +112,8 @@ class TestRouter(TestCase):
function, args = router.process_http_request('/stage/api/poll', None)
# THEN: the function should have been called only once
assert function['function'] == mocked_function, \
'The mocked function should match defined value.'
assert function['secure'] == False, \
'The mocked function should not require any security.'
self.assertEqual(mocked_function, function['function'], 'The mocked function should match defined value.')
self.assertFalse(function['secure'], 'The mocked function should not require any security.')
def get_content_type_test(self):
"""
@ -127,10 +125,12 @@ class TestRouter(TestCase):
['test.gif', 'image/gif'], ['test.ico', 'image/x-icon'],
['test.png', 'image/png'], ['test.whatever', 'text/plain'],
['test', 'text/plain'], ['', 'text/plain'],
[os.path.join(TEST_PATH,'test.html'), 'text/html']]
[os.path.join(TEST_PATH, 'test.html'), 'text/html']]
# WHEN: calling each file type
for header in headers:
ext, content_type = self.router.get_content_type(header[0])
# THEN: all types should match
self.assertEqual(content_type, header[1], 'Mismatch of content type')
@ -145,13 +145,14 @@ class TestRouter(TestCase):
self.router.wfile = MagicMock()
self.router.html_dir = os.path.normpath('test/dir')
self.router.template_vars = MagicMock()
# WHEN: call serve_file with no file_name
self.router.serve_file()
# THEN: it should return a 404
self.router.send_response.assert_called_once_with(404)
self.router.send_header.assert_called_once_with('Content-type','text/html')
self.assertEqual(self.router.end_headers.call_count, 1,
'end_headers called once')
self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once')
def serve_file_with_valid_params_test(self):
"""
@ -165,16 +166,16 @@ class TestRouter(TestCase):
self.router.html_dir = os.path.normpath('test/dir')
self.router.template_vars = MagicMock()
with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
patch('builtins.open', mock_open(read_data='123')):
patch('builtins.open', mock_open(read_data='123')):
mocked_exists.return_value = True
# WHEN: call serve_file with an existing html file
self.router.serve_file(os.path.normpath('test/dir/test.html'))
# THEN: it should return a 200 and the file
self.router.send_response.assert_called_once_with(200)
self.router.send_header.assert_called_once_with(
'Content-type','text/html')
self.assertEqual(self.router.end_headers.call_count, 1,
'end_headers called once')
self.router.send_header.assert_called_once_with('Content-type', 'text/html')
self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once')
def serve_thumbnail_without_params_test(self):
"""

View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Interface tests to test the thememanagerhelper class and related methods.
"""
import os
from unittest import TestCase
from tempfile import mkstemp
from openlp.core.common import Settings
from openlp.core.ui import ThemeManagerHelper
from tests.functional import patch, MagicMock
class TestThemeManagerHelper(TestCase):
"""
Test the functions in the ThemeManagerHelp[er module
"""
def setUp(self):
"""
Create the UI
"""
fd, self.ini_file = mkstemp('.ini')
Settings().set_filename(self.ini_file)
self.helper = ThemeManagerHelper()
self.helper.settings_section = "themes"
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
os.unlink(self.ini_file)
os.unlink(Settings().fileName())
def test_initialise(self):
"""
Test the thememanagerhelper initialise - basic test
"""
# GIVEN: A new a call to initialise
Settings().setValue('themes/global theme', 'my_theme')
self.helper.build_theme_path = MagicMock()
self.helper.load_first_time_themes = MagicMock()
# WHEN: the initialistion is run
self.helper.initialise()
# THEN:
self.assertEqual(1, self.helper.build_theme_path.call_count,
'The function build_theme_path should have been called')
self.assertEqual(1, self.helper.load_first_time_themes.call_count,
'The function load_first_time_themes should have been called only once')
self.assertEqual(self.helper.global_theme, 'my_theme',
'The global theme should have been set to my_theme')
def test_build_theme_path(self):
"""
Test the thememanagerhelper build_theme_path - basic test
"""
# GIVEN: A new a call to initialise
with patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
mocked_check_directory_exists.return_value = True
Settings().setValue('themes/global theme', 'my_theme')
self.helper.theme_form = MagicMock()
#self.helper.load_first_time_themes = MagicMock()
# WHEN: the build_theme_path is run
self.helper.build_theme_path()
# THEN:
self.assertEqual(self.helper.path, self.helper.theme_form.path,
'The theme path and the main path should be the same value')