This commit is contained in:
Tomas Groth 2014-04-05 15:27:53 +02:00
commit bc2d45fc30
68 changed files with 666 additions and 283 deletions

View File

@ -51,8 +51,10 @@ def trace_error_handler(logger):
:param logger: logger to use so traceback is logged to correct class :param logger: logger to use so traceback is logged to correct class
""" """
log_string = "OpenLP Error trace"
for tb in traceback.extract_stack(): for tb in traceback.extract_stack():
logger.error('Called by ' + tb[3] + ' at line ' + str(tb[1]) + ' in ' + tb[0]) log_string = '%s\n File %s at line %d \n\t called %s' % (log_string, tb[0], tb[1], tb[3])
logger.error(log_string)
def check_directory_exists(directory, do_not_log=False): def check_directory_exists(directory, do_not_log=False):

View File

@ -62,11 +62,9 @@ class Registry(object):
registry = cls() registry = cls()
registry.service_list = {} registry.service_list = {}
registry.functions_list = {} registry.functions_list = {}
registry.running_under_test = False
registry.initialising = True
# Allow the tests to remove Registry entries but not the live system # Allow the tests to remove Registry entries but not the live system
if 'nose' in sys.argv[0]: registry.running_under_test = 'nose' in sys.argv[0]
registry.running_under_test = True registry.initialising = True
return registry return registry
def get(self, key): def get(self, key):
@ -128,7 +126,7 @@ class Registry(object):
:param event: The function description.. :param event: The function description..
:param function: The function to be called when the event happens. :param function: The function to be called when the event happens.
""" """
if self.running_under_test is False: if not self.running_under_test:
trace_error_handler(log) trace_error_handler(log)
log.error('Invalid Method call for key %s' % event) log.error('Invalid Method call for key %s' % event)
raise KeyError('Invalid Method call for key %s' % event) raise KeyError('Invalid Method call for key %s' % event)

View File

@ -178,15 +178,7 @@ class SearchEdit(QtGui.QLineEdit):
correct action on the button, and set the current search type (using the list of identifiers provided by the correct action on the button, and set the current search type (using the list of identifiers provided by the
developer), the ``searchTypeChanged(int)`` signal is emitted with the identifier. developer), the ``searchTypeChanged(int)`` signal is emitted with the identifier.
""" """
sender = self.sender()
for action in self.menu_button.menu().actions(): for action in self.menu_button.menu().actions():
# Why is this needed?
action.setChecked(False) action.setChecked(False)
self.menu_button.setDefaultAction(sender) self.set_current_search_type(self.sender().data())
self._current_search_type = sender.data()
# setplaceholder_text has been implemented in Qt 4.7 and in at least
# PyQt 4.9 (I am not sure, if it was implemented in PyQt 4.8).
try:
self.setPlaceholderText(self.menu_button.defaultAction().placeholder_text)
except AttributeError:
pass
self.emit(QtCore.SIGNAL('searchTypeChanged(int)'), self._current_search_type)

View File

@ -652,7 +652,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
translate('OpenLP.MainWindow', 'Are you sure you want to re-run the First ' translate('OpenLP.MainWindow', 'Are you sure you want to re-run the First '
'Time Wizard?\n\nRe-running this wizard may make changes to your ' 'Time Wizard?\n\nRe-running this wizard may make changes to your '
'current OpenLP configuration and possibly add songs to your ' 'current OpenLP configuration and possibly add songs to your '
'#existing songs list and change your default theme.'), 'existing songs list and change your default theme.'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No), QtGui.QMessageBox.No),
QtGui.QMessageBox.No) QtGui.QMessageBox.No)

View File

@ -561,7 +561,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
Return a book by name or abbreviation. Return a book by name or abbreviation.
:param name: The name or abbreviation of the book. :param name: The name or abbreviation of the book.
:param lower: True if the comparsion should be only lowercase :param lower: True if the comparison should be only lowercase
""" """
log.debug('BiblesResourcesDB.get_book("%s")', name) log.debug('BiblesResourcesDB.get_book("%s")', name)
if not isinstance(name, str): if not isinstance(name, str):

View File

@ -87,7 +87,7 @@ class PptviewController(PresentationController):
return return
log.debug('start PPTView') log.debug('start PPTView')
dll_path = os.path.join(AppLocation.get_directory(AppLocation.AppDir), dll_path = os.path.join(AppLocation.get_directory(AppLocation.AppDir),
'presentations', 'lib', 'pptviewlib', 'pptviewlib.dll') 'plugins', 'presentations', 'lib', 'pptviewlib', 'pptviewlib.dll')
self.process = cdll.LoadLibrary(dll_path) self.process = cdll.LoadLibrary(dll_path)
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
self.process.SetDebug(1) self.process.SetDebug(1)

View File

@ -28,15 +28,15 @@
############################################################################### ###############################################################################
""" """
The :mod:`http` module contains the API web server. This is a lightweight web The :mod:`http` module contains the API web server. This is a lightweight web server used by remotes to interact
server used by remotes to interact with OpenLP. It uses JSON to communicate with with OpenLP. It uses JSON to communicate with the remotes.
the remotes.
""" """
import ssl import ssl
import socket import socket
import os import os
import logging import logging
import time
from PyQt4 import QtCore from PyQt4 import QtCore
@ -53,8 +53,8 @@ log = logging.getLogger(__name__)
class CustomHandler(BaseHTTPRequestHandler, HttpRouter): class CustomHandler(BaseHTTPRequestHandler, HttpRouter):
""" """
Stateless session handler to handle the HTTP request and process it. Stateless session handler to handle the HTTP request and process it.
This class handles just the overrides to the base methods and the logic to invoke the This class handles just the overrides to the base methods and the logic to invoke the methods within the HttpRouter
methods within the HttpRouter class. class.
DO not try change the structure as this is as per the documentation. DO not try change the structure as this is as per the documentation.
""" """
@ -116,9 +116,20 @@ class OpenLPServer():
log.debug('Started ssl httpd...') log.debug('Started ssl httpd...')
else: else:
port = Settings().value(self.settings_section + '/port') port = Settings().value(self.settings_section + '/port')
self.httpd = ThreadingHTTPServer((address, port), CustomHandler) loop = 1
while loop < 3:
try:
self.httpd = ThreadingHTTPServer((address, port), CustomHandler)
except OSError:
loop += 1
time.sleep(0.1)
except:
log.error('Failed to start server ')
log.debug('Started non ssl httpd...') log.debug('Started non ssl httpd...')
self.httpd.serve_forever() if hasattr(self, 'httpd') and self.httpd:
self.httpd.serve_forever()
else:
log.debug('Failed to start server')
def stop_server(self): def stop_server(self):
""" """

View File

@ -32,4 +32,3 @@ The :mod:`resources` module contains a bunch of resources for OpenLP.
DO NOT REMOVE THIS FILE, IT IS REQUIRED FOR INCLUDING THE RESOURCES ON SOME DO NOT REMOVE THIS FILE, IT IS REQUIRED FOR INCLUDING THE RESOURCES ON SOME
PLATFORMS! PLATFORMS!
""" """

View File

@ -94,6 +94,7 @@ OPTIONAL_MODULES = [
('psycopg2', '(PostgreSQL support)', True), ('psycopg2', '(PostgreSQL support)', True),
('nose', '(testing framework)', True), ('nose', '(testing framework)', True),
('mock', '(testing module)', sys.version_info[1] < 3), ('mock', '(testing module)', sys.version_info[1] < 3),
('jenkins', '(access jenkins api - package name: jenkins-webapi)', True),
] ]
w = sys.stdout.write w = sys.stdout.write

192
scripts/jenkins_script.py Normal file
View File

@ -0,0 +1,192 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 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 script helps to trigger builds of branches. To use it you have to install the jenkins-webapi package:
pip3 install jenkins-webapi
You probably want to create an alias. Add this to your ~/.bashrc file and then logout and login (to apply the alias):
alias ci="python3 ./scripts/jenkins_script.py TOKEN"
You can look up the token in the Branch-01-Pull job configuration or ask in IRC.
"""
from optparse import OptionParser
from requests.exceptions import HTTPError
from subprocess import Popen, PIPE
import sys
import time
from jenkins import Jenkins
JENKINS_URL = 'http://ci.openlp.org/'
class OpenLPJobs(object):
"""
This class holds any jobs we have on jenkins and we actually need in this script.
"""
Branch_Pull = 'Branch-01-Pull'
Branch_Functional = 'Branch-02-Functional-Tests'
Branch_Interface = 'Branch-03-Interface-Tests'
Branch_Windows = 'Branch-04-Windows_Tests'
Branch_PEP = 'Branch-05-Code-Analysis'
Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP]
class JenkinsTrigger(object):
def __init__(self, token):
"""
Create the JenkinsTrigger instance.
:param token: The token we need to trigger the build. If you do not have this token, ask in IRC.
"""
self.token = token
self.repo_name = get_repo_name()
self.jenkins_instance = Jenkins(JENKINS_URL)
def trigger_build(self):
"""
Ask our jenkins server to build the "Branch-01-Pull" job.
"""
self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name}, token=self.token)
def print_output(self):
"""
Print the status information of the build tirggered.
"""
print("Add this to your merge proposal:")
print("--------------------------------")
for job in OpenLPJobs.Jobs:
self.__print_build_info(job)
def open_browser(self):
"""
Opens the browser.
"""
url = self.jenkins_instance.job(OpenLPJobs.Branch_Pull).info['url']
# Open the url
Popen(('xdg-open', url), stderr=PIPE)
def __print_build_info(self, job_name):
"""
This helper method prints the job information of the given ``job_name``
:param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class
variables from the :class:`OpenLPJobs` class.
"""
job = self.jenkins_instance.job(job_name)
while job.info['inQueue']:
# Give other processes the possibility to take over. Like Thread.yield().
time.sleep(0)
build = job.last_build
build.wait()
result_string = build.info['result']
url = build.info['url']
print('[%s] %s' % (result_string, url))
# On failure open the browser.
#if result_string == "FAILURE":
# url += 'console'
# Popen(('xdg-open', url), stderr=PIPE)
def get_repo_name():
"""
This returns the name of branch of the wokring directory. For example it returns *lp:~googol/openlp/render*.
"""
# Run the bzr command.
bzr = Popen(('bzr', 'info'), stdout=PIPE, stderr=PIPE)
raw_output, error = bzr.communicate()
# Detect any errors
if error:
print('This is not a branch.')
return
# Clean the output.
raw_output = raw_output.decode()
output_list = list(map(str.strip, raw_output.split('\n')))
# Determine the branch's name
repo_name = ''
for line in output_list:
# Check if it is remote branch.
if 'push branch' in line:
repo_name = line.replace('push branch: bzr+ssh://bazaar.launchpad.net/', 'lp:')
break
elif 'checkout of branch' in line:
repo_name = line.replace('checkout of branch: bzr+ssh://bazaar.launchpad.net/', 'lp:')
break
repo_name = repo_name.strip('/')
# Did we find the branch name?
if not repo_name:
for line in output_list:
# Check if the branch was pushed.
if 'Shared repository with trees (format: 2a)' in line:
print('Not a branch. cd to a branch.')
return
print('Not a branch. Have you pushed it to launchpad?')
return
return repo_name
def main():
usage = 'Usage: python %prog TOKEN [options]'
parser = OptionParser(usage=usage)
parser.add_option('-d', '--disable-output', dest='enable_output', action="store_false", default=True,
help='Disable output.')
parser.add_option('-b', '--open-browser', dest='open_browser', action="store_true", default=False,
help='Opens the jenkins page in your browser.')
#parser.add_option('-e', '--open-browser-on-error', dest='open_browser_on_error', action="store_true",
# default=False, help='Opens the jenkins page in your browser in case a test fails.')
options, args = parser.parse_args(sys.argv)
if len(args) == 2:
if not get_repo_name():
return
token = args[-1]
jenkins_trigger = JenkinsTrigger(token)
try:
jenkins_trigger.trigger_build()
except HTTPError as e:
print("Wrong token.")
return
# Open the browser before printing the output.
if options.open_browser:
jenkins_trigger.open_browser()
if options.enable_output:
jenkins_trigger.print_output()
else:
parser.print_help()
if __name__ == '__main__':
main()

View File

@ -52,7 +52,9 @@ This is done easily via the ``-d``, ``-p`` and ``-u`` options::
""" """
import os import os
import urllib.request, urllib.error, urllib.parse import urllib.request
import urllib.error
import urllib.parse
from getpass import getpass from getpass import getpass
import base64 import base64
import json import json
@ -70,6 +72,7 @@ quiet_mode = False
username = '' username = ''
password = '' password = ''
class Command(object): class Command(object):
""" """
Provide an enumeration of commands. Provide an enumeration of commands.
@ -80,6 +83,7 @@ class Command(object):
Update = 4 Update = 4
Generate = 5 Generate = 5
class CommandStack(object): class CommandStack(object):
""" """
This class provides an iterable stack. This class provides an iterable stack.
@ -134,13 +138,13 @@ class CommandStack(object):
results.append(str((item['command'], ))) results.append(str((item['command'], )))
return '[%s]' % ', '.join(results) return '[%s]' % ', '.join(results)
def print_quiet(text, linefeed=True): def print_quiet(text, linefeed=True):
""" """
This method checks to see if we are in quiet mode, and if not prints This method checks to see if we are in quiet mode, and if not prints ``text`` out.
``text`` out.
``text`` :param text: The text to print.
The text to print. :param linefeed: Linefeed required
""" """
global quiet_mode global quiet_mode
if not quiet_mode: if not quiet_mode:
@ -149,33 +153,33 @@ def print_quiet(text, linefeed=True):
else: else:
print(text, end=' ') print(text, end=' ')
def print_verbose(text): def print_verbose(text):
""" """
This method checks to see if we are in verbose mode, and if so prints This method checks to see if we are in verbose mode, and if so prints ``text`` out.
``text`` out.
``text`` :param text: The text to print.
The text to print.
""" """
global verbose_mode, quiet_mode global verbose_mode, quiet_mode
if not quiet_mode and verbose_mode: if not quiet_mode and verbose_mode:
print(' %s' % text) print(' %s' % text)
def run(command): def run(command):
""" """
This method runs an external application. This method runs an external application.
``command`` :param command: The command to run.
The command to run.
""" """
print_verbose(command) print_verbose(command)
process = QtCore.QProcess() process = QtCore.QProcess()
process.start(command) process.start(command)
while (process.waitForReadyRead()): while process.waitForReadyRead():
print_verbose('ReadyRead: %s' % QtCore.QString(process.readAll())) print_verbose('ReadyRead: %s' % QtCore.QString(process.readAll()))
print_verbose('Error(s):\n%s' % process.readAllStandardError()) print_verbose('Error(s):\n%s' % process.readAllStandardError())
print_verbose('Output:\n%s' % process.readAllStandardOutput()) print_verbose('Output:\n%s' % process.readAllStandardOutput())
def download_translations(): def download_translations():
""" """
This method downloads the translation files from the Pootle server. This method downloads the translation files from the Pootle server.
@ -190,9 +194,8 @@ def download_translations():
password = getpass(' Transifex password: ') password = getpass(' Transifex password: ')
# First get the list of languages # First get the list of languages
url = SERVER_URL + 'resource/ents/' url = SERVER_URL + 'resource/ents/'
base64string = base64.encodestring( base64string = base64.encodbytes('%s:%s' % (username, password))[:-1]
'%s:%s' % (username, password))[:-1] auth_header = 'Basic %s' % base64string
auth_header = 'Basic %s' % base64string
request = urllib.request.Request(url + '?details') request = urllib.request.Request(url + '?details')
request.add_header('Authorization', auth_header) request.add_header('Authorization', auth_header)
print_verbose('Downloading list of languages from: %s' % url) print_verbose('Downloading list of languages from: %s' % url)
@ -207,8 +210,7 @@ def download_translations():
lang_url = url + 'translation/%s/?file' % language lang_url = url + 'translation/%s/?file' % language
request = urllib.request.Request(lang_url) request = urllib.request.Request(lang_url)
request.add_header('Authorization', auth_header) request.add_header('Authorization', auth_header)
filename = os.path.join(os.path.abspath('..'), 'resources', 'i18n', filename = os.path.join(os.path.abspath('..'), 'resources', 'i18n', language + '.ts')
language + '.ts')
print_verbose('Get Translation File: %s' % filename) print_verbose('Get Translation File: %s' % filename)
response = urllib.request.urlopen(request) response = urllib.request.urlopen(request)
fd = open(filename, 'w') fd = open(filename, 'w')
@ -217,10 +219,10 @@ def download_translations():
print_quiet(' Done.') print_quiet(' Done.')
return True return True
def prepare_project(): def prepare_project():
""" """
This method creates the project file needed to update the translation files This method creates the project file needed to update the translation files and compile them into .qm files.
and compile them into .qm files.
""" """
print_quiet('Generating the openlp.pro file') print_quiet('Generating the openlp.pro file')
lines = [] lines = []
@ -229,9 +231,9 @@ def prepare_project():
print_verbose('Starting directory: %s' % start_dir) print_verbose('Starting directory: %s' % start_dir)
for root, dirs, files in os.walk(start_dir): for root, dirs, files in os.walk(start_dir):
for file in files: for file in files:
path = root.replace(start_dir, '').replace('\\', '/') #.replace(u'..', u'.') path = root.replace(start_dir, '').replace('\\', '/')
if file.startswith('hook-') or file.startswith('test_'): if file.startswith('hook-') or file.startswith('test_'):
continue continue
ignore = False ignore = False
for ignored_path in IGNORED_PATHS: for ignored_path in IGNORED_PATHS:
if path.startswith(ignored_path): if path.startswith(ignored_path):
@ -263,6 +265,7 @@ def prepare_project():
file.close() file.close()
print_quiet(' Done.') print_quiet(' Done.')
def update_translations(): def update_translations():
print_quiet('Update the translation files') print_quiet('Update the translation files')
if not os.path.exists(os.path.join(os.path.abspath('..'), 'openlp.pro')): if not os.path.exists(os.path.join(os.path.abspath('..'), 'openlp.pro')):
@ -273,11 +276,12 @@ def update_translations():
run('pylupdate4 -verbose -noobsolete openlp.pro') run('pylupdate4 -verbose -noobsolete openlp.pro')
os.chdir(os.path.abspath('scripts')) os.chdir(os.path.abspath('scripts'))
def generate_binaries(): def generate_binaries():
print_quiet('Generate the related *.qm files') print_quiet('Generate the related *.qm files')
if not os.path.exists(os.path.join(os.path.abspath('..'), 'openlp.pro')): if not os.path.exists(os.path.join(os.path.abspath('..'), 'openlp.pro')):
print('You have not generated a project file yet, please run this script with the -p option. It is also ' + print('You have not generated a project file yet, please run this script with the -p option. It is also ' +
'recommended that you this script with the -u option to update the translation files as well.') 'recommended that you this script with the -u option to update the translation files as well.')
return return
else: else:
os.chdir(os.path.abspath('..')) os.chdir(os.path.abspath('..'))
@ -290,12 +294,11 @@ def create_translation():
This method opens a browser to the OpenLP project page at Transifex so This method opens a browser to the OpenLP project page at Transifex so
that the user can request a new language. that the user can request a new language.
""" """
print_quiet('Please request a new language at the OpenLP project on ' print_quiet('Please request a new language at the OpenLP project on Transifex.')
'Transifex.') webbrowser.open('https://www.transifex.net/projects/p/openlp/resource/ents/')
webbrowser.open('https://www.transifex.net/projects/p/openlp/'
'resource/ents/')
print_quiet('Opening browser to OpenLP project...') print_quiet('Opening browser to OpenLP project...')
def process_stack(command_stack): def process_stack(command_stack):
""" """
This method looks at the commands in the command stack, and processes them This method looks at the commands in the command stack, and processes them
@ -323,6 +326,7 @@ def process_stack(command_stack):
else: else:
print_quiet('No commands to process.') print_quiet('No commands to process.')
def main(): def main():
global verbose_mode, quiet_mode, username, password global verbose_mode, quiet_mode, username, password
# Set up command line options. # Set up command line options.
@ -331,23 +335,23 @@ def main():
'This script is used to manage OpenLP\'s translation files.' 'This script is used to manage OpenLP\'s translation files.'
parser = OptionParser(usage=usage) parser = OptionParser(usage=usage)
parser.add_option('-U', '--username', dest='username', metavar='USERNAME', parser.add_option('-U', '--username', dest='username', metavar='USERNAME',
help='Transifex username, used for authentication') help='Transifex username, used for authentication')
parser.add_option('-P', '--password', dest='password', metavar='PASSWORD', parser.add_option('-P', '--password', dest='password', metavar='PASSWORD',
help='Transifex password, used for authentication') help='Transifex password, used for authentication')
parser.add_option('-d', '--download-ts', dest='download', parser.add_option('-d', '--download-ts', dest='download',
action='store_true', help='download language files from Transifex') action='store_true', help='download language files from Transifex')
parser.add_option('-c', '--create', dest='create', action='store_true', parser.add_option('-c', '--create', dest='create', action='store_true',
help='go to Transifex to request a new translation file') help='go to Transifex to request a new translation file')
parser.add_option('-p', '--prepare', dest='prepare', action='store_true', parser.add_option('-p', '--prepare', dest='prepare', action='store_true',
help='generate a project file, used to update the translations') help='generate a project file, used to update the translations')
parser.add_option('-u', '--update', action='store_true', dest='update', parser.add_option('-u', '--update', action='store_true', dest='update',
help='update translation files (needs a project file)') help='update translation files (needs a project file)')
parser.add_option('-g', '--generate', dest='generate', action='store_true', parser.add_option('-g', '--generate', dest='generate', action='store_true',
help='compile .ts files into .qm files') help='compile .ts files into .qm files')
parser.add_option('-v', '--verbose', dest='verbose', action='store_true', parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
help='show extra information while processing translations') help='show extra information while processing translations')
parser.add_option('-q', '--quiet', dest='quiet', action='store_true', parser.add_option('-q', '--quiet', dest='quiet', action='store_true',
help='suppress all output other than errors') help='suppress all output other than errors')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
# Create and populate the command stack # Create and populate the command stack
command_stack = CommandStack() command_stack = CommandStack()

View File

@ -106,9 +106,9 @@ try:
# If they are equal, then this tree is tarball with the source for the release. We do not want the revision number # If they are equal, then this tree is tarball with the source for the release. We do not want the revision number
# in the version string. # in the version string.
if tree_revision == tag_revision: if tree_revision == tag_revision:
version_string = tag_version version_string = tag_version
else: else:
version_string = '%s-bzr%s' % (tag_version, tree_revision) version_string = '%s-bzr%s' % (tag_version, tree_revision)
ver_file = open(VERSION_FILE, 'w') ver_file = open(VERSION_FILE, 'w')
ver_file.write(version_string) ver_file.write(version_string)
except: except:
@ -123,7 +123,9 @@ setup(
version=version_string, version=version_string,
description="Open source Church presentation and lyrics projection application.", description="Open source Church presentation and lyrics projection application.",
long_description="""\ long_description="""\
OpenLP (previously openlp.org) is free church presentation software, or lyrics projection software, used to display slides of songs, Bible verses, videos, images, and even presentations (if PowerPoint is installed) for church worship using a computer and a data projector.""", OpenLP (previously openlp.org) is free church presentation software, or lyrics projection software, used to display
slides of songs, Bible verses, videos, images, and even presentations (if PowerPoint is installed) for church worship
using a computer and a data projector.""",
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 4 - Beta',
'Environment :: MacOS X', 'Environment :: MacOS X',
@ -158,7 +160,7 @@ OpenLP (previously openlp.org) is free church presentation software, or lyrics p
'Topic :: Multimedia :: Sound/Audio', 'Topic :: Multimedia :: Sound/Audio',
'Topic :: Multimedia :: Video', 'Topic :: Multimedia :: Video',
'Topic :: Religion' 'Topic :: Religion'
], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers ], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='open source church presentation lyrics projection song bible display project', keywords='open source church presentation lyrics projection song bible display project',
author='Raoul Snyman', author='Raoul Snyman',
author_email='raoulsnyman@openlp.org', author_email='raoulsnyman@openlp.org',

View File

@ -54,9 +54,9 @@ class TestAppLocation(TestCase):
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory() # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
mocked_settings = mocked_class.return_value mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = False mocked_settings.contains.return_value = False
mocked_get_directory.return_value = os.path.join('test','dir') mocked_get_directory.return_value = os.path.join('test', 'dir')
mocked_check_directory_exists.return_value = True mocked_check_directory_exists.return_value = True
mocked_os.path.normpath.return_value = os.path.join('test','dir') mocked_os.path.normpath.return_value = os.path.join('test', 'dir')
# WHEN: we call AppLocation.get_data_path() # WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_data_path() data_path = AppLocation.get_data_path()
@ -64,8 +64,8 @@ class TestAppLocation(TestCase):
# THEN: check that all the correct methods were called, and the result is correct # THEN: check that all the correct methods were called, and the result is correct
mocked_settings.contains.assert_called_with('advanced/data path') mocked_settings.contains.assert_called_with('advanced/data path')
mocked_get_directory.assert_called_with(AppLocation.DataDir) mocked_get_directory.assert_called_with(AppLocation.DataDir)
mocked_check_directory_exists.assert_called_with(os.path.join('test','dir')) mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir'))
self.assertEqual(os.path.join('test','dir'), data_path, 'Result should be "test/dir"') self.assertEqual(os.path.join('test', 'dir'), data_path, 'Result should be "test/dir"')
def get_data_path_with_custom_location_test(self): def get_data_path_with_custom_location_test(self):
""" """
@ -110,14 +110,14 @@ class TestAppLocation(TestCase):
with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \ with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
patch('openlp.core.common.applocation.os.listdir') as mocked_listdir: patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
# GIVEN: Our mocked modules/methods. # GIVEN: Our mocked modules/methods.
mocked_get_data_path.return_value = os.path.join('test','dir') mocked_get_data_path.return_value = os.path.join('test', 'dir')
mocked_listdir.return_value = copy.deepcopy(FILE_LIST) mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
# When: Get the list of files. # When: Get the list of files.
result = AppLocation.get_files('section', '.mp3') result = AppLocation.get_files('section', '.mp3')
# Then: Check if the section parameter was used correctly. # Then: Check if the section parameter was used correctly.
mocked_listdir.assert_called_with(os.path.join('test','dir','section')) mocked_listdir.assert_called_with(os.path.join('test', 'dir', 'section'))
# Then: check if the file lists are identical. # Then: check if the file lists are identical.
self.assertListEqual(['file5.mp3', 'file6.mp3'], result, 'The file lists should be identical.') self.assertListEqual(['file5.mp3', 'file6.mp3'], result, 'The file lists should be identical.')
@ -129,15 +129,15 @@ class TestAppLocation(TestCase):
with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \ with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists: patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
# GIVEN: A mocked out AppLocation.get_data_path() # GIVEN: A mocked out AppLocation.get_data_path()
mocked_get_data_path.return_value = os.path.join('test','dir') mocked_get_data_path.return_value = os.path.join('test', 'dir')
mocked_check_directory_exists.return_value = True mocked_check_directory_exists.return_value = True
# WHEN: we call AppLocation.get_data_path() # WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_section_data_path('section') data_path = AppLocation.get_section_data_path('section')
# THEN: check that all the correct methods were called, and the result is correct # THEN: check that all the correct methods were called, and the result is correct
mocked_check_directory_exists.assert_called_with(os.path.join('test','dir','section')) mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir', 'section'))
self.assertEqual(os.path.join('test','dir','section'), data_path, 'Result should be "test/dir/section"') self.assertEqual(os.path.join('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"')
def get_directory_for_app_dir_test(self): def get_directory_for_app_dir_test(self):
""" """
@ -145,13 +145,13 @@ class TestAppLocation(TestCase):
""" """
# GIVEN: A mocked out _get_frozen_path function # GIVEN: A mocked out _get_frozen_path function
with patch('openlp.core.common.applocation.get_frozen_path') as mocked_get_frozen_path: with patch('openlp.core.common.applocation.get_frozen_path') as mocked_get_frozen_path:
mocked_get_frozen_path.return_value = os.path.join('app','dir') mocked_get_frozen_path.return_value = os.path.join('app', 'dir')
# WHEN: We call AppLocation.get_directory # WHEN: We call AppLocation.get_directory
directory = AppLocation.get_directory(AppLocation.AppDir) directory = AppLocation.get_directory(AppLocation.AppDir)
# THEN: check that the correct directory is returned # THEN: check that the correct directory is returned
self.assertEqual(os.path.join('app','dir'), directory, 'Directory should be "app/dir"') self.assertEqual(os.path.join('app', 'dir'), directory, 'Directory should be "app/dir"')
def get_directory_for_plugins_dir_test(self): def get_directory_for_plugins_dir_test(self):
""" """

View File

@ -100,9 +100,22 @@ class TestRegistry(TestCase):
# THEN: I expect then function to have been called and a return given # THEN: I expect then function to have been called and a return given
self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches') self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches')
def remove_function_test(self):
"""
Test the remove_function() method
"""
# GIVEN: An existing registry register a function
Registry.create()
Registry().register_function('test1', self.dummy_function_1)
# WHEN: Remove the function.
Registry().remove_function('test1', self.dummy_function_1)
# THEN: The method should not be available.
assert not Registry().functions_list['test1'], 'The function should not be in the dict anymore.'
def dummy_function_1(self): def dummy_function_1(self):
return "function_1" return "function_1"
def dummy_function_2(self): def dummy_function_2(self):
return "function_2" return "function_2"

View File

@ -63,4 +63,4 @@ class TestRegistryProperties(TestCase, RegistryProperties):
# WHEN the application is registered # WHEN the application is registered
Registry().register('application', application) Registry().register('application', application)
# THEN the application should be none # THEN the application should be none
self.assertEquals(self.application, application, 'The application value should match') self.assertEquals(self.application, application, 'The application value should match')

View File

@ -46,5 +46,3 @@ class TestUiStrings(TestCase):
# THEN: Check if the instances are the same. # THEN: Check if the instances are the same.
self.assertIs(first_instance, second_instance, 'Two UiStrings objects should be the same instance') self.assertIs(first_instance, second_instance, 'Two UiStrings objects should be the same instance')

View File

@ -28,4 +28,4 @@
############################################################################### ###############################################################################
""" """
Package to test the openlp.core.lib package. Package to test the openlp.core.lib package.
""" """

View File

@ -52,7 +52,7 @@ class TestDB(TestCase):
with patch('openlp.core.lib.db.create_engine') as mocked_create_engine, \ with patch('openlp.core.lib.db.create_engine') as mocked_create_engine, \
patch('openlp.core.lib.db.MetaData') as MockedMetaData, \ patch('openlp.core.lib.db.MetaData') as MockedMetaData, \
patch('openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \ patch('openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \
patch('openlp.core.lib.db.scoped_session') as mocked_scoped_session: patch('openlp.core.lib.db.scoped_session') as mocked_scoped_session:
mocked_engine = MagicMock() mocked_engine = MagicMock()
mocked_metadata = MagicMock() mocked_metadata = MagicMock()
mocked_sessionmaker_object = MagicMock() mocked_sessionmaker_object = MagicMock()

View File

@ -42,7 +42,8 @@ class TestFileDialog(TestCase):
# THEN: The returned value should be an empty QStringList and os.path.exists should not have been called # 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 assert not self.mocked_os.path.exists.called
self.assertEqual(result, [], self.assertEqual(result, [],
'FileDialog.getOpenFileNames should return and empty list when QFileDialog.getOpenFileNames is canceled') 'FileDialog.getOpenFileNames should return and empty list when QFileDialog.getOpenFileNames '
'is canceled')
def returned_file_list_test(self): def returned_file_list_test(self):
""" """
@ -70,5 +71,5 @@ class TestFileDialog(TestCase):
self.mocked_os.path.exists.assert_callde_with('/non-existing') self.mocked_os.path.exists.assert_callde_with('/non-existing')
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, self.mocked_qt_gui.QmessageBox.information.called_with(self.mocked_parent, UiStrings().FileNotFound,
UiStrings().FileNotFoundMessage % '/non-existing') UiStrings().FileNotFoundMessage % '/non-existing')
self.assertEqual(result, ['/Valid File', '/url encoded file #1'], 'The returned file list is incorrect') self.assertEqual(result, ['/Valid File', '/url encoded file #1'], 'The returned file list is incorrect')

View File

@ -108,4 +108,3 @@ class TestFormattingTags(TestCase):
# THEN: The lists should now be identical. # THEN: The lists should now be identical.
assert old_tags_list == FormattingTags.get_html_tags(), 'The lists should be identical.' assert old_tags_list == FormattingTags.get_html_tags(), 'The lists should be identical.'

View File

@ -321,4 +321,3 @@ class Htmbuilder(TestCase):
# THEN: THE css should be the same. # THEN: THE css should be the same.
assert FOOTER_CSS == css, 'The footer strings should be equal.' assert FOOTER_CSS == css, 'The footer strings should be equal.'

View File

@ -311,8 +311,8 @@ class TestLib(TestCase):
mocked_buffer.open.assert_called_with('writeonly') mocked_buffer.open.assert_called_with('writeonly')
mocked_image.save.assert_called_with(mocked_buffer, "PNG") mocked_image.save.assert_called_with(mocked_buffer, "PNG")
mocked_byte_array.toBase64.assert_called_with() mocked_byte_array.toBase64.assert_called_with()
self.assertEqual('base64mock', result, self.assertEqual('base64mock', result, 'The result should be the return value of the mocked out '
'The result should be the return value of the mocked out base64 method') 'base64 method')
def create_thumb_with_size_test(self): def create_thumb_with_size_test(self):
""" """

View File

@ -86,4 +86,4 @@ class TestRenderer(TestCase):
self.assertEqual(renderer.width, 1024, 'The base renderer should be a live controller') self.assertEqual(renderer.width, 1024, 'The base renderer should be a live controller')
self.assertEqual(renderer.height, 768, 'The base renderer should be a live controller') self.assertEqual(renderer.height, 768, 'The base renderer should be a live controller')
self.assertEqual(renderer.screen_ratio, 0.75, 'The base renderer should be a live controller') self.assertEqual(renderer.screen_ratio, 0.75, 'The base renderer should be a live controller')
self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller') self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller')

View File

@ -69,4 +69,3 @@ class TestTheme(TestCase):
'The theme should have a font_footer_name of Arial') '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(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') self.assertTrue(len(default_theme.__dict__) == 47, 'The theme should have 47 variables')

View File

@ -72,9 +72,10 @@ class TestFormattingTagController(TestCase):
# THEN: The result should match the predetermined value. # THEN: The result should match the predetermined value.
self.assertTrue(result == test['gen'], self.assertTrue(result == test['gen'],
'Function should handle end tag correctly : %s and %s for %s ' % (test['gen'], result, test['start'])) 'Function should handle end tag correctly : %s and %s for %s ' %
self.assertTrue(error == test['valid'], (test['gen'], result, test['start']))
'Function should not generate unexpected error messages : %s ' % error) self.assertTrue(error == test['valid'], 'Function should not generate unexpected error messages : %s ' %
error)
def test_start_tag_changed_processes_correctly(self): def test_start_tag_changed_processes_correctly(self):
""" """
@ -94,10 +95,10 @@ class TestFormattingTagController(TestCase):
error, result = self.services.start_tag_changed(test['start'], test['end']) error, result = self.services.start_tag_changed(test['start'], test['end'])
# THEN: The result should match the predetermined value. # THEN: The result should match the predetermined value.
self.assertTrue(result == test['gen'], self.assertTrue(result == test['gen'], 'Function should handle end tag correctly : %s and %s ' %
'Function should handle end tag correctly : %s and %s ' % (test['gen'], result)) (test['gen'], result))
self.assertTrue(error == test['valid'], self.assertTrue(error == test['valid'], 'Function should not generate unexpected error messages : %s ' %
'Function should not generate unexpected error messages : %s ' % error) error)
def test_start_html_to_end_html(self): def test_start_html_to_end_html(self):
""" """
@ -112,5 +113,5 @@ class TestFormattingTagController(TestCase):
result = self.services.start_html_to_end_html(test1) result = self.services.start_html_to_end_html(test1)
# THEN: The result should match the predetermined value. # THEN: The result should match the predetermined value.
self.assertTrue(result == test2, 'Calculated end tag should be valid: %s and %s = %s' self.assertTrue(result == test2, 'Calculated end tag should be valid: %s and %s = %s' %
% (test1, test2, result)) (test1, test2, result))

View File

@ -74,4 +74,3 @@ class TestFormattingTagForm(TestCase):
# THEN: setEnabled and setDefault should have been called on save_push_button # THEN: setEnabled and setDefault should have been called on save_push_button
#form.save_button.setEnabled.assert_called_with(True) #form.save_button.setEnabled.assert_called_with(True)

View File

@ -74,4 +74,4 @@ class TestServiceManager(TestCase):
# THEN: The the controller should be registered in the registry. # THEN: The the controller should be registered in the registry.
self.assertNotEqual(service, None, 'The base service should be created') self.assertNotEqual(service, None, 'The base service should be created')
self.assertEqual(service['openlp_core']['service-theme'], 'test_theme', 'The test theme should be saved') self.assertEqual(service['openlp_core']['service-theme'], 'test_theme', 'The test theme should be saved')
self.assertEqual(service['openlp_core']['lite-service'], False, 'The lite service should be saved') self.assertEqual(service['openlp_core']['lite-service'], False, 'The lite service should be saved')

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -149,5 +149,3 @@ class TestActionList(TestCase, TestMixin):
# THEN: Both action should keep their shortcuts. # THEN: Both action should keep their shortcuts.
assert len(action3.shortcuts()) == 2, 'The action should have two shortcut assigned.' assert len(action3.shortcuts()) == 2, 'The action should have two shortcut assigned.'
assert len(action_with_same_shortcuts3.shortcuts()) == 2, 'The action should have two shortcuts assigned.' assert len(action_with_same_shortcuts3.shortcuts()) == 2, 'The action should have two shortcuts assigned.'

View File

@ -107,7 +107,7 @@ class TestUtils(TestCase):
""" """
# GIVEN: sys.getfilesystemencoding returns "cp1252" # GIVEN: sys.getfilesystemencoding returns "cp1252"
with patch('openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \ with patch('openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
patch('openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding: patch('openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding:
mocked_getfilesystemencoding.return_value = 'cp1252' mocked_getfilesystemencoding.return_value = 'cp1252'
# WHEN: get_filesystem_encoding() is called # WHEN: get_filesystem_encoding() is called
@ -124,7 +124,7 @@ class TestUtils(TestCase):
""" """
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8" # GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
with patch('openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \ with patch('openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
patch('openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding: patch('openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding:
mocked_getfilesystemencoding.return_value = None mocked_getfilesystemencoding.return_value = None
mocked_getdefaultencoding.return_value = 'utf-8' mocked_getdefaultencoding.return_value = 'utf-8'
@ -175,7 +175,7 @@ class TestUtils(TestCase):
# THEN: A tuple should be returned. # THEN: A tuple should be returned.
self.assertEqual(wanted_result, result, self.assertEqual(wanted_result, result,
'A two-entry tuple with the directory and file name (empty) should have been returned.') 'A two-entry tuple with the directory and file name (empty) should have been returned.')
def clean_filename_test(self): def clean_filename_test(self):
""" """
@ -206,7 +206,7 @@ class TestUtils(TestCase):
# THEN: We get a properly sorted list # THEN: We get a properly sorted list
self.assertEqual(['Aushang', '\u00C4u\u00DFerung', 'Auszug'], sorted_list, self.assertEqual(['Aushang', '\u00C4u\u00DFerung', 'Auszug'], sorted_list,
'Strings should be sorted properly') 'Strings should be sorted properly')
def get_natural_key_test(self): def get_natural_key_test(self):
""" """

View File

@ -26,4 +26,3 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -116,7 +116,8 @@ class TestBSExtract(TestCase):
self.mock_get_soup_for_bible_ref.assert_called_once_with( self.mock_get_soup_for_bible_ref.assert_called_once_with(
'http://m.bibleserver.com/overlay/selectBook?translation=NIV') 'http://m.bibleserver.com/overlay/selectBook?translation=NIV')
self.assertIsNone(result, self.assertIsNone(result,
'BSExtract.get_books_from_http should return None when get_soup_for_bible_ref returns a false value') '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): def get_books_from_http_no_content_test(self):
""" """
@ -146,7 +147,8 @@ class TestBSExtract(TestCase):
self.mock_log.error.assert_called_once_with('No books found in the Bibleserver response.') 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.mock_send_error_message.assert_called_once_with('parse')
self.assertIsNone(result, self.assertIsNone(result,
'BSExtract.get_books_from_http should return None when get_soup_for_bible_ref returns a false value') '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): def get_books_from_http_content_test(self):
""" """

View File

@ -85,5 +85,3 @@ class TestLib(TestCase):
# THEN: It should be False # THEN: It should be False
self.assertFalse(has_verse_list, 'The SearchResults object should have a verse list') self.assertFalse(has_verse_list, 'The SearchResults object should have a verse list')

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -108,7 +108,7 @@ class TestImageMediaItem(TestCase):
Test that the save_new_images_list() saves all images in the list Test that the save_new_images_list() saves all images in the list
""" """
# GIVEN: A list with 3 images # GIVEN: A list with 3 images
image_list = [ 'test_image_1.jpg', 'test_image_2.jpg', 'test_image_3.jpg' ] image_list = ['test_image_1.jpg', 'test_image_2.jpg', 'test_image_3.jpg']
with patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list: with patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
self.media_item.manager = MagicMock() self.media_item.manager = MagicMock()
@ -124,7 +124,7 @@ class TestImageMediaItem(TestCase):
Test that the save_new_images_list() ignores everything in the provided list except strings Test that the save_new_images_list() ignores everything in the provided list except strings
""" """
# GIVEN: A list with images and objects # GIVEN: A list with images and objects
image_list = [ 'test_image_1.jpg', None, True, ImageFilenames(), 'test_image_2.jpg' ] image_list = ['test_image_1.jpg', None, True, ImageFilenames(), 'test_image_2.jpg']
with patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list: with patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
self.media_item.manager = MagicMock() self.media_item.manager = MagicMock()
@ -171,7 +171,7 @@ class TestImageMediaItem(TestCase):
assert self.media_item.manager.delete_object.call_count == 7, \ assert self.media_item.manager.delete_object.call_count == 7, \
'manager.delete_object() should be called exactly 7 times' 'manager.delete_object() should be called exactly 7 times'
# CLEANUP: Remove added attribute from ImageFilenames and ImageGroups # CLEANUP: Remove added attribute from Image Filenames and ImageGroups
delattr(ImageFilenames, 'group_id') delattr(ImageFilenames, 'group_id')
delattr(ImageGroups, 'parent_id') delattr(ImageGroups, 'parent_id')

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -33,6 +33,7 @@ import os
import shutil import shutil
from unittest import TestCase, SkipTest from unittest import TestCase, SkipTest
from tempfile import mkdtemp from tempfile import mkdtemp
from PyQt4 import QtCore, QtGui
from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument
from tests.functional import MagicMock from tests.functional import MagicMock
@ -45,6 +46,12 @@ __default_settings__ = {
'presentations/enable_pdf_program': False 'presentations/enable_pdf_program': False
} }
SCREEN = {
'primary': False,
'number': 1,
'size': QtCore.QRect(0, 0, 1024, 768)
}
class TestPdfController(TestCase, TestMixin): class TestPdfController(TestCase, TestMixin):
""" """
@ -56,7 +63,12 @@ class TestPdfController(TestCase, TestMixin):
""" """
self.get_application() self.get_application()
self.build_settings() self.build_settings()
ScreenList.create(self.app.desktop()) # Mocked out desktop object
self.desktop = MagicMock()
self.desktop.primaryScreen.return_value = SCREEN['primary']
self.desktop.screenCount.return_value = SCREEN['number']
self.desktop.screenGeometry.return_value = SCREEN['size']
self.screens = ScreenList.create(self.desktop)
Settings().extend_default_settings(__default_settings__) Settings().extend_default_settings(__default_settings__)
self.temp_folder = mkdtemp() self.temp_folder = mkdtemp()
self.thumbnail_folder = mkdtemp() self.thumbnail_folder = mkdtemp()
@ -67,12 +79,10 @@ class TestPdfController(TestCase, TestMixin):
""" """
Delete all the C++ objects at the end so that we don't have a segfault Delete all the C++ objects at the end so that we don't have a segfault
""" """
try: del self.screens
self.destroy_settings() self.destroy_settings()
shutil.rmtree(self.thumbnail_folder) shutil.rmtree(self.thumbnail_folder)
shutil.rmtree(self.temp_folder) shutil.rmtree(self.temp_folder)
except OSError:
pass
def constructor_test(self): def constructor_test(self):
""" """
@ -106,3 +116,30 @@ class TestPdfController(TestCase, TestMixin):
# THEN: The load should succeed and we should be able to get a pagecount # THEN: The load should succeed and we should be able to get a pagecount
self.assertTrue(loaded, 'The loading of the PDF should succeed.') self.assertTrue(loaded, 'The loading of the PDF should succeed.')
self.assertEqual(3, document.get_slide_count(), 'The pagecount of the PDF should be 3.') self.assertEqual(3, document.get_slide_count(), 'The pagecount of the PDF should be 3.')
def load_pdf_pictures_test(self):
"""
Test loading of a Pdf and check size of generate pictures
"""
# GIVEN: A Pdf-file
test_file = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'pdf_test1.pdf')
# WHEN: The Pdf is loaded
controller = PdfController(plugin=self.mock_plugin)
if not controller.check_available():
raise SkipTest('Could not detect mudraw or ghostscript, so skipping PDF test')
controller.temp_folder = self.temp_folder
controller.thumbnail_folder = self.thumbnail_folder
document = PdfDocument(controller, test_file)
loaded = document.load_presentation()
# THEN: The load should succeed and pictures should be created and have been scales to fit the screen
self.assertTrue(loaded, 'The loading of the PDF should succeed.')
image = QtGui.QImage(os.path.join(self.temp_folder, 'pdf_test1.pdf', 'mainslide001.png'))
# Based on the converter used the resolution will differ a bit
if controller.gsbin:
self.assertEqual(760, image.height(), 'The height should be 760')
self.assertEqual(537, image.width(), 'The width should be 537')
else:
self.assertEqual(767, image.height(), 'The height should be 767')
self.assertEqual(543, image.width(), 'The width should be 543')

View File

@ -80,7 +80,8 @@ class TestPptviewController(TestCase, TestMixin):
controller = PptviewController(plugin=self.mock_plugin) controller = PptviewController(plugin=self.mock_plugin)
# THEN: The name of the presentation controller should be correct # THEN: The name of the presentation controller should be correct
self.assertEqual('Powerpoint Viewer', controller.name, 'The name of the presentation controller should be correct') self.assertEqual('Powerpoint Viewer', controller.name,
'The name of the presentation controller should be correct')
def check_available_test(self): def check_available_test(self):
""" """
@ -98,9 +99,9 @@ class TestPptviewController(TestCase, TestMixin):
# THEN: On windows it should return True, on other platforms False # THEN: On windows it should return True, on other platforms False
if os.name == 'nt': if os.name == 'nt':
self.assertTrue(available, 'check_available should return True on windows.') self.assertTrue(available, 'check_available should return True on windows.')
else: else:
self.assertFalse(available, 'check_available should return False when not on windows.') self.assertFalse(available, 'check_available should return False when not on windows.')
class TestPptviewDocument(TestCase): class TestPptviewDocument(TestCase):

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -111,7 +111,8 @@ class TestRouter(TestCase, TestMixin):
Test the get_content_type logic Test the get_content_type logic
""" """
# GIVEN: a set of files and their corresponding types # GIVEN: a set of files and their corresponding types
headers = [ ['test.html', 'text/html'], ['test.css', 'text/css'], headers = [
['test.html', 'text/html'], ['test.css', 'text/css'],
['test.js', 'application/javascript'], ['test.jpg', 'image/jpeg'], ['test.js', 'application/javascript'], ['test.jpg', 'image/jpeg'],
['test.gif', 'image/gif'], ['test.ico', 'image/x-icon'], ['test.gif', 'image/gif'], ['test.ico', 'image/x-icon'],
['test.png', 'image/png'], ['test.whatever', 'text/plain'], ['test.png', 'image/png'], ['test.whatever', 'text/plain'],
@ -142,7 +143,7 @@ class TestRouter(TestCase, TestMixin):
# THEN: it should return a 404 # THEN: it should return a 404
self.router.send_response.assert_called_once_with(404) self.router.send_response.assert_called_once_with(404)
self.router.send_header.assert_called_once_with('Content-type','text/html') 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): def serve_file_with_valid_params_test(self):

View File

@ -41,33 +41,33 @@ TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'easyworshipsongs')) os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'easyworshipsongs'))
SONG_TEST_DATA = [ SONG_TEST_DATA = [
{'title': 'Amazing Grace', {'title': 'Amazing Grace',
'authors': ['John Newton'], 'authors': ['John Newton'],
'copyright': 'Public Domain', 'copyright': 'Public Domain',
'ccli_number': 0, 'ccli_number': 0,
'verses': 'verses':
[('Amazing grace how sweet the sound,\nThat saved a wretch like me;\n' [('Amazing grace how sweet the sound,\nThat saved a wretch like me;\n'
'I once was lost, but now am found\nWas blind, but now I see.', 'v1'), 'I once was lost, but now am found\nWas blind, but now I see.', 'v1'),
('T\'was grace that taught my heart to fear,\nAnd grace my fears relieved;\n' ('T\'was grace that taught my heart to fear,\nAnd grace my fears relieved;\n'
'How precious did that grace appear\nThe hour I first believed.', 'v2'), 'How precious did that grace appear\nThe hour I first believed.', 'v2'),
('Through many dangers, toil and snares,\nI have already come;\n' ('Through many dangers, toil and snares,\nI have already come;\n'
'\'Tis grace has brought me safe thus far,\nAnd grace will lead me home.', 'v3'), '\'Tis grace has brought me safe thus far,\nAnd grace will lead me home.', 'v3'),
('When we\'ve been there ten thousand years\nBright shining as the sun,\n' ('When we\'ve been there ten thousand years\nBright shining as the sun,\n'
'We\'ve no less days to sing God\'s praise\nThan when we\'ve first begun.', 'v4')], 'We\'ve no less days to sing God\'s praise\nThan when we\'ve first begun.', 'v4')],
'verse_order_list': []}, 'verse_order_list': []},
{'title': 'Beautiful Garden Of Prayer', {'title': 'Beautiful Garden Of Prayer',
'authors': ['Eleanor Allen Schroll James H. Fillmore'], 'authors': ['Eleanor Allen Schroll James H. Fillmore'],
'copyright': 'Public Domain', 'copyright': 'Public Domain',
'ccli_number': 0, 'ccli_number': 0,
'verses': 'verses':
[('O the beautiful garden, the garden of prayer,\nO the beautiful garden of prayer.\n' [('O the beautiful garden, the garden of prayer,\nO the beautiful garden of prayer.\n'
'There my Savior awaits, and He opens the gates\nTo the beautiful garden of prayer.', 'c1'), 'There my Savior awaits, and He opens the gates\nTo the beautiful garden of prayer.', 'c1'),
('There\'s a garden where Jesus is waiting,\nThere\'s a place that is wondrously fair.\n' ('There\'s a garden where Jesus is waiting,\nThere\'s a place that is wondrously fair.\n'
'For it glows with the light of His presence,\n\'Tis the beautiful garden of prayer.', 'v1'), 'For it glows with the light of His presence,\n\'Tis the beautiful garden of prayer.', 'v1'),
('There\'s a garden where Jesus is waiting,\nAnd I go with my burden and care.\n' ('There\'s a garden where Jesus is waiting,\nAnd I go with my burden and care.\n'
'Just to learn from His lips, words of comfort,\nIn the beautiful garden of prayer.', 'v2'), 'Just to learn from His lips, words of comfort,\nIn the beautiful garden of prayer.', 'v2'),
('There\'s a garden where Jesus is waiting,\nAnd He bids you to come meet Him there,\n' ('There\'s a garden where Jesus is waiting,\nAnd He bids you to come meet Him there,\n'
'Just to bow and receive a new blessing,\nIn the beautiful garden of prayer.', 'v3')], 'Just to bow and receive a new blessing,\nIn the beautiful garden of prayer.', 'v3')],
'verse_order_list': []}] 'verse_order_list': []}]
class EasyWorshipSongImportLogger(EasyWorshipSongImport): class EasyWorshipSongImportLogger(EasyWorshipSongImport):
@ -95,26 +95,32 @@ class TestFieldDesc:
self.size = size self.size = size
TEST_DATA_ENCODING = 'cp1252' TEST_DATA_ENCODING = 'cp1252'
CODE_PAGE_MAPPINGS = [(852, 'cp1250'), (737, 'cp1253'), (775, 'cp1257'), (855, 'cp1251'), (857, 'cp1254'), CODE_PAGE_MAPPINGS = [
(852, 'cp1250'), (737, 'cp1253'), (775, 'cp1257'), (855, 'cp1251'), (857, 'cp1254'),
(866, 'cp1251'), (869, 'cp1253'), (862, 'cp1255'), (874, 'cp874')] (866, 'cp1251'), (869, 'cp1253'), (862, 'cp1255'), (874, 'cp874')]
TEST_FIELD_DESCS = [TestFieldDesc('Title', FieldType.String, 50), TEST_FIELD_DESCS = [
TestFieldDesc('Title', FieldType.String, 50),
TestFieldDesc('Text Percentage Bottom', FieldType.Int16, 2), TestFieldDesc('RecID', FieldType.Int32, 4), TestFieldDesc('Text Percentage Bottom', FieldType.Int16, 2), TestFieldDesc('RecID', FieldType.Int32, 4),
TestFieldDesc('Default Background', FieldType.Logical, 1), TestFieldDesc('Words', FieldType.Memo, 250), TestFieldDesc('Default Background', FieldType.Logical, 1), TestFieldDesc('Words', FieldType.Memo, 250),
TestFieldDesc('Words', FieldType.Memo, 250), TestFieldDesc('BK Bitmap', FieldType.Blob, 10), TestFieldDesc('Words', FieldType.Memo, 250), TestFieldDesc('BK Bitmap', FieldType.Blob, 10),
TestFieldDesc('Last Modified', FieldType.Timestamp, 10)] TestFieldDesc('Last Modified', FieldType.Timestamp, 10)]
TEST_FIELDS = [b'A Heart Like Thine\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', 32868, 2147483750, TEST_FIELDS = [
b'A Heart Like Thine\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', 32868, 2147483750,
129, b'{\\rtf1\\ansi\\deff0\\deftab254{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}{\\f1\\fnil\\fcharset0 Verdana;}}' 129, b'{\\rtf1\\ansi\\deff0\\deftab254{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}{\\f1\\fnil\\fcharset0 Verdana;}}'
b'{\\colortbl\\red0\\green0\\blue0;\\red255\\green0\\blue0;\\red0\\green128\\blue0;\\red0\\green0\\blue255;' b'{\\colortbl\\red0\\green0\\blue0;\\red255\\green0\\blue0;\\red0\\green128\\blue0;\\red0\\green0\\blue255;'
b'\\red255\\green255\\blue0;\\red255\\green0\\blue255;\\red128\\g\xBF\xBD\7\0f\r\0\0\1\0', b'\\red255\\green255\\blue0;\\red255\\green0\\blue255;\\red128\\g\xBF\xBD\7\0f\r\0\0\1\0',
b'{\\rtf1\\ansi\\deff0\\deftab254{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}{\\f1\\fnil\\fcharset0 Verdana;}}' b'{\\rtf1\\ansi\\deff0\\deftab254{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}{\\f1\\fnil\\fcharset0 Verdana;}}'
b'{\\colortbl\\red0\\green0\\blue0;\\red255\\green0\\blue0;\\red0\\green128\\blue0;\\red0\\green0\\blue255;\\red255' b'{\\colortbl\\red0\\green0\\blue0;\\red255\\green0\\blue0;\\red0\\green128\\blue0;\\red0\\green0'
b'\\green255\\blue0;\\red255\\green0\\blue255;\\red128\\g\6\0\xEF\xBF\xBD\6\0\0\1\0', b'\0\0\0\0\0\0\0\0\0\0', 0] b'\\blue255;\\red255'
b'\\green255\\blue0;\\red255\\green0\\blue255;\\red128\\g\6\0\xEF\xBF\xBD\6\0\0\1\0',
b'\0\0\0\0\0\0\0\0\0\0', 0]
GET_MEMO_FIELD_TEST_RESULTS = [ GET_MEMO_FIELD_TEST_RESULTS = [
(4, b'\2', {'return': b'\2','read': (1, 3430), 'seek': (507136, (8, os.SEEK_CUR))}), (4, b'\2', {'return': b'\2', 'read': (1, 3430), 'seek': (507136, (8, os.SEEK_CUR))}),
(4, b'\3', {'return': b'', 'read': (1, ), 'seek': (507136, )}), (4, b'\3', {'return': b'', 'read': (1, ), 'seek': (507136, )}),
(5, b'\3', {'return': b'\3', 'read': (1, 1725), 'seek': (3220111360, (41, os.SEEK_CUR), 3220111408)}), (5, b'\3', {'return': b'\3', 'read': (1, 1725), 'seek': (3220111360, (41, os.SEEK_CUR), 3220111408)}),
(5, b'\4', {'return': b'', 'read': (), 'seek': ()})] (5, b'\4', {'return': b'', 'read': (), 'seek': ()})]
class TestEasyWorshipSongImport(TestCase): class TestEasyWorshipSongImport(TestCase):
""" """
Test the functions in the :mod:`ewimport` module. Test the functions in the :mod:`ewimport` module.
@ -135,7 +141,7 @@ class TestEasyWorshipSongImport(TestCase):
self.assertIsNotNone(field_desc_entry, 'Import should not be none') self.assertIsNotNone(field_desc_entry, 'Import should not be none')
self.assertEquals(field_desc_entry.name, name, 'FieldDescEntry.name should be the same as the name argument') self.assertEquals(field_desc_entry.name, name, 'FieldDescEntry.name should be the same as the name argument')
self.assertEquals(field_desc_entry.field_type, field_type, self.assertEquals(field_desc_entry.field_type, field_type,
'FieldDescEntry.type should be the same as the typeargument') 'FieldDescEntry.type should be the same as the type argument')
self.assertEquals(field_desc_entry.size, size, 'FieldDescEntry.size should be the same as the size argument') self.assertEquals(field_desc_entry.size, size, 'FieldDescEntry.size should be the same as the size argument')
def create_importer_test(self): def create_importer_test(self):
@ -164,7 +170,7 @@ class TestEasyWorshipSongImport(TestCase):
# WHEN: Called with a field name that exists # WHEN: Called with a field name that exists
existing_fields = ['Title', 'Text Percentage Bottom', 'RecID', 'Default Background', 'Words', existing_fields = ['Title', 'Text Percentage Bottom', 'RecID', 'Default Background', 'Words',
'BK Bitmap', 'Last Modified'] 'BK Bitmap', 'Last Modified']
for field_name in existing_fields: for field_name in existing_fields:
# THEN: The item corresponding the index returned should have the same name attribute # THEN: The item corresponding the index returned should have the same name attribute
@ -194,7 +200,7 @@ class TestEasyWorshipSongImport(TestCase):
# GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of # GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of
# field descriptions # field descriptions
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct: patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
@ -225,7 +231,8 @@ class TestEasyWorshipSongImport(TestCase):
# THEN: get_field should return the known results # THEN: get_field should return the known results
self.assertEquals(return_value, result, self.assertEquals(return_value, result,
'get_field should return "%s" when called with "%s"' % (result, TEST_FIELDS[field_index])) 'get_field should return "%s" when called with "%s"' %
(result, TEST_FIELDS[field_index]))
def get_memo_field_test(self): def get_memo_field_test(self):
""" """
@ -265,7 +272,7 @@ class TestEasyWorshipSongImport(TestCase):
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" # GIVEN: A mocked out SongImport class, a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.side_effect = [True, False] mocked_os_path.isfile.side_effect = [True, False]
@ -284,7 +291,7 @@ class TestEasyWorshipSongImport(TestCase):
""" """
# GIVEN: A mocked out SongImport class, os.path and a mocked out "manager" # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.return_value = True mocked_os_path.isfile.return_value = True
@ -305,7 +312,7 @@ class TestEasyWorshipSongImport(TestCase):
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \ patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \
patch('builtins.open') as mocked_open, \ patch('builtins.open') as mocked_open, \
patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct: patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.return_value = True mocked_os_path.isfile.return_value = True
@ -320,7 +327,7 @@ class TestEasyWorshipSongImport(TestCase):
for effect in struct_unpack_return_values: for effect in struct_unpack_return_values:
self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800') self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800')
self.assertEqual(mocked_open().close.call_count, 2, self.assertEqual(mocked_open().close.call_count, 2,
'The open db and memo files should have been closed') 'The open db and memo files should have been closed')
mocked_open().close.reset_mock() mocked_open().close.reset_mock()
self.assertIs(mocked_open().seek.called, False, 'db_file.seek should not have been called.') self.assertIs(mocked_open().seek.called, False, 'db_file.seek should not have been called.')
@ -332,7 +339,8 @@ class TestEasyWorshipSongImport(TestCase):
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \ patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \
patch('builtins.open'), patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct, \ patch('builtins.open'), patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct, \
patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as mocked_retrieve_windows_encoding: patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as \
mocked_retrieve_windows_encoding:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.return_value = True mocked_os_path.isfile.return_value = True
@ -357,7 +365,8 @@ class TestEasyWorshipSongImport(TestCase):
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard",
# and mocked out "author", "add_copyright", "add_verse", "finish" methods. # and mocked out "author", "add_copyright", "add_verse", "finish" methods.
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as mocked_retrieve_windows_encoding: patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as \
mocked_retrieve_windows_encoding:
mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_retrieve_windows_encoding.return_value = 'cp1252'
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
@ -395,10 +404,10 @@ class TestEasyWorshipSongImport(TestCase):
self.assertEqual(importer.copyright, song_copyright) self.assertEqual(importer.copyright, song_copyright)
if ccli_number: if ccli_number:
self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s'
% (title, ccli_number)) % (title, ccli_number))
for verse_text, verse_tag in add_verse_calls: for verse_text, verse_tag in add_verse_calls:
mocked_add_verse.assert_any_call(verse_text, verse_tag) mocked_add_verse.assert_any_call(verse_text, verse_tag)
if verse_order_list: if verse_order_list:
self.assertEquals(importer.verse_order_list, verse_order_list, 'verse_order_list for %s should be %s' self.assertEquals(importer.verse_order_list, verse_order_list,
% (title, verse_order_list)) 'verse_order_list for %s should be %s' % (title, verse_order_list))
mocked_finish.assert_called_with() mocked_finish.assert_called_with()

View File

@ -44,20 +44,20 @@ class TestLib(TestCase):
""" """
Mock up two songs and provide a set of lyrics for the songs_probably_equal tests. Mock up two songs and provide a set of lyrics for the songs_probably_equal tests.
""" """
self.full_lyrics ='''amazing grace how sweet the sound that saved a wretch like me i once was lost but now am self.full_lyrics = '''amazing grace how sweet the sound that saved a wretch like me i once was lost but now am
found was blind but now i see twas grace that taught my heart to fear and grace my fears relieved how found was blind but now i see twas grace that taught my heart to fear and grace my fears relieved how
precious did that grace appear the hour i first believed through many dangers toils and snares i have already precious did that grace appear the hour i first believed through many dangers toils and snares i have
come tis grace that brought me safe thus far and grace will lead me home''' already come tis grace that brought me safe thus far and grace will lead me home'''
self.short_lyrics ='''twas grace that taught my heart to fear and grace my fears relieved how precious did that self.short_lyrics = '''twas grace that taught my heart to fear and grace my fears relieved how precious did
grace appear the hour i first believed''' that grace appear the hour i first believed'''
self.error_lyrics ='''amazing how sweet the trumpet that saved a wrench like me i once was losst but now am self.error_lyrics = '''amazing how sweet the trumpet that saved a wrench like me i once was losst but now am
found waf blind but now i see it was grace that taught my heart to fear and grace my fears relieved how found waf blind but now i see it was grace that taught my heart to fear and grace my fears relieved how
precious did that grace appppppppear the hour i first believedxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx snares i have precious did that grace appppppppear the hour i first believedxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx snares i have
already come to this grace that brought me safe so far and grace will lead me home''' already come to this grace that brought me safe so far and grace will lead me home'''
self.different_lyrics='''on a hill far away stood an old rugged cross the emblem of suffering and shame and i love self.different_lyrics = '''on a hill far away stood an old rugged cross the emblem of suffering and shame and
that old cross where the dearest and best for a world of lost sinners was slain so ill cherish the old rugged i love that old cross where the dearest and best for a world of lost sinners was slain so ill cherish the
cross till my trophies at last i lay down i will cling to the old rugged cross and exchange it some day for a old rugged cross till my trophies at last i lay down i will cling to the old rugged cross and exchange it
crown''' some day for a crown'''
self.song1 = MagicMock() self.song1 = MagicMock()
self.song2 = MagicMock() self.song2 = MagicMock()
@ -99,7 +99,7 @@ class TestLib(TestCase):
result = songs_probably_equal(self.song1, self.song2) result = songs_probably_equal(self.song1, self.song2)
# THEN: The result should be True. # THEN: The result should be True.
assert result == True, 'The result should be True' assert result is True, 'The result should be True'
def songs_probably_equal_short_song_test(self): def songs_probably_equal_short_song_test(self):
""" """
@ -113,7 +113,7 @@ class TestLib(TestCase):
result = songs_probably_equal(self.song1, self.song2) result = songs_probably_equal(self.song1, self.song2)
# THEN: The result should be True. # THEN: The result should be True.
assert result == True, 'The result should be True' assert result is True, 'The result should be True'
def songs_probably_equal_error_song_test(self): def songs_probably_equal_error_song_test(self):
""" """
@ -127,7 +127,7 @@ class TestLib(TestCase):
result = songs_probably_equal(self.song1, self.song2) result = songs_probably_equal(self.song1, self.song2)
# THEN: The result should be True. # THEN: The result should be True.
assert result == True, 'The result should be True' assert result is True, 'The result should be True'
def songs_probably_equal_different_song_test(self): def songs_probably_equal_different_song_test(self):
""" """
@ -141,7 +141,7 @@ class TestLib(TestCase):
result = songs_probably_equal(self.song1, self.song2) result = songs_probably_equal(self.song1, self.song2)
# THEN: The result should be False. # THEN: The result should be False.
assert result == False, 'The result should be False' assert result is False, 'The result should be False'
def remove_typos_beginning_test(self): def remove_typos_beginning_test(self):
""" """
@ -267,8 +267,8 @@ class TestLib(TestCase):
# WHEN: We call strip_rtf on the input RTF # WHEN: We call strip_rtf on the input RTF
result, result_enc = strip_rtf( result, result_enc = strip_rtf(
'{\\rtf1 \\ansi \\ansicpg1252 {\\fonttbl \\f0 \\fswiss \\fcharset%s Helvetica;}' \ '{\\rtf1 \\ansi \\ansicpg1252 {\\fonttbl \\f0 \\fswiss \\fcharset%s Helvetica;}'
'{\\colortbl ;\\red0 \\green0 \\blue0 ;}\\pard \\f0 %s}' % (charset, input)) '{\\colortbl ;\\red0 \\green0 \\blue0 ;}\\pard \\f0 %s}' % (charset, input))
# THEN: The stripped text matches thed expected result # THEN: The stripped text matches thed expected result
assert result == exp_result, 'The result should be %s' % exp_result assert result == exp_result, 'The result should be %s' % exp_result

View File

@ -110,7 +110,7 @@ class TestSongBeamerImport(TestCase):
# THEN: do_import should return none and the progress bar setMaximum should be called with the length of # THEN: do_import should return none and the progress bar setMaximum should be called with the length of
# import_source. # import_source.
self.assertIsNone(importer.do_import(), self.assertIsNone(importer.do_import(),
'do_import should return None when import_source is a list and stop_import_flag is True') 'do_import should return None when import_source is a list and stop_import_flag is True')
mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source)) mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source))
def file_import_test(self): def file_import_test(self):
@ -147,9 +147,9 @@ class TestSongBeamerImport(TestCase):
for verse_text, verse_tag in add_verse_calls: for verse_text, verse_tag in add_verse_calls:
mocked_add_verse.assert_any_call(verse_text, verse_tag) mocked_add_verse.assert_any_call(verse_text, verse_tag)
if song_book_name: if song_book_name:
self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' %
% (song_file, song_book_name)) (song_file, song_book_name))
if song_number: if song_number:
self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s' self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s' %
% (song_file, song_number)) (song_file, song_number))
mocked_finish.assert_called_with() mocked_finish.assert_called_with()

View File

@ -352,7 +352,7 @@ class TestSongSelect(TestCase):
""" """
# GIVEN: A song to save, and some mocked out objects # GIVEN: A song to save, and some mocked out objects
with patch('openlp.plugins.songs.lib.songselect.clean_song') as mocked_clean_song, \ with patch('openlp.plugins.songs.lib.songselect.clean_song') as mocked_clean_song, \
patch('openlp.plugins.songs.lib.songselect.Author') as MockedAuthor: patch('openlp.plugins.songs.lib.songselect.Author') as MockedAuthor:
song_dict = { song_dict = {
'title': 'Arky Arky', 'title': 'Arky Arky',
'authors': ['Public Domain'], 'authors': ['Public Domain'],

View File

@ -115,8 +115,8 @@ class TestSongShowPlusImport(TestCase):
# THEN: do_import should return none and the progress bar setMaximum should be called with the length of # THEN: do_import should return none and the progress bar setMaximum should be called with the length of
# import_source. # import_source.
self.assertIsNone(importer.do_import(), self.assertIsNone(importer.do_import(), 'do_import should return None when import_source is a list '
'do_import should return None when import_source is a list and stop_import_flag is True') 'and stop_import_flag is True')
mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source)) mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source))
def to_openlp_verse_tag_test(self): def to_openlp_verse_tag_test(self):
@ -129,7 +129,8 @@ class TestSongShowPlusImport(TestCase):
importer = SongShowPlusImport(mocked_manager, filenames=[]) importer = SongShowPlusImport(mocked_manager, filenames=[])
# WHEN: Supplied with the following arguments replicating verses being added # WHEN: Supplied with the following arguments replicating verses being added
test_values = [('Verse 1', VerseType.tags[VerseType.Verse] + '1'), test_values = [
('Verse 1', VerseType.tags[VerseType.Verse] + '1'),
('Verse 2', VerseType.tags[VerseType.Verse] + '2'), ('Verse 2', VerseType.tags[VerseType.Verse] + '2'),
('verse1', VerseType.tags[VerseType.Verse] + '1'), ('verse1', VerseType.tags[VerseType.Verse] + '1'),
('Verse', VerseType.tags[VerseType.Verse] + '1'), ('Verse', VerseType.tags[VerseType.Verse] + '1'),
@ -143,8 +144,8 @@ class TestSongShowPlusImport(TestCase):
# THEN: The returned value should should correlate with the input arguments # THEN: The returned value should should correlate with the input arguments
for original_tag, openlp_tag in test_values: for original_tag, openlp_tag in test_values:
self.assertEquals(importer.to_openlp_verse_tag(original_tag), openlp_tag, self.assertEquals(importer.to_openlp_verse_tag(original_tag), openlp_tag,
'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' 'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' %
% (openlp_tag, original_tag)) (openlp_tag, original_tag))
def to_openlp_verse_tag_verse_order_test(self): def to_openlp_verse_tag_verse_order_test(self):
""" """
@ -156,7 +157,8 @@ class TestSongShowPlusImport(TestCase):
importer = SongShowPlusImport(mocked_manager, filenames=[]) importer = SongShowPlusImport(mocked_manager, filenames=[])
# WHEN: Supplied with the following arguments replicating a verse order being added # WHEN: Supplied with the following arguments replicating a verse order being added
test_values = [('Verse 1', VerseType.tags[VerseType.Verse] + '1'), test_values = [
('Verse 1', VerseType.tags[VerseType.Verse] + '1'),
('Verse 2', VerseType.tags[VerseType.Verse] + '2'), ('Verse 2', VerseType.tags[VerseType.Verse] + '2'),
('verse1', VerseType.tags[VerseType.Verse] + '1'), ('verse1', VerseType.tags[VerseType.Verse] + '1'),
('Verse', VerseType.tags[VerseType.Verse] + '1'), ('Verse', VerseType.tags[VerseType.Verse] + '1'),
@ -171,5 +173,5 @@ class TestSongShowPlusImport(TestCase):
# THEN: The returned value should should correlate with the input arguments # THEN: The returned value should should correlate with the input arguments
for original_tag, openlp_tag in test_values: for original_tag, openlp_tag in test_values:
self.assertEquals(importer.to_openlp_verse_tag(original_tag, ignore_unique=True), openlp_tag, self.assertEquals(importer.to_openlp_verse_tag(original_tag, ignore_unique=True), openlp_tag,
'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' 'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' %
% (openlp_tag, original_tag)) (openlp_tag, original_tag))

View File

@ -73,35 +73,37 @@ class WorshipCenterProImportLogger(WorshipCenterProImport):
RECORDSET_TEST_DATA = [TestRecord(1, 'TITLE', 'Amazing Grace'), RECORDSET_TEST_DATA = [TestRecord(1, 'TITLE', 'Amazing Grace'),
TestRecord(1, 'LYRICS', TestRecord(
'Amazing grace! How&crlf;sweet the sound&crlf;That saved a wretch like me!&crlf;' 1, 'LYRICS',
'I once was lost,&crlf;but now am found;&crlf;Was blind, but now I see.&crlf;&crlf;' 'Amazing grace! How&crlf;sweet the sound&crlf;That saved a wretch like me!&crlf;'
'\'Twas grace that&crlf;taught my heart to fear,&crlf;And grace my fears relieved;&crlf;' 'I once was lost,&crlf;but now am found;&crlf;Was blind, but now I see.&crlf;&crlf;'
'How precious did&crlf;that grace appear&crlf;The hour I first believed.&crlf;&crlf;' '\'Twas grace that&crlf;taught my heart to fear,&crlf;And grace my fears relieved;&crlf;'
'Through many dangers,&crlf;toils and snares,&crlf;I have already come;&crlf;' 'How precious did&crlf;that grace appear&crlf;The hour I first believed.&crlf;&crlf;'
'\'Tis grace hath brought&crlf;me safe thus far,&crlf;' 'Through many dangers,&crlf;toils and snares,&crlf;I have already come;&crlf;'
'And grace will lead me home.&crlf;&crlf;The Lord has&crlf;promised good to me,&crlf;' '\'Tis grace hath brought&crlf;me safe thus far,&crlf;'
'His Word my hope secures;&crlf;He will my Shield&crlf;and Portion be,&crlf;' 'And grace will lead me home.&crlf;&crlf;The Lord has&crlf;promised good to me,&crlf;'
'As long as life endures.&crlf;&crlf;Yea, when this flesh&crlf;and heart shall fail,&crlf;' 'His Word my hope secures;&crlf;He will my Shield&crlf;and Portion be,&crlf;'
'And mortal life shall cease,&crlf;I shall possess,&crlf;within the veil,&crlf;' 'As long as life endures.&crlf;&crlf;Yea, when this flesh&crlf;and heart shall fail,&crlf;'
'A life of joy and peace.&crlf;&crlf;The earth shall soon&crlf;dissolve like snow,&crlf;' 'And mortal life shall cease,&crlf;I shall possess,&crlf;within the veil,&crlf;'
'The sun forbear to shine;&crlf;But God, Who called&crlf;me here below,&crlf;' 'A life of joy and peace.&crlf;&crlf;The earth shall soon&crlf;dissolve like snow,&crlf;'
'Shall be forever mine.&crlf;&crlf;When we\'ve been there&crlf;ten thousand years,&crlf;' 'The sun forbear to shine;&crlf;But God, Who called&crlf;me here below,&crlf;'
'Bright shining as the sun,&crlf;We\'ve no less days to&crlf;sing God\'s praise&crlf;' 'Shall be forever mine.&crlf;&crlf;When we\'ve been there&crlf;ten thousand years,&crlf;'
'Than when we\'d first begun.&crlf;&crlf;'), 'Bright shining as the sun,&crlf;We\'ve no less days to&crlf;sing God\'s praise&crlf;'
'Than when we\'d first begun.&crlf;&crlf;'),
TestRecord(2, 'TITLE', 'Beautiful Garden Of Prayer, The'), TestRecord(2, 'TITLE', 'Beautiful Garden Of Prayer, The'),
TestRecord(2, 'LYRICS', TestRecord(
'There\'s a garden where&crlf;Jesus is waiting,&crlf;' 2, 'LYRICS',
'There\'s a place that&crlf;is wondrously fair,&crlf;For it glows with the&crlf;' 'There\'s a garden where&crlf;Jesus is waiting,&crlf;'
'light of His presence.&crlf;\'Tis the beautiful&crlf;garden of prayer.&crlf;&crlf;' 'There\'s a place that&crlf;is wondrously fair,&crlf;For it glows with the&crlf;'
'Oh, the beautiful garden,&crlf;the garden of prayer!&crlf;Oh, the beautiful&crlf;' 'light of His presence.&crlf;\'Tis the beautiful&crlf;garden of prayer.&crlf;&crlf;'
'garden of prayer!&crlf;There my Savior awaits,&crlf;and He opens the gates&crlf;' 'Oh, the beautiful garden,&crlf;the garden of prayer!&crlf;Oh, the beautiful&crlf;'
'To the beautiful&crlf;garden of prayer.&crlf;&crlf;There\'s a garden where&crlf;' 'garden of prayer!&crlf;There my Savior awaits,&crlf;and He opens the gates&crlf;'
'Jesus is waiting,&crlf;And I go with my&crlf;burden and care,&crlf;' 'To the beautiful&crlf;garden of prayer.&crlf;&crlf;There\'s a garden where&crlf;'
'Just to learn from His&crlf;lips words of comfort&crlf;In the beautiful&crlf;' 'Jesus is waiting,&crlf;And I go with my&crlf;burden and care,&crlf;'
'garden of prayer.&crlf;&crlf;There\'s a garden where&crlf;Jesus is waiting,&crlf;' 'Just to learn from His&crlf;lips words of comfort&crlf;In the beautiful&crlf;'
'And He bids you to come,&crlf;meet Him there;&crlf;Just to bow and&crlf;' 'garden of prayer.&crlf;&crlf;There\'s a garden where&crlf;Jesus is waiting,&crlf;'
'receive a new blessing&crlf;In the beautiful&crlf;garden of prayer.&crlf;&crlf;')] 'And He bids you to come,&crlf;meet Him there;&crlf;Just to bow and&crlf;'
'receive a new blessing&crlf;In the beautiful&crlf;garden of prayer.&crlf;&crlf;')]
SONG_TEST_DATA = [{'title': 'Amazing Grace', SONG_TEST_DATA = [{'title': 'Amazing Grace',
'verses': [ 'verses': [
('Amazing grace! How\nsweet the sound\nThat saved a wretch like me!\nI once was lost,\n' ('Amazing grace! How\nsweet the sound\nThat saved a wretch like me!\nI once was lost,\n'
@ -118,7 +120,7 @@ SONG_TEST_DATA = [{'title': 'Amazing Grace',
'me here below,\nShall be forever mine.'), 'me here below,\nShall be forever mine.'),
('When we\'ve been there\nten thousand years,\nBright shining as the sun,\n' ('When we\'ve been there\nten thousand years,\nBright shining as the sun,\n'
'We\'ve no less days to\nsing God\'s praise\nThan when we\'d first begun.')]}, 'We\'ve no less days to\nsing God\'s praise\nThan when we\'d first begun.')]},
{'title': 'Beautiful Garden Of Prayer, The', {'title': 'Beautiful Garden Of Prayer, The',
'verses': [ 'verses': [
('There\'s a garden where\nJesus is waiting,\nThere\'s a place that\nis wondrously fair,\n' ('There\'s a garden where\nJesus is waiting,\nThere\'s a place that\nis wondrously fair,\n'
'For it glows with the\nlight of His presence.\n\'Tis the beautiful\ngarden of prayer.'), 'For it glows with the\nlight of His presence.\n\'Tis the beautiful\ngarden of prayer.'),
@ -129,6 +131,7 @@ SONG_TEST_DATA = [{'title': 'Amazing Grace',
('There\'s a garden where\nJesus is waiting,\nAnd He bids you to come,\nmeet Him there;\n' ('There\'s a garden where\nJesus is waiting,\nAnd He bids you to come,\nmeet Him there;\n'
'Just to bow and\nreceive a new blessing\nIn the beautiful\ngarden of prayer.')]}] 'Just to bow and\nreceive a new blessing\nIn the beautiful\ngarden of prayer.')]}]
class TestWorshipCenterProSongImport(TestCase): class TestWorshipCenterProSongImport(TestCase):
""" """
Test the functions in the :mod:`worshipcenterproimport` module. Test the functions in the :mod:`worshipcenterproimport` module.
@ -155,7 +158,7 @@ class TestWorshipCenterProSongImport(TestCase):
# a mocked "manager" and a mocked out log_error method. # a mocked "manager" and a mocked out log_error method.
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \
patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \ patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \
patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate:
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_log_error = MagicMock() mocked_log_error = MagicMock()
mocked_translate.return_value = 'Translated Text' mocked_translate.return_value = 'Translated Text'
@ -171,9 +174,9 @@ class TestWorshipCenterProSongImport(TestCase):
# THEN: do_import should return None, and pyodbc, translate & log_error are called with known calls # THEN: do_import should return None, and pyodbc, translate & log_error are called with known calls
self.assertIsNone(return_value, 'do_import should return None when pyodbc raises an exception.') self.assertIsNone(return_value, 'do_import should return None when pyodbc raises an exception.')
mocked_pyodbc_connect.assert_called_with( 'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source') mocked_pyodbc_connect.assert_called_with('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source')
mocked_translate.assert_called_with('SongsPlugin.WorshipCenterProImport', mocked_translate.assert_called_with('SongsPlugin.WorshipCenterProImport',
'Unable to connect the WorshipCenter Pro database.') 'Unable to connect the WorshipCenter Pro database.')
mocked_log_error.assert_called_with('import_source', 'Translated Text') mocked_log_error.assert_called_with('import_source', 'Translated Text')
def song_import_test(self): def song_import_test(self):
@ -184,7 +187,7 @@ class TestWorshipCenterProSongImport(TestCase):
# translate method, a mocked "manager", add_verse method & mocked_finish method. # translate method, a mocked "manager", add_verse method & mocked_finish method.
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \
patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \
patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate:
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
mocked_add_verse = MagicMock() mocked_add_verse = MagicMock()
@ -201,9 +204,8 @@ class TestWorshipCenterProSongImport(TestCase):
# WHEN: Calling the do_import method # WHEN: Calling the do_import method
return_value = importer.do_import() return_value = importer.do_import()
# THEN: do_import should return None, and pyodbc, import_wizard, importer.title and add_verse are called
# THEN: do_import should return None, and pyodbc, import_wizard, importer.title and add_verse are called with # with known calls
# known calls
self.assertIsNone(return_value, 'do_import should return None when pyodbc raises an exception.') self.assertIsNone(return_value, 'do_import should return None when pyodbc raises an exception.')
mocked_pyodbc.connect.assert_called_with('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source') mocked_pyodbc.connect.assert_called_with('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source')
mocked_pyodbc.connect().cursor.assert_any_call() mocked_pyodbc.connect().cursor.assert_any_call()
@ -214,10 +216,10 @@ class TestWorshipCenterProSongImport(TestCase):
for song_data in SONG_TEST_DATA: for song_data in SONG_TEST_DATA:
title_value = song_data['title'] title_value = song_data['title']
self.assertIn(title_value, importer._title_assignment_list, self.assertIn(title_value, importer._title_assignment_list,
'title should have been set to %s' % title_value) 'title should have been set to %s' % title_value)
verse_calls = song_data['verses'] verse_calls = song_data['verses']
add_verse_call_count += len(verse_calls) add_verse_call_count += len(verse_calls)
for call in verse_calls: for call in verse_calls:
mocked_add_verse.assert_any_call(call) mocked_add_verse.assert_any_call(call)
self.assertEqual(mocked_add_verse.call_count, add_verse_call_count, self.assertEqual(mocked_add_verse.call_count, add_verse_call_count,
'Incorrect number of calls made to add_verse') 'Incorrect number of calls made to add_verse')

View File

@ -116,28 +116,27 @@ class SongImportTestHelper(TestCase):
if song_copyright: if song_copyright:
self.mocked_add_copyright.assert_called_with(song_copyright) self.mocked_add_copyright.assert_called_with(song_copyright)
if ccli_number: if ccli_number:
self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' %
% (source_file_name, ccli_number)) (source_file_name, ccli_number))
for verse_text, verse_tag in add_verse_calls: for verse_text, verse_tag in add_verse_calls:
self.mocked_add_verse.assert_any_call(verse_text, verse_tag) self.mocked_add_verse.assert_any_call(verse_text, verse_tag)
if topics: if topics:
self.assertEquals(importer.topics, topics, 'topics for %s should be %s' % (source_file_name, topics)) self.assertEquals(importer.topics, topics, 'topics for %s should be %s' % (source_file_name, topics))
if comments: if comments:
self.assertEquals(importer.comments, comments, 'comments for %s should be "%s"' self.assertEquals(importer.comments, comments, 'comments for %s should be "%s"' %
% (source_file_name, comments)) (source_file_name, comments))
if song_book_name: if song_book_name:
self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' %
% (source_file_name, song_book_name)) (source_file_name, song_book_name))
if song_number: if song_number:
self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s' self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s' %
% (source_file_name, song_number)) (source_file_name, song_number))
if verse_order_list: if verse_order_list:
self.assertEquals(importer.verse_order_list, [], 'verse_order_list for %s should be %s' self.assertEquals(importer.verse_order_list, [], 'verse_order_list for %s should be %s' %
% (source_file_name, verse_order_list)) (source_file_name, verse_order_list))
self.mocked_finish.assert_called_with() self.mocked_finish.assert_called_with()
def _get_data(self, data, key): def _get_data(self, data, key):
if key in data: if key in data:
return data[key] return data[key]
return '' return ''

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -95,4 +95,3 @@ class TestPluginManager(TestCase, TestMixin):
assert 'songusage' in plugin_names, 'There should be a "songusage" plugin.' assert 'songusage' in plugin_names, 'There should be a "songusage" plugin.'
assert 'alerts' in plugin_names, 'There should be a "alerts" plugin.' assert 'alerts' in plugin_names, 'There should be a "alerts" plugin.'
assert 'remotes' in plugin_names, 'There should be a "remotes" plugin.' assert 'remotes' in plugin_names, 'There should be a "remotes" plugin.'

View File

@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 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 #
###############################################################################
"""
Module to test the EditCustomForm.
"""
from unittest import TestCase
from unittest.mock import MagicMock
from PyQt4 import QtCore, QtGui, QtTest
from openlp.core.common import Registry
from openlp.core.lib.searchedit import SearchEdit
from tests.helpers.testmixin import TestMixin
class SearchTypes(object):
First = 0
Second = 1
SECOND_PLACEHOLDER_TEXT = "Second Placeholder Text"
SEARCH_TYPES = [(SearchTypes.First, QtGui.QIcon(), "First", "First Placeholder Text"),
(SearchTypes.Second, QtGui.QIcon(), "Second", SECOND_PLACEHOLDER_TEXT)]
class TestSearchEdit(TestCase, TestMixin):
"""
Test the EditCustomForm.
"""
def setUp(self):
"""
Create the UI
"""
Registry.create()
self.get_application()
self.main_window = QtGui.QMainWindow()
Registry().register('main_window', self.main_window)
self.search_edit = SearchEdit(self.main_window)
# To complete set up we have to set the search types.
self.search_edit.set_search_types(SEARCH_TYPES)
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.main_window
def set_search_types_test(self):
"""
Test setting the search types of the search edit.
"""
# GIVEN: The search edit with the search types set. NOTE: The set_search_types(types) is called in the setUp()
# method!
# WHEN:
# THEN: The first search type should be the first one in the list.
assert self.search_edit.current_search_type() == SearchTypes.First, "The first search type should be selected."
def set_current_search_type_test(self):
"""
Test if changing the search type works.
"""
# GIVEN:
# WHEN: Change the search type
result = self.search_edit.set_current_search_type(SearchTypes.Second)
# THEN:
assert result, "The call should return success (True)."
assert self.search_edit.current_search_type() == SearchTypes.Second,\
"The search type should be SearchTypes.Second"
assert self.search_edit.placeholderText() == SECOND_PLACEHOLDER_TEXT,\
"The correct placeholder text should be 'Second Placeholder Text'."
def clear_button_visibility_test(self):
"""
Test if the clear button is hidden/shown correctly.
"""
# GIVEN: Everything is left to its defaults (hidden).
assert self.search_edit.clear_button.isHidden(), "Pre condition not met. Button should be hidden."
# WHEN: Type something in the search edit.
QtTest.QTest.keyPress(self.search_edit, QtCore.Qt.Key_A)
QtTest.QTest.keyRelease(self.search_edit, QtCore.Qt.Key_A)
# THEN: The clear button should not be hidden any more.
assert not self.search_edit.clear_button.isHidden(), "The clear button should be visible."
def press_clear_button_test(self):
"""
Check if the search edit behaves correctly when pressing the clear button.
"""
# GIVEN: A search edit with text.
QtTest.QTest.keyPress(self.search_edit, QtCore.Qt.Key_A)
QtTest.QTest.keyRelease(self.search_edit, QtCore.Qt.Key_A)
# WHEN: Press the clear button.
QtTest.QTest.mouseClick(self.search_edit.clear_button, QtCore.Qt.LeftButton)
# THEN: The search edit text should be cleared and the button be hidden.
assert not self.search_edit.text(), "The search edit should not have any text."
assert self.search_edit.clear_button.isHidden(), "The clear button should be hidden."
def resize_event_test(self):
"""
Just check if the resizeEvent() method is re-implemented.
"""
assert hasattr(self.search_edit, "resizeEvent"), "The search edit should re-implement the resizeEvent method."

View File

@ -85,4 +85,3 @@ class TestMainWindow(TestCase, TestMixin):
# THEN: The current widget should have been set. # THEN: The current widget should have been set.
self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2) self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2)

View File

@ -90,9 +90,8 @@ class TestStartNoteDialog(TestCase, TestMixin):
with patch('PyQt4.QtGui.QDialog.exec_'): with patch('PyQt4.QtGui.QDialog.exec_'):
self.form.exec_() self.form.exec_()
self.form.text_edit.setPlainText(text) self.form.text_edit.setPlainText(text)
okWidget = self.form.button_box.button(self.form.button_box.Save) ok_widget = self.form.button_box.button(self.form.button_box.Save)
QtTest.QTest.mouseClick(okWidget, QtCore.Qt.LeftButton) QtTest.QTest.mouseClick(ok_widget, QtCore.Qt.LeftButton)
# THEN the following text is returned # THEN the following text is returned
self.assertEqual(self.form.text_edit.toPlainText(), text, 'The new text should be returned') self.assertEqual(self.form.text_edit.toPlainText(), text, 'The new text should be returned')

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -86,4 +86,3 @@ class TestUtils(TestCase, TestMixin):
# THEN the result is false # THEN the result is false
assert result is True, 'The file is not an image file so the test should return True' assert result is True, 'The file is not an image file so the test should return True'

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -97,4 +97,3 @@ class TestBibleHTTP(TestCase):
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed'

View File

@ -115,4 +115,3 @@ class TestBibleManager(TestCase, TestMixin):
verses = self.manager.get_verse_count_by_book_ref_id('tests', 54, 3) verses = self.manager.get_verse_count_by_book_ref_id('tests', 54, 3)
# THEN the chapter count should be returned # THEN the chapter count should be returned
self.assertEqual(16, verses, '1 Timothy v3 should have 16 verses returned from the bible') self.assertEqual(16, verses, '1 Timothy v3 should have 16 verses returned from the bible')

View File

@ -83,7 +83,7 @@ class TestBibleManager(TestCase, TestMixin):
# WHEN asking to parse the bible reference # WHEN asking to parse the bible reference
results = parse_reference('1 Timothy 1', self.manager.db_cache['tests'], MagicMock(), 54) results = parse_reference('1 Timothy 1', self.manager.db_cache['tests'], MagicMock(), 54)
# THEN a verse array should be returned # THEN a verse array should be returned
self.assertEquals([(54, 1, 1, -1)], results , "The bible verses should matches the expected results") self.assertEquals([(54, 1, 1, -1)], results, "The bible verses should matches the expected results")
def parse_reference_two_test(self): def parse_reference_two_test(self):
""" """
@ -93,7 +93,7 @@ class TestBibleManager(TestCase, TestMixin):
# WHEN asking to parse the bible reference # WHEN asking to parse the bible reference
results = parse_reference('1 Timothy 1:1-2', self.manager.db_cache['tests'], MagicMock(), 54) results = parse_reference('1 Timothy 1:1-2', self.manager.db_cache['tests'], MagicMock(), 54)
# THEN a verse array should be returned # THEN a verse array should be returned
self.assertEquals([(54, 1, 1, 2)], results , "The bible verses should matches the expected results") self.assertEquals([(54, 1, 1, 2)], results, "The bible verses should matches the expected results")
def parse_reference_three_test(self): def parse_reference_three_test(self):
""" """
@ -103,4 +103,5 @@ class TestBibleManager(TestCase, TestMixin):
# WHEN asking to parse the bible reference # WHEN asking to parse the bible reference
results = parse_reference('1 Timothy 1:1-2:1', self.manager.db_cache['tests'], MagicMock(), 54) results = parse_reference('1 Timothy 1:1-2:1', self.manager.db_cache['tests'], MagicMock(), 54)
# THEN a verse array should be returned # THEN a verse array should be returned
self.assertEquals([(54,1,1,-1),(54,2,1,1)], results , "The bible verses should matches the expected results") self.assertEquals([(54, 1, 1, -1), (54, 2, 1, 1)], results, "The bible verses should matches the expected "
"results")

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -88,7 +88,6 @@ class TestEditCustomForm(TestCase, TestMixin):
self.assertEqual(self.form.title_edit.text(), '', 'The title edit should be empty') self.assertEqual(self.form.title_edit.text(), '', 'The title edit should be empty')
self.assertEqual(self.form.credit_edit.text(), '', 'The credit edit should be empty') self.assertEqual(self.form.credit_edit.text(), '', 'The credit edit should be empty')
def on_add_button_clicked_test(self): def on_add_button_clicked_test(self):
""" """
Test the on_add_button_clicked_test method / add_button button. Test the on_add_button_clicked_test method / add_button button.

View File

@ -92,4 +92,3 @@ class TestEditCustomSlideForm(TestCase, TestMixin):
# THEN: The dialog should have focus. # THEN: The dialog should have focus.
mocked_set_focus.assert_called_with() mocked_set_focus.assert_called_with()

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -25,4 +25,4 @@
# You should have received a copy of the GNU General Public License along # # 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 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################

View File

@ -145,4 +145,3 @@ class TestAuthorsForm(TestCase, TestMixin):
# THEN: The display_name_edit should have the correct value # THEN: The display_name_edit should have the correct value
self.assertEqual(self.form.display_edit.text(), display_name, 'The display name should be set correctly') self.assertEqual(self.form.display_edit.text(), display_name, 'The display name should be set correctly')

View File

@ -120,4 +120,3 @@ class TestEditVerseForm(TestCase, TestMixin):
# THEN: The verse text edit should have a Chorus:1 in it # THEN: The verse text edit should have a Chorus:1 in it
self.assertIn('---[Chorus:1]---', self.form.verse_text_edit.toPlainText(), self.assertIn('---[Chorus:1]---', self.form.verse_text_edit.toPlainText(),
'The verse text edit should have a "Chorus 1" marker') 'The verse text edit should have a "Chorus 1" marker')

View File

@ -48,4 +48,3 @@ def convert_file_service_item(test_path, name, row=0):
finally: finally:
open_file.close() open_file.close()
return first_line return first_line