Phase 2 complete

This commit is contained in:
Raoul Snyman 2017-10-10 00:08:44 -07:00
parent 4d68382d52
commit 15a4a93c96
102 changed files with 933 additions and 886 deletions

View File

@ -44,3 +44,4 @@ coverage
tags
output
htmlcov
openlp-test-projectordb.sqlite

View File

@ -27,7 +27,7 @@ import faulthandler
import multiprocessing
import sys
from openlp.core import main
from openlp.core.app import main
from openlp.core.common import is_win, is_macosx
from openlp.core.common.applocation import AppLocation
from openlp.core.common.path import create_paths

View File

@ -22,7 +22,3 @@
"""
The :mod:`openlp` module contains all the project produced OpenLP functionality
"""
from openlp import core, plugins
__all__ = ['core', 'plugins']

View File

@ -26,400 +26,3 @@ The :mod:`core` module provides all core application functions
All the core functions of the OpenLP application including the GUI, settings,
logging and a plugin framework are contained within the openlp.core module.
"""
import argparse
import logging
import sys
import time
from datetime import datetime
from traceback import format_exception
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import is_macosx, is_win
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import LanguageManager, UiStrings, translate
from openlp.core.common.mixins import OpenLPMixin
from openlp.core.common.path import create_paths, copytree
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.version import check_for_update, get_version
from openlp.core.lib import ScreenList
from openlp.core.resources import qInitResources
from openlp.core.ui import SplashScreen
from openlp.core.ui.exceptionform import ExceptionForm
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.style import get_application_stylesheet
__all__ = ['OpenLP', 'main']
log = logging.getLogger()
class OpenLP(OpenLPMixin, QtWidgets.QApplication):
"""
The core application class. This class inherits from Qt's QApplication
class in order to provide the core of the application.
"""
args = []
def exec(self):
"""
Override exec method to allow the shared memory to be released on exit
"""
self.is_event_loop_active = True
result = QtWidgets.QApplication.exec()
self.shared_memory.detach()
return result
def run(self, args):
"""
Run the OpenLP application.
:param args: Some Args
"""
self.is_event_loop_active = False
# On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use.
# On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line
# argument. This interferes with files being passed in as command line arguments, so we remove it from the list.
if 'OpenLP' in args:
args.remove('OpenLP')
self.args.extend(args)
# Decide how many screens we have and their size
screens = ScreenList.create(self.desktop())
# First time checks in settings
has_run_wizard = Settings().value('core/has run wizard')
if not has_run_wizard:
ftw = FirstTimeForm()
ftw.initialize(screens)
if ftw.exec() == QtWidgets.QDialog.Accepted:
Settings().setValue('core/has run wizard', True)
elif ftw.was_cancelled:
QtCore.QCoreApplication.exit()
sys.exit()
# Correct stylesheet bugs
application_stylesheet = get_application_stylesheet()
if application_stylesheet:
self.setStyleSheet(application_stylesheet)
can_show_splash = Settings().value('core/show splash')
if can_show_splash:
self.splash = SplashScreen()
self.splash.show()
# make sure Qt really display the splash screen
self.processEvents()
# Check if OpenLP has been upgrade and if a backup of data should be created
self.backup_on_upgrade(has_run_wizard, can_show_splash)
# start the main app window
self.main_window = MainWindow()
Registry().execute('bootstrap_initialise')
Registry().execute('bootstrap_post_set_up')
Registry().initialise = False
self.main_window.show()
if can_show_splash:
# now kill the splashscreen
self.splash.finish(self.main_window)
log.debug('Splashscreen closed')
# make sure Qt really display the splash screen
self.processEvents()
self.main_window.repaint()
self.processEvents()
if not has_run_wizard:
self.main_window.first_time()
if Settings().value('core/update check'):
check_for_update(self.main_window)
self.main_window.is_display_blank()
self.main_window.app_startup()
return self.exec()
def is_already_running(self):
"""
Look to see if OpenLP is already running and ask if a 2nd instance is to be started.
"""
self.shared_memory = QtCore.QSharedMemory('OpenLP')
if self.shared_memory.attach():
status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No))
if status == QtWidgets.QMessageBox.No:
return True
return False
else:
self.shared_memory.create(1)
return False
def is_data_path_missing(self):
"""
Check if the data folder path exists.
"""
data_folder_path = AppLocation.get_data_path()
if not data_folder_path.exists():
log.critical('Database was not found in: %s', data_folder_path)
status = QtWidgets.QMessageBox.critical(
None, translate('OpenLP', 'Data Directory Error'),
translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}\n\nThe location of the data folder '
'was previously changed from the OpenLP\'s default location. If the data was '
'stored on removable device, that device needs to be made available.\n\nYou may '
'reset the data location back to the default location, or you can try to make the '
'current location available.\n\nDo you want to reset to the default data location? '
'If not, OpenLP will be closed so you can try to fix the the problem.')
.format(path=data_folder_path),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
if status == QtWidgets.QMessageBox.No:
# If answer was "No", return "True", it will shutdown OpenLP in def main
log.info('User requested termination')
return True
# If answer was "Yes", remove the custom data path thus resetting the default location.
Settings().remove('advanced/data path')
log.info('Database location has been reset to the default settings.')
return False
def hook_exception(self, exc_type, value, traceback):
"""
Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where
users cannot see it and cannot report when we encounter these problems.
:param exc_type: The class of exception.
:param value: The actual exception object.
:param traceback: A traceback object with the details of where the exception occurred.
"""
# We can't log.exception here because the last exception no longer exists, we're actually busy handling it.
log.critical(''.join(format_exception(exc_type, value, traceback)))
if not hasattr(self, 'exception_form'):
self.exception_form = ExceptionForm()
self.exception_form.exception_text_edit.setPlainText(''.join(format_exception(exc_type, value, traceback)))
self.set_normal_cursor()
is_splash_visible = False
if hasattr(self, 'splash') and self.splash.isVisible():
is_splash_visible = True
self.splash.hide()
self.exception_form.exec()
if is_splash_visible:
self.splash.show()
def backup_on_upgrade(self, has_run_wizard, can_show_splash):
"""
Check if OpenLP has been upgraded, and ask if a backup of data should be made
:param has_run_wizard: OpenLP has been run before
:param can_show_splash: Should OpenLP show the splash screen
"""
data_version = Settings().value('core/application version')
openlp_version = get_version()['version']
# New installation, no need to create backup
if not has_run_wizard:
Settings().setValue('core/application version', openlp_version)
# If data_version is different from the current version ask if we should backup the data folder
elif data_version != openlp_version:
if can_show_splash and self.splash.isVisible():
self.splash.hide()
if QtWidgets.QMessageBox.question(None, translate('OpenLP', 'Backup'),
translate('OpenLP', 'OpenLP has been upgraded, do you want to create\n'
'a backup of the old data folder?'),
defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes:
# Create copy of data folder
data_folder_path = AppLocation.get_data_path()
timestamp = time.strftime("%Y%m%d-%H%M%S")
data_folder_backup_path = data_folder_path.with_name(data_folder_path.name + '-' + timestamp)
try:
copytree(data_folder_path, data_folder_backup_path)
except OSError:
QtWidgets.QMessageBox.warning(None, translate('OpenLP', 'Backup'),
translate('OpenLP', 'Backup of the data folder failed!'))
return
message = translate('OpenLP',
'A backup of the data folder has been created at:\n\n'
'{text}').format(text=data_folder_backup_path)
QtWidgets.QMessageBox.information(None, translate('OpenLP', 'Backup'), message)
# Update the version in the settings
Settings().setValue('core/application version', openlp_version)
if can_show_splash:
self.splash.show()
def process_events(self):
"""
Wrapper to make ProcessEvents visible and named correctly
"""
self.processEvents()
def set_busy_cursor(self):
"""
Sets the Busy Cursor for the Application
"""
self.setOverrideCursor(QtCore.Qt.BusyCursor)
self.processEvents()
def set_normal_cursor(self):
"""
Sets the Normal Cursor for the Application
"""
self.restoreOverrideCursor()
self.processEvents()
def event(self, event):
"""
Enables platform specific event handling i.e. direct file opening on OS X
:param event: The event
"""
if event.type() == QtCore.QEvent.FileOpen:
file_name = event.file()
log.debug('Got open file event for {name}!'.format(name=file_name))
self.args.insert(0, file_name)
return True
# Mac OS X should restore app window when user clicked on the OpenLP icon
# in the Dock bar. However, OpenLP consists of multiple windows and this
# does not work. This workaround fixes that.
# The main OpenLP window is restored when it was previously minimized.
elif event.type() == QtCore.QEvent.ApplicationActivate:
if is_macosx() and hasattr(self, 'main_window'):
if self.main_window.isMinimized():
# Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window
# while preserving its maximized and/or full-screen state.
self.main_window.setWindowState(self.main_window.windowState() & ~QtCore.Qt.WindowMinimized |
QtCore.Qt.WindowActive)
return True
return QtWidgets.QApplication.event(self, event)
def parse_options(args=None):
"""
Parse the command line arguments
:param args: list of command line arguments
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
"""
# Set up command line options.
parser = argparse.ArgumentParser(prog='openlp.py')
parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
help='Disable the error notification form.')
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
parser.add_argument('-p', '--portable', dest='portable', action='store_true',
help='Specify if this should be run as a portable app, '
'off a USB flash drive (not implemented).')
parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
help='Ignore the version file and pull the version directly from Bazaar')
parser.add_argument('-s', '--style', dest='style', help='Set the Qt5 style (passed directly to Qt5).')
parser.add_argument('-w', '--no-web-server', dest='no_web_server', action='store_false',
help='Turn off the Web and Socket Server ')
parser.add_argument('rargs', nargs='?', default=[])
# Parse command line options and deal with them. Use args supplied pragmatically if possible.
return parser.parse_args(args) if args else parser.parse_args()
def set_up_logging(log_path):
"""
Setup our logging using log_path
:param openlp.core.common.path.Path log_path: The file to save the log to.
:rtype: None
"""
create_paths(log_path, do_not_log=True)
file_path = log_path / 'openlp.log'
# TODO: FileHandler accepts a Path object in Py3.6
logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile)
if log.isEnabledFor(logging.DEBUG):
print('Logging to: {name}'.format(name=file_path))
def main(args=None):
"""
The main function which parses command line options and then runs
:param args: Some args
"""
args = parse_options(args)
qt_args = []
if args and args.loglevel.lower() in ['d', 'debug']:
log.setLevel(logging.DEBUG)
elif args and args.loglevel.lower() in ['w', 'warning']:
log.setLevel(logging.WARNING)
else:
log.setLevel(logging.INFO)
if args and args.style:
qt_args.extend(['-style', args.style])
# Throw the rest of the arguments at Qt, just in case.
qt_args.extend(args.rargs)
# Bug #1018855: Set the WM_CLASS property in X11
if not is_win() and not is_macosx():
qt_args.append('OpenLP')
# Initialise the resources
qInitResources()
# Now create and actually run the application.
application = OpenLP(qt_args)
application.setOrganizationName('OpenLP')
application.setOrganizationDomain('openlp.org')
application.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
application.setAttribute(QtCore.Qt.AA_DontCreateNativeWidgetSiblings, True)
if args and args.portable:
application.setApplicationName('OpenLPPortable')
Settings.setDefaultFormat(Settings.IniFormat)
# Get location OpenLPPortable.ini
portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve()
data_path = portable_path / 'Data'
set_up_logging(portable_path / 'Other')
log.info('Running portable')
portable_settings_path = data_path / 'OpenLP.ini'
# Make this our settings file
log.info('INI file: {name}'.format(name=portable_settings_path))
Settings.set_filename(str(portable_settings_path))
portable_settings = Settings()
# Set our data path
log.info('Data path: {name}'.format(name=data_path))
# Point to our data path
portable_settings.setValue('advanced/data path', data_path)
portable_settings.setValue('advanced/is portable', True)
portable_settings.sync()
else:
application.setApplicationName('OpenLP')
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
Registry.create()
Registry().register('application', application)
Registry().set_flag('no_web_server', args.no_web_server)
application.setApplicationVersion(get_version()['version'])
# Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one
if application.is_already_running():
sys.exit()
# If the custom data path is missing and the user wants to restore the data path, quit OpenLP.
if application.is_data_path_missing():
application.shared_memory.detach()
sys.exit()
# Upgrade settings.
settings = Settings()
if settings.can_upgrade():
now = datetime.now()
# Only back up if OpenLP has previously run.
if settings.value('core/has run wizard'):
back_up_path = AppLocation.get_data_path() / (now.strftime('%Y-%m-%d %H-%M') + '.conf')
log.info('Settings about to be upgraded. Existing settings are being backed up to {back_up_path}'
.format(back_up_path=back_up_path))
QtWidgets.QMessageBox.information(
None, translate('OpenLP', 'Settings Upgrade'),
translate('OpenLP', 'Your settings are about to upgraded. A backup will be created at {back_up_path}')
.format(back_up_path=back_up_path))
settings.export(back_up_path)
settings.upgrade_settings()
# First time checks in settings
if not Settings().value('core/has run wizard'):
if not FirstTimeLanguageForm().exec():
# if cancel then stop processing
sys.exit()
# i18n Set Language
language = LanguageManager.get_language()
translators = LanguageManager.get_translators(language)
for translator in translators:
if not translator.isEmpty():
application.installTranslator(translator)
if not translators:
log.debug('Could not find translators.')
if args and not args.no_error_form:
sys.excepthook = application.hook_exception
sys.exit(application.run(qt_args))

425
openlp/core/app.py Normal file
View File

@ -0,0 +1,425 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`core` module provides all core application functions
All the core functions of the OpenLP application including the GUI, settings,
logging and a plugin framework are contained within the openlp.core module.
"""
import argparse
import logging
import sys
import time
from datetime import datetime
from traceback import format_exception
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import is_macosx, is_win
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import LanguageManager, UiStrings, translate
from openlp.core.common.mixins import OpenLPMixin
from openlp.core.common.path import create_paths, copytree
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.version import check_for_update, get_version
from openlp.core.display.screens import ScreenList
from openlp.core.resources import qInitResources
from openlp.core.ui import SplashScreen
from openlp.core.ui.exceptionform import ExceptionForm
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.style import get_application_stylesheet
__all__ = ['OpenLP', 'main']
log = logging.getLogger()
class OpenLP(OpenLPMixin, QtWidgets.QApplication):
"""
The core application class. This class inherits from Qt's QApplication
class in order to provide the core of the application.
"""
args = []
def exec(self):
"""
Override exec method to allow the shared memory to be released on exit
"""
self.is_event_loop_active = True
result = QtWidgets.QApplication.exec()
self.shared_memory.detach()
return result
def run(self, args):
"""
Run the OpenLP application.
:param args: Some Args
"""
self.is_event_loop_active = False
# On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use.
# On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line
# argument. This interferes with files being passed in as command line arguments, so we remove it from the list.
if 'OpenLP' in args:
args.remove('OpenLP')
self.args.extend(args)
# Decide how many screens we have and their size
screens = ScreenList.create(self.desktop())
# First time checks in settings
has_run_wizard = Settings().value('core/has run wizard')
if not has_run_wizard:
ftw = FirstTimeForm()
ftw.initialize(screens)
if ftw.exec() == QtWidgets.QDialog.Accepted:
Settings().setValue('core/has run wizard', True)
elif ftw.was_cancelled:
QtCore.QCoreApplication.exit()
sys.exit()
# Correct stylesheet bugs
application_stylesheet = get_application_stylesheet()
if application_stylesheet:
self.setStyleSheet(application_stylesheet)
can_show_splash = Settings().value('core/show splash')
if can_show_splash:
self.splash = SplashScreen()
self.splash.show()
# make sure Qt really display the splash screen
self.processEvents()
# Check if OpenLP has been upgrade and if a backup of data should be created
self.backup_on_upgrade(has_run_wizard, can_show_splash)
# start the main app window
self.main_window = MainWindow()
Registry().execute('bootstrap_initialise')
Registry().execute('bootstrap_post_set_up')
Registry().initialise = False
self.main_window.show()
if can_show_splash:
# now kill the splashscreen
self.splash.finish(self.main_window)
log.debug('Splashscreen closed')
# make sure Qt really display the splash screen
self.processEvents()
self.main_window.repaint()
self.processEvents()
if not has_run_wizard:
self.main_window.first_time()
if Settings().value('core/update check'):
check_for_update(self.main_window)
self.main_window.is_display_blank()
self.main_window.app_startup()
return self.exec()
def is_already_running(self):
"""
Look to see if OpenLP is already running and ask if a 2nd instance is to be started.
"""
self.shared_memory = QtCore.QSharedMemory('OpenLP')
if self.shared_memory.attach():
status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No))
if status == QtWidgets.QMessageBox.No:
return True
return False
else:
self.shared_memory.create(1)
return False
def is_data_path_missing(self):
"""
Check if the data folder path exists.
"""
data_folder_path = AppLocation.get_data_path()
if not data_folder_path.exists():
log.critical('Database was not found in: %s', data_folder_path)
status = QtWidgets.QMessageBox.critical(
None, translate('OpenLP', 'Data Directory Error'),
translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}\n\nThe location of the data folder '
'was previously changed from the OpenLP\'s default location. If the data was '
'stored on removable device, that device needs to be made available.\n\nYou may '
'reset the data location back to the default location, or you can try to make the '
'current location available.\n\nDo you want to reset to the default data location? '
'If not, OpenLP will be closed so you can try to fix the the problem.')
.format(path=data_folder_path),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
if status == QtWidgets.QMessageBox.No:
# If answer was "No", return "True", it will shutdown OpenLP in def main
log.info('User requested termination')
return True
# If answer was "Yes", remove the custom data path thus resetting the default location.
Settings().remove('advanced/data path')
log.info('Database location has been reset to the default settings.')
return False
def hook_exception(self, exc_type, value, traceback):
"""
Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where
users cannot see it and cannot report when we encounter these problems.
:param exc_type: The class of exception.
:param value: The actual exception object.
:param traceback: A traceback object with the details of where the exception occurred.
"""
# We can't log.exception here because the last exception no longer exists, we're actually busy handling it.
log.critical(''.join(format_exception(exc_type, value, traceback)))
if not hasattr(self, 'exception_form'):
self.exception_form = ExceptionForm()
self.exception_form.exception_text_edit.setPlainText(''.join(format_exception(exc_type, value, traceback)))
self.set_normal_cursor()
is_splash_visible = False
if hasattr(self, 'splash') and self.splash.isVisible():
is_splash_visible = True
self.splash.hide()
self.exception_form.exec()
if is_splash_visible:
self.splash.show()
def backup_on_upgrade(self, has_run_wizard, can_show_splash):
"""
Check if OpenLP has been upgraded, and ask if a backup of data should be made
:param has_run_wizard: OpenLP has been run before
:param can_show_splash: Should OpenLP show the splash screen
"""
data_version = Settings().value('core/application version')
openlp_version = get_version()['version']
# New installation, no need to create backup
if not has_run_wizard:
Settings().setValue('core/application version', openlp_version)
# If data_version is different from the current version ask if we should backup the data folder
elif data_version != openlp_version:
if can_show_splash and self.splash.isVisible():
self.splash.hide()
if QtWidgets.QMessageBox.question(None, translate('OpenLP', 'Backup'),
translate('OpenLP', 'OpenLP has been upgraded, do you want to create\n'
'a backup of the old data folder?'),
defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes:
# Create copy of data folder
data_folder_path = AppLocation.get_data_path()
timestamp = time.strftime("%Y%m%d-%H%M%S")
data_folder_backup_path = data_folder_path.with_name(data_folder_path.name + '-' + timestamp)
try:
copytree(data_folder_path, data_folder_backup_path)
except OSError:
QtWidgets.QMessageBox.warning(None, translate('OpenLP', 'Backup'),
translate('OpenLP', 'Backup of the data folder failed!'))
return
message = translate('OpenLP',
'A backup of the data folder has been created at:\n\n'
'{text}').format(text=data_folder_backup_path)
QtWidgets.QMessageBox.information(None, translate('OpenLP', 'Backup'), message)
# Update the version in the settings
Settings().setValue('core/application version', openlp_version)
if can_show_splash:
self.splash.show()
def process_events(self):
"""
Wrapper to make ProcessEvents visible and named correctly
"""
self.processEvents()
def set_busy_cursor(self):
"""
Sets the Busy Cursor for the Application
"""
self.setOverrideCursor(QtCore.Qt.BusyCursor)
self.processEvents()
def set_normal_cursor(self):
"""
Sets the Normal Cursor for the Application
"""
self.restoreOverrideCursor()
self.processEvents()
def event(self, event):
"""
Enables platform specific event handling i.e. direct file opening on OS X
:param event: The event
"""
if event.type() == QtCore.QEvent.FileOpen:
file_name = event.file()
log.debug('Got open file event for {name}!'.format(name=file_name))
self.args.insert(0, file_name)
return True
# Mac OS X should restore app window when user clicked on the OpenLP icon
# in the Dock bar. However, OpenLP consists of multiple windows and this
# does not work. This workaround fixes that.
# The main OpenLP window is restored when it was previously minimized.
elif event.type() == QtCore.QEvent.ApplicationActivate:
if is_macosx() and hasattr(self, 'main_window'):
if self.main_window.isMinimized():
# Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window
# while preserving its maximized and/or full-screen state.
self.main_window.setWindowState(self.main_window.windowState() & ~QtCore.Qt.WindowMinimized |
QtCore.Qt.WindowActive)
return True
return QtWidgets.QApplication.event(self, event)
def parse_options(args=None):
"""
Parse the command line arguments
:param args: list of command line arguments
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
"""
# Set up command line options.
parser = argparse.ArgumentParser(prog='openlp.py')
parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
help='Disable the error notification form.')
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
parser.add_argument('-p', '--portable', dest='portable', action='store_true',
help='Specify if this should be run as a portable app, '
'off a USB flash drive (not implemented).')
parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
help='Ignore the version file and pull the version directly from Bazaar')
parser.add_argument('-s', '--style', dest='style', help='Set the Qt5 style (passed directly to Qt5).')
parser.add_argument('-w', '--no-web-server', dest='no_web_server', action='store_false',
help='Turn off the Web and Socket Server ')
parser.add_argument('rargs', nargs='?', default=[])
# Parse command line options and deal with them. Use args supplied pragmatically if possible.
return parser.parse_args(args) if args else parser.parse_args()
def set_up_logging(log_path):
"""
Setup our logging using log_path
:param openlp.core.common.path.Path log_path: The file to save the log to.
:rtype: None
"""
create_paths(log_path, do_not_log=True)
file_path = log_path / 'openlp.log'
# TODO: FileHandler accepts a Path object in Py3.6
logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile)
if log.isEnabledFor(logging.DEBUG):
print('Logging to: {name}'.format(name=file_path))
def main(args=None):
"""
The main function which parses command line options and then runs
:param args: Some args
"""
args = parse_options(args)
qt_args = []
if args and args.loglevel.lower() in ['d', 'debug']:
log.setLevel(logging.DEBUG)
elif args and args.loglevel.lower() in ['w', 'warning']:
log.setLevel(logging.WARNING)
else:
log.setLevel(logging.INFO)
if args and args.style:
qt_args.extend(['-style', args.style])
# Throw the rest of the arguments at Qt, just in case.
qt_args.extend(args.rargs)
# Bug #1018855: Set the WM_CLASS property in X11
if not is_win() and not is_macosx():
qt_args.append('OpenLP')
# Initialise the resources
qInitResources()
# Now create and actually run the application.
application = OpenLP(qt_args)
application.setOrganizationName('OpenLP')
application.setOrganizationDomain('openlp.org')
application.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
application.setAttribute(QtCore.Qt.AA_DontCreateNativeWidgetSiblings, True)
if args and args.portable:
application.setApplicationName('OpenLPPortable')
Settings.setDefaultFormat(Settings.IniFormat)
# Get location OpenLPPortable.ini
portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve()
data_path = portable_path / 'Data'
set_up_logging(portable_path / 'Other')
log.info('Running portable')
portable_settings_path = data_path / 'OpenLP.ini'
# Make this our settings file
log.info('INI file: {name}'.format(name=portable_settings_path))
Settings.set_filename(str(portable_settings_path))
portable_settings = Settings()
# Set our data path
log.info('Data path: {name}'.format(name=data_path))
# Point to our data path
portable_settings.setValue('advanced/data path', data_path)
portable_settings.setValue('advanced/is portable', True)
portable_settings.sync()
else:
application.setApplicationName('OpenLP')
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
Registry.create()
Registry().register('application', application)
Registry().set_flag('no_web_server', args.no_web_server)
application.setApplicationVersion(get_version()['version'])
# Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one
if application.is_already_running():
sys.exit()
# If the custom data path is missing and the user wants to restore the data path, quit OpenLP.
if application.is_data_path_missing():
application.shared_memory.detach()
sys.exit()
# Upgrade settings.
settings = Settings()
if settings.can_upgrade():
now = datetime.now()
# Only back up if OpenLP has previously run.
if settings.value('core/has run wizard'):
back_up_path = AppLocation.get_data_path() / (now.strftime('%Y-%m-%d %H-%M') + '.conf')
log.info('Settings about to be upgraded. Existing settings are being backed up to {back_up_path}'
.format(back_up_path=back_up_path))
QtWidgets.QMessageBox.information(
None, translate('OpenLP', 'Settings Upgrade'),
translate('OpenLP', 'Your settings are about to upgraded. A backup will be created at {back_up_path}')
.format(back_up_path=back_up_path))
settings.export(back_up_path)
settings.upgrade_settings()
# First time checks in settings
if not Settings().value('core/has run wizard'):
if not FirstTimeLanguageForm().exec():
# if cancel then stop processing
sys.exit()
# i18n Set Language
language = LanguageManager.get_language()
translators = LanguageManager.get_translators(language)
for translator in translators:
if not translator.isEmpty():
application.installTranslator(translator)
if not translators:
log.debug('Could not find translators.')
if args and not args.no_error_form:
sys.excepthook = application.hook_exception
sys.exit(application.run(qt_args))

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.display` module contains all the code related to rendering and output
"""

View File

@ -29,10 +29,11 @@ from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.common.path import path_to_str
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, ScreenList, ServiceItem, expand_tags, \
build_lyrics_format_css, build_lyrics_outline_css, build_chords_css
from openlp.core.display.screens import ScreenList
from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, ServiceItem, expand_tags, build_chords_css, \
build_lyrics_format_css, build_lyrics_outline_css
from openlp.core.common import ThemeLevel
from openlp.core.ui import MainDisplay
from openlp.core.ui.maindisplay import MainDisplay
VERSE = 'The Lord said to {r}Noah{/r}: \n' \
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \

View File

@ -23,7 +23,6 @@
The :mod:`screen` module provides management functionality for a machines'
displays.
"""
import logging
import copy

View File

@ -612,7 +612,6 @@ def create_separated_list(string_list):
from .exceptions import ValidationError
from .screen import ScreenList
from .formattingtags import FormattingTags
from .plugin import PluginStatus, StringContent, Plugin
from .pluginmanager import PluginManager
@ -620,7 +619,6 @@ from .settingstab import SettingsTab
from .serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
from .htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css, build_chords_css
from .imagemanager import ImageManager
from .renderer import Renderer
from .mediamanageritem import MediaManagerItem
from .projector.db import ProjectorDB, Projector
from .projector.pjlink import PJLink

View File

@ -33,7 +33,8 @@ from PyQt5 import QtCore
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ScreenList, resize_image, image_to_byte
from openlp.core.display.screens import ScreenList
from openlp.core.lib import resize_image, image_to_byte
log = logging.getLogger(__name__)

View File

@ -30,7 +30,8 @@ from lxml import etree, objectify
from openlp.core.common import de_hump
from openlp.core.common.applocation import AppLocation
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
from openlp.core.lib import ScreenList, str_to_bool, get_text_file_string
from openlp.core.display.screens import ScreenList
from openlp.core.lib import str_to_bool, get_text_file_string
log = logging.getLogger(__name__)

View File

@ -31,7 +31,8 @@ from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.path import Path
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab, ScreenList
from openlp.core.display.screens import ScreenList
from openlp.core.lib import SettingsTab
from openlp.core.ui.lib import ColorButton, PathEdit
log = logging.getLogger(__name__)

View File

@ -28,7 +28,8 @@ import logging
from PyQt5 import QtWidgets
from openlp.core.lib import ScreenList, build_icon
from openlp.core.display.screens import ScreenList
from openlp.core.lib import build_icon
log = logging.getLogger(__name__)

View File

@ -40,7 +40,8 @@ from openlp.core.common.mixins import OpenLPMixin
from openlp.core.common.path import path_to_str
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import ServiceItem, ImageSource, ScreenList, build_html, expand_tags, image_to_byte
from openlp.core.display.screens import ScreenList
from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte
from openlp.core.lib.theme import BackgroundType
from openlp.core.ui import HideMode, AlertLocation, DisplayControllerType

View File

@ -43,17 +43,19 @@ from openlp.core.common.i18n import LanguageManager, UiStrings, translate
from openlp.core.common.path import Path, copyfile, create_paths, path_to_str, str_to_path
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon
from openlp.core.display.screens import ScreenList
from openlp.core.display.renderer import Renderer
from openlp.core.lib import PluginManager, ImageManager, PluginStatus, build_icon
from openlp.core.lib.ui import create_action
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \
ShortcutListForm, FormattingTagForm, PreviewController
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.media import MediaController
from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.ui.projector.manager import ProjectorManager
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
from openlp.core.ui.lib.filedialog import FileDialog
from openlp.core.ui.lib.mediadockmanager import MediaDockManager
from openlp.core.ui.media import MediaController
from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.ui.projector.manager import ProjectorManager
from openlp.core.ui.style import PROGRESSBAR_STYLE, get_library_stylesheet
from openlp.core.version import get_version

View File

@ -36,8 +36,8 @@ from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, ScreenList, build_icon, \
build_html
from openlp.core.display.screens import ScreenList
from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, build_icon, build_html
from openlp.core.lib.ui import create_action
from openlp.core.ui.lib.toolbar import OpenLPToolbar
from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget

View File

@ -38,7 +38,7 @@ from PyQt5 import QtCore
from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win
from openlp.core.common.registry import Registry
from openlp.core.lib import ScreenList
from openlp.core.display.screens import ScreenList
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \
TextType

View File

@ -29,7 +29,7 @@ from openlp.core.common import check_binary_exists, is_win
from openlp.core.common.applocation import AppLocation
from openlp.core.common.path import which
from openlp.core.common.settings import Settings
from openlp.core.lib import ScreenList
from openlp.core.display.screens import ScreenList
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
if is_win():

View File

@ -31,7 +31,7 @@ from openlp.core.common import is_win, trace_error_handler
from openlp.core.common.i18n import UiStrings
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ScreenList
from openlp.core.display.screens import ScreenList
from openlp.core.lib.ui import critical_error_message_box, translate
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument

View File

@ -26,7 +26,7 @@ from xml.etree import ElementTree
from openlp.core.common import is_win
from openlp.core.common.applocation import AppLocation
from openlp.core.lib import ScreenList
from openlp.core.display.screens import ScreenList
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
if is_win():

View File

@ -27,7 +27,7 @@ from unittest import TestCase
from openlp.core.api.deploy import deploy_zipfile
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
class TestRemoteDeploy(TestCase):

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Test the :mod:`~openlp.core.display` module
"""

View File

@ -28,8 +28,9 @@ from unittest.mock import MagicMock, patch
from PyQt5 import QtCore
from openlp.core.common.registry import Registry
from openlp.core.lib import Renderer, ScreenList, ServiceItem, FormattingTags
from openlp.core.lib.renderer import words_split, get_start_tags
from openlp.core.display.screens import ScreenList
from openlp.core.display.renderer import Renderer, words_split, get_start_tags
from openlp.core.lib import ServiceItem
from openlp.core.lib.theme import Theme
@ -83,15 +84,16 @@ class TestRenderer(TestCase):
Test the default layout calculations
"""
# GIVEN: A new renderer instance.
renderer = Renderer()
# WHEN: given the default screen size has been created.
# THEN: The renderer have created a default screen.
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.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')
renderer = Renderer()
@patch('openlp.core.lib.renderer.FormattingTags.get_html_tags')
# THEN: The renderer have created a default screen.
assert renderer.width == 1024, 'The base renderer should be a live controller'
assert renderer.height == 768, 'The base renderer should be a live controller'
assert renderer.screen_ratio == 0.75, 'The base renderer should be a live controller'
assert renderer.footer_start == 691, 'The base renderer should be a live controller'
@patch('openlp.core.display.renderer.FormattingTags.get_html_tags')
def test_get_start_tags(self, mocked_get_html_tags):
"""
Test the get_start_tags() method
@ -179,10 +181,10 @@ class TestRenderer(TestCase):
# THEN: The blanks have been removed.
self.assertListEqual(result_words, expected_words)
@patch('openlp.core.lib.renderer.QtWebKitWidgets.QWebView')
@patch('openlp.core.lib.renderer.build_lyrics_format_css')
@patch('openlp.core.lib.renderer.build_lyrics_outline_css')
@patch('openlp.core.lib.renderer.build_chords_css')
@patch('openlp.core.display.renderer.QtWebKitWidgets.QWebView')
@patch('openlp.core.display.renderer.build_lyrics_format_css')
@patch('openlp.core.display.renderer.build_lyrics_outline_css')
@patch('openlp.core.display.renderer.build_chords_css')
def test_set_text_rectangle(self, mock_build_chords_css, mock_outline_css, mock_lyrics_css, mock_webview):
"""
Test set_text_rectangle returns a proper html string

View File

@ -28,7 +28,7 @@ from unittest.mock import MagicMock
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.registry import Registry
from openlp.core.lib import ScreenList
from openlp.core.display.screens import ScreenList
SCREEN = {
'primary': False,

View File

@ -34,7 +34,6 @@ from sqlalchemy import MetaData
from openlp.core.common.path import Path
from openlp.core.lib.db import init_db, get_upgrade_op, delete_database, upgrade_db
from openlp.core.lib.projector import upgrade as pjlink_upgrade
class TestDB(TestCase):
@ -163,16 +162,16 @@ class TestDB(TestCase):
mocked_delete_file.assert_called_with(test_location)
self.assertFalse(result, 'The result of delete_file should be False (was rigged that way)')
@patch('tests.functional.openlp_core_lib.test_db.pjlink_upgrade')
def test_skip_db_upgrade_with_no_database(self, mocked_upgrade):
def test_skip_db_upgrade_with_no_database(self):
"""
Test the upgrade_db function does not try to update a missing database
"""
# GIVEN: Database URL that does not (yet) exist
url = 'sqlite:///{tmp}/test_db.sqlite'.format(tmp=self.tmp_folder)
mocked_upgrade = MagicMock()
# WHEN: We attempt to upgrade a non-existant database
upgrade_db(url, pjlink_upgrade)
upgrade_db(url, mocked_upgrade)
# THEN: upgrade should NOT have been called
self.assertFalse(mocked_upgrade.called, 'Database upgrade function should NOT have been called')

View File

@ -31,12 +31,12 @@ from unittest.mock import patch
from PyQt5 import QtGui
from openlp.core.common.registry import Registry
from openlp.core.lib import ImageManager, ScreenList
from openlp.core.lib.imagemanager import Priority
from openlp.core.display.screens import ScreenList
from openlp.core.lib.imagemanager import ImageManager, Priority
from tests.helpers.testmixin import TestMixin
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
class TestImageManager(TestCase, TestMixin):
@ -152,8 +152,8 @@ class TestImageManager(TestCase, TestMixin):
# Allow the queue to process.
self.lock.release()
# Request some "data".
image_bytes = self.image_manager.get_image_bytes(TEST_PATH, image4)
image_object = self.image_manager.get_image(TEST_PATH, image3)
self.image_manager.get_image_bytes(TEST_PATH, image4)
self.image_manager.get_image(TEST_PATH, image3)
# Now the mocked methods/functions do not have to sleep anymore.
self.sleep_time = 0
# Wait for the queue to finish.

View File

@ -33,7 +33,7 @@ from openlp.core.lib import FormattingTags, build_icon, check_item_selected, cle
create_separated_list, create_thumb, expand_chords, expand_chords_for_printing, expand_tags, find_formatting_tags, \
get_text_file_string, image_to_byte, resize_image, str_to_bool, validate_thumb
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
class TestLib(TestCase):

View File

@ -57,7 +57,7 @@ RENDERED_VERSE = 'The Lord said to <span style="-webkit-text-fill-color:red">Noa
'<span style="-webkit-text-fill-color:#FFA500">e</span><span style="-webkit-text-fill-color:#800080">'\
'n</span> of the Lord\n'
FOOTER = ['Arky Arky (Unknown)', 'Public Domain', 'CCLI 123456']
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources', 'service'))
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'service'))
class TestServiceItem(TestCase):

View File

@ -0,0 +1,378 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import os
import sys
from unittest import TestCase, skip
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtWidgets
from openlp.core.app import OpenLP, parse_options
from openlp.core.common.settings import Settings
from tests.helpers.testmixin import TestMixin
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources'))
def test_parse_options_basic():
"""
Test the parse options process works
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = []
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == 'warning', 'The log level should be set to warning'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
assert args.style is None, 'There are no style flags to be processed'
assert args.rargs == [], 'The service file should be blank'
def test_parse_options_debug():
"""
Test the parse options process works for debug only
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['-l debug']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == ' debug', 'The log level should be set to debug'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
assert args.style is None, 'There are no style flags to be processed'
assert args.rargs == [], 'The service file should be blank'
def test_parse_options_debug_and_portable():
"""
Test the parse options process works for debug and portable
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['--portable']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == 'warning', 'The log level should be set to warning'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is True, 'The portable flag should be set to true'
assert args.style is None, 'There are no style flags to be processed'
assert args.rargs == [], 'The service file should be blank'
def test_parse_options_all_no_file():
"""
Test the parse options process works with two options
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['-l debug', '-d']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
assert args.dev_version is True, 'The dev_version flag should be True'
assert args.loglevel == ' debug', 'The log level should be set to debug'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
assert args.style is None, 'There are no style flags to be processed'
assert args.rargs == [], 'The service file should be blank'
def test_parse_options_file():
"""
Test the parse options process works with a file
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['dummy_temp']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == 'warning', 'The log level should be set to warning'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
assert args.style is None, 'There are no style flags to be processed'
assert args.rargs == 'dummy_temp', 'The service file should not be blank'
def test_parse_options_file_and_debug():
"""
Test the parse options process works with a file and the debug log level
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['-l debug', 'dummy_temp']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == ' debug', 'The log level should be set to debug'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
assert args.style is None, 'There are no style flags to be processed'
assert args.rargs == 'dummy_temp', 'The service file should not be blank'
@skip('Figure out why this is causing a segfault')
class TestOpenLP(TestCase):
"""
Test the OpenLP app class
"""
@patch('openlp.core.app.QtWidgets.QApplication.exec')
def test_exec(self, mocked_exec):
"""
Test the exec method
"""
# GIVEN: An app
app = OpenLP([])
app.shared_memory = MagicMock()
mocked_exec.return_value = False
# WHEN: exec() is called
result = app.exec()
# THEN: The right things should be called
assert app.is_event_loop_active is True
mocked_exec.assert_called_once_with()
app.shared_memory.detach.assert_called_once_with()
assert result is False
@patch('openlp.core.app.QtCore.QSharedMemory')
def test_is_already_running_not_running(self, MockedSharedMemory):
"""
Test the is_already_running() method when OpenLP is NOT running
"""
# GIVEN: An OpenLP app and some mocks
mocked_shared_memory = MagicMock()
mocked_shared_memory.attach.return_value = False
MockedSharedMemory.return_value = mocked_shared_memory
app = OpenLP([])
# WHEN: is_already_running() is called
result = app.is_already_running()
# THEN: The result should be false
MockedSharedMemory.assert_called_once_with('OpenLP')
mocked_shared_memory.attach.assert_called_once_with()
mocked_shared_memory.create.assert_called_once_with(1)
assert result is False
@patch('openlp.core.app.QtWidgets.QMessageBox.critical')
@patch('openlp.core.app.QtWidgets.QMessageBox.StandardButtons')
@patch('openlp.core.app.QtCore.QSharedMemory')
def test_is_already_running_is_running_continue(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
"""
Test the is_already_running() method when OpenLP IS running and the user chooses to continue
"""
# GIVEN: An OpenLP app and some mocks
mocked_shared_memory = MagicMock()
mocked_shared_memory.attach.return_value = True
MockedSharedMemory.return_value = mocked_shared_memory
MockedStandardButtons.return_value = 0
mocked_critical.return_value = QtWidgets.QMessageBox.Yes
app = OpenLP([])
# WHEN: is_already_running() is called
result = app.is_already_running()
# THEN: The result should be false
MockedSharedMemory.assert_called_once_with('OpenLP')
mocked_shared_memory.attach.assert_called_once_with()
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
assert result is False
@patch('openlp.core.app.QtWidgets.QMessageBox.critical')
@patch('openlp.core.app.QtWidgets.QMessageBox.StandardButtons')
@patch('openlp.core.app.QtCore.QSharedMemory')
def test_is_already_running_is_running_stop(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
"""
Test the is_already_running() method when OpenLP IS running and the user chooses to stop
"""
# GIVEN: An OpenLP app and some mocks
mocked_shared_memory = MagicMock()
mocked_shared_memory.attach.return_value = True
MockedSharedMemory.return_value = mocked_shared_memory
MockedStandardButtons.return_value = 0
mocked_critical.return_value = QtWidgets.QMessageBox.No
app = OpenLP([])
# WHEN: is_already_running() is called
result = app.is_already_running()
# THEN: The result should be false
MockedSharedMemory.assert_called_once_with('OpenLP')
mocked_shared_memory.attach.assert_called_once_with()
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
assert result is True
def test_process_events(self):
"""
Test that the app.process_events() method simply calls the Qt method
"""
# GIVEN: An app
app = OpenLP([])
# WHEN: process_events() is called
with patch.object(app, 'processEvents') as mocked_processEvents:
app.process_events()
# THEN: processEvents was called
mocked_processEvents.assert_called_once_with()
def test_set_busy_cursor(self):
"""
Test that the set_busy_cursor() method sets the cursor
"""
# GIVEN: An app
app = OpenLP([])
# WHEN: set_busy_cursor() is called
with patch.object(app, 'setOverrideCursor') as mocked_setOverrideCursor, \
patch.object(app, 'processEvents') as mocked_processEvents:
app.set_busy_cursor()
# THEN: The cursor should have been set
mocked_setOverrideCursor.assert_called_once_with(QtCore.Qt.BusyCursor)
mocked_processEvents.assert_called_once_with()
def test_set_normal_cursor(self):
"""
Test that the set_normal_cursor() method resets the cursor
"""
# GIVEN: An app
app = OpenLP([])
# WHEN: set_normal_cursor() is called
with patch.object(app, 'restoreOverrideCursor') as mocked_restoreOverrideCursor, \
patch.object(app, 'processEvents') as mocked_processEvents:
app.set_normal_cursor()
# THEN: The cursor should have been set
mocked_restoreOverrideCursor.assert_called_once_with()
mocked_processEvents.assert_called_once_with()
class TestInit(TestCase, TestMixin):
def setUp(self):
self.build_settings()
with patch('openlp.core.app.OpenLPMixin.__init__') as constructor:
constructor.return_value = None
self.openlp = OpenLP(list())
def tearDown(self):
self.destroy_settings()
del self.openlp
def test_event(self):
"""
Test the reimplemented event method
"""
# GIVEN: A file path and a QEvent.
file_path = os.path.join(TEST_PATH, 'church.jpg')
mocked_file_method = MagicMock(return_value=file_path)
event = QtCore.QEvent(QtCore.QEvent.FileOpen)
event.file = mocked_file_method
# WHEN: Call the vent method.
result = self.openlp.event(event)
# THEN: The path should be inserted.
self.assertTrue(result, "The method should have returned True.")
mocked_file_method.assert_called_once_with()
self.assertEqual(self.openlp.args[0], file_path, "The path should be in args.")
@patch('openlp.core.app.is_macosx')
def test_application_activate_event(self, mocked_is_macosx):
"""
Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized
"""
# GIVEN: Mac OS X and an ApplicationActivate event
mocked_is_macosx.return_value = True
event = MagicMock()
event.type.return_value = QtCore.QEvent.ApplicationActivate
mocked_main_window = MagicMock()
self.openlp.main_window = mocked_main_window
# WHEN: The icon in the dock is clicked
result = self.openlp.event(event)
# THEN:
self.assertTrue(result, "The method should have returned True.")
# self.assertFalse(self.openlp.main_window.isMinimized())
@patch('openlp.core.app.get_version')
@patch('openlp.core.app.QtWidgets.QMessageBox.question')
def test_backup_on_upgrade_first_install(self, mocked_question, mocked_get_version):
"""
Test that we don't try to backup on a new install
"""
# GIVEN: Mocked data version and OpenLP version which are the same
old_install = False
MOCKED_VERSION = {
'full': '2.2.0-bzr000',
'version': '2.2.0',
'build': 'bzr000'
}
Settings().setValue('core/application version', '2.2.0')
mocked_get_version.return_value = MOCKED_VERSION
mocked_question.return_value = QtWidgets.QMessageBox.No
# WHEN: We check if a backup should be created
self.openlp.backup_on_upgrade(old_install, False)
# THEN: It should not ask if we want to create a backup
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!')
self.assertEqual(mocked_question.call_count, 0, 'No question should have been asked!')
@patch('openlp.core.app.get_version')
@patch('openlp.core.app.QtWidgets.QMessageBox.question')
def test_backup_on_upgrade(self, mocked_question, mocked_get_version):
"""
Test that we try to backup on a new install
"""
# GIVEN: Mocked data version and OpenLP version which are different
old_install = True
MOCKED_VERSION = {
'full': '2.2.0-bzr000',
'version': '2.2.0',
'build': 'bzr000'
}
Settings().setValue('core/application version', '2.0.5')
self.openlp.splash = MagicMock()
self.openlp.splash.isVisible.return_value = True
mocked_get_version.return_value = MOCKED_VERSION
mocked_question.return_value = QtWidgets.QMessageBox.No
# WHEN: We check if a backup should be created
self.openlp.backup_on_upgrade(old_install, True)
# THEN: It should ask if we want to create a backup
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
self.openlp.splash.hide.assert_called_once_with()
self.openlp.splash.show.assert_called_once_with()

View File

@ -1,273 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import sys
from unittest import TestCase, skip
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtWidgets
from openlp.core import OpenLP, parse_options
class TestInitFunctions(TestCase):
def test_parse_options_basic(self):
"""
Test the parse options process works
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = []
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
self.assertFalse(args.portable, 'The portable flag should be set to false')
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def test_parse_options_debug(self):
"""
Test the parse options process works for debug only
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['-l debug']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
self.assertFalse(args.portable, 'The portable flag should be set to false')
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def test_parse_options_debug_and_portable(self):
"""
Test the parse options process works for debug and portable
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['--portable']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
self.assertTrue(args.portable, 'The portable flag should be set to true')
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def test_parse_options_all_no_file(self):
"""
Test the parse options process works with two options
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['-l debug', '-d']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
self.assertTrue(args.dev_version, 'The dev_version flag should be True')
self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
self.assertFalse(args.portable, 'The portable flag should be set to false')
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def test_parse_options_file(self):
"""
Test the parse options process works with a file
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['dummy_temp']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
self.assertFalse(args.portable, 'The portable flag should be set to false')
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
def test_parse_options_file_and_debug(self):
"""
Test the parse options process works with a file and the debug log level
"""
# GIVEN: a a set of system arguments.
sys.argv[1:] = ['-l debug', 'dummy_temp']
# WHEN: We we parse them to expand to options
args = parse_options(None)
# THEN: the following fields will have been extracted.
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
self.assertFalse(args.portable, 'The portable flag should be set to false')
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
@skip('Figure out why this is causing a segfault')
class TestOpenLP(TestCase):
"""
Test the OpenLP app class
"""
@patch('openlp.core.QtWidgets.QApplication.exec')
def test_exec(self, mocked_exec):
"""
Test the exec method
"""
# GIVEN: An app
app = OpenLP([])
app.shared_memory = MagicMock()
mocked_exec.return_value = False
# WHEN: exec() is called
result = app.exec()
# THEN: The right things should be called
assert app.is_event_loop_active is True
mocked_exec.assert_called_once_with()
app.shared_memory.detach.assert_called_once_with()
assert result is False
@patch('openlp.core.QtCore.QSharedMemory')
def test_is_already_running_not_running(self, MockedSharedMemory):
"""
Test the is_already_running() method when OpenLP is NOT running
"""
# GIVEN: An OpenLP app and some mocks
mocked_shared_memory = MagicMock()
mocked_shared_memory.attach.return_value = False
MockedSharedMemory.return_value = mocked_shared_memory
app = OpenLP([])
# WHEN: is_already_running() is called
result = app.is_already_running()
# THEN: The result should be false
MockedSharedMemory.assert_called_once_with('OpenLP')
mocked_shared_memory.attach.assert_called_once_with()
mocked_shared_memory.create.assert_called_once_with(1)
assert result is False
@patch('openlp.core.QtWidgets.QMessageBox.critical')
@patch('openlp.core.QtWidgets.QMessageBox.StandardButtons')
@patch('openlp.core.QtCore.QSharedMemory')
def test_is_already_running_is_running_continue(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
"""
Test the is_already_running() method when OpenLP IS running and the user chooses to continue
"""
# GIVEN: An OpenLP app and some mocks
mocked_shared_memory = MagicMock()
mocked_shared_memory.attach.return_value = True
MockedSharedMemory.return_value = mocked_shared_memory
MockedStandardButtons.return_value = 0
mocked_critical.return_value = QtWidgets.QMessageBox.Yes
app = OpenLP([])
# WHEN: is_already_running() is called
result = app.is_already_running()
# THEN: The result should be false
MockedSharedMemory.assert_called_once_with('OpenLP')
mocked_shared_memory.attach.assert_called_once_with()
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
assert result is False
@patch('openlp.core.QtWidgets.QMessageBox.critical')
@patch('openlp.core.QtWidgets.QMessageBox.StandardButtons')
@patch('openlp.core.QtCore.QSharedMemory')
def test_is_already_running_is_running_stop(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
"""
Test the is_already_running() method when OpenLP IS running and the user chooses to stop
"""
# GIVEN: An OpenLP app and some mocks
mocked_shared_memory = MagicMock()
mocked_shared_memory.attach.return_value = True
MockedSharedMemory.return_value = mocked_shared_memory
MockedStandardButtons.return_value = 0
mocked_critical.return_value = QtWidgets.QMessageBox.No
app = OpenLP([])
# WHEN: is_already_running() is called
result = app.is_already_running()
# THEN: The result should be false
MockedSharedMemory.assert_called_once_with('OpenLP')
mocked_shared_memory.attach.assert_called_once_with()
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
assert result is True
def test_process_events(self):
"""
Test that the app.process_events() method simply calls the Qt method
"""
# GIVEN: An app
app = OpenLP([])
# WHEN: process_events() is called
with patch.object(app, 'processEvents') as mocked_processEvents:
app.process_events()
# THEN: processEvents was called
mocked_processEvents.assert_called_once_with()
def test_set_busy_cursor(self):
"""
Test that the set_busy_cursor() method sets the cursor
"""
# GIVEN: An app
app = OpenLP([])
# WHEN: set_busy_cursor() is called
with patch.object(app, 'setOverrideCursor') as mocked_setOverrideCursor, \
patch.object(app, 'processEvents') as mocked_processEvents:
app.set_busy_cursor()
# THEN: The cursor should have been set
mocked_setOverrideCursor.assert_called_once_with(QtCore.Qt.BusyCursor)
mocked_processEvents.assert_called_once_with()
def test_set_normal_cursor(self):
"""
Test that the set_normal_cursor() method resets the cursor
"""
# GIVEN: An app
app = OpenLP([])
# WHEN: set_normal_cursor() is called
with patch.object(app, 'restoreOverrideCursor') as mocked_restoreOverrideCursor, \
patch.object(app, 'processEvents') as mocked_processEvents:
app.set_normal_cursor()
# THEN: The cursor should have been set
mocked_restoreOverrideCursor.assert_called_once_with()
mocked_processEvents.assert_called_once_with()

View File

@ -30,7 +30,8 @@ from PyQt5 import QtCore
from openlp.core.common import is_macosx
from openlp.core.common.path import Path
from openlp.core.common.registry import Registry
from openlp.core.lib import ScreenList, PluginManager
from openlp.core.display.screens import ScreenList
from openlp.core.lib import PluginManager
from openlp.core.ui import MainDisplay, AudioPlayer
from openlp.core.ui.maindisplay import TRANSPARENT_STYLESHEET, OPAQUE_STYLESHEET

View File

@ -27,8 +27,8 @@ from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtGui
from openlp.core import Registry
from openlp.core.lib import ImageSource, ServiceItemAction
from openlp.core.common.registry import Registry
from openlp.core.lib import ServiceItemAction
from openlp.core.ui import SlideController, LiveController, PreviewController
from openlp.core.ui.slidecontroller import InfoLabel, WIDE_MENU, NON_TEXT_MENU

View File

@ -27,7 +27,7 @@ from unittest.mock import MagicMock, patch
from PyQt5 import QtCore
from openlp.core import Settings
from openlp.core.common.settings import Settings
from openlp.core.common.path import Path
from openlp.plugins.media.lib.mediaitem import MediaMediaItem

View File

@ -23,9 +23,9 @@
Test the media plugin
"""
from unittest import TestCase
from unittest.mock import MagicMock, patch
from unittest.mock import patch
from openlp.core import Registry
from openlp.core.common.registry import Registry
from openlp.plugins.media.mediaplugin import MediaPlugin, process_check_binary
from tests.helpers.testmixin import TestMixin

View File

@ -33,7 +33,7 @@ from PyQt5 import QtCore, QtGui
from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument
from openlp.core.common.settings import Settings
from openlp.core.common.path import Path
from openlp.core.lib import ScreenList
from openlp.core.display.screens import ScreenList
from tests.utils.constants import TEST_RESOURCES_PATH
from tests.helpers.testmixin import TestMixin

View File

@ -30,11 +30,11 @@ from urllib.error import URLError
from PyQt5 import QtWidgets
from openlp.core import Registry
from openlp.core.common.registry import Registry
from openlp.core.common.path import Path
from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker
from openlp.plugins.songs.lib import Song
from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGIN_PAGE, LOGOUT_URL, BASE_URL
from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGOUT_URL, BASE_URL
from tests.helpers.songfileimport import SongImportTestHelper
from tests.helpers.testmixin import TestMixin
@ -308,7 +308,7 @@ class TestSongSelectImport(TestCase, TestMixin):
importer.run_search = True
# WHEN: The stop method is called
results = importer.stop()
importer.stop()
# THEN: Searching should have stopped
self.assertFalse(importer.run_search, 'Searching should have been stopped')

View File

@ -25,7 +25,7 @@ This module contains tests for the Songusage plugin.
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core import Registry
from openlp.core.common.registry import Registry
from openlp.plugins.songusage.lib import upgrade
from openlp.plugins.songusage.lib.db import init_schema
from openlp.plugins.songusage.songusageplugin import SongUsagePlugin

View File

@ -1,137 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Package to test the openlp.core.__init__ package.
"""
import os
from unittest import TestCase
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtWidgets
from openlp.core import OpenLP
from openlp.core.common.settings import Settings
from tests.helpers.testmixin import TestMixin
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources'))
class TestInit(TestCase, TestMixin):
def setUp(self):
self.build_settings()
with patch('openlp.core.OpenLPMixin.__init__') as constructor:
constructor.return_value = None
self.openlp = OpenLP(list())
def tearDown(self):
self.destroy_settings()
del self.openlp
def test_event(self):
"""
Test the reimplemented event method
"""
# GIVEN: A file path and a QEvent.
file_path = os.path.join(TEST_PATH, 'church.jpg')
mocked_file_method = MagicMock(return_value=file_path)
event = QtCore.QEvent(QtCore.QEvent.FileOpen)
event.file = mocked_file_method
# WHEN: Call the vent method.
result = self.openlp.event(event)
# THEN: The path should be inserted.
self.assertTrue(result, "The method should have returned True.")
mocked_file_method.assert_called_once_with()
self.assertEqual(self.openlp.args[0], file_path, "The path should be in args.")
@patch('openlp.core.is_macosx')
def test_application_activate_event(self, mocked_is_macosx):
"""
Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized
"""
# GIVEN: Mac OS X and an ApplicationActivate event
mocked_is_macosx.return_value = True
event = MagicMock()
event.type.return_value = QtCore.QEvent.ApplicationActivate
mocked_main_window = MagicMock()
self.openlp.main_window = mocked_main_window
# WHEN: The icon in the dock is clicked
result = self.openlp.event(event)
# THEN:
self.assertTrue(result, "The method should have returned True.")
# self.assertFalse(self.openlp.main_window.isMinimized())
def test_backup_on_upgrade_first_install(self):
"""
Test that we don't try to backup on a new install
"""
# GIVEN: Mocked data version and OpenLP version which are the same
old_install = False
MOCKED_VERSION = {
'full': '2.2.0-bzr000',
'version': '2.2.0',
'build': 'bzr000'
}
Settings().setValue('core/application version', '2.2.0')
with patch('openlp.core.get_version') as mocked_get_version,\
patch('openlp.core.QtWidgets.QMessageBox.question') as mocked_question:
mocked_get_version.return_value = MOCKED_VERSION
mocked_question.return_value = QtWidgets.QMessageBox.No
# WHEN: We check if a backup should be created
self.openlp.backup_on_upgrade(old_install, False)
# THEN: It should not ask if we want to create a backup
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!')
self.assertEqual(mocked_question.call_count, 0, 'No question should have been asked!')
def test_backup_on_upgrade(self):
"""
Test that we try to backup on a new install
"""
# GIVEN: Mocked data version and OpenLP version which are different
old_install = True
MOCKED_VERSION = {
'full': '2.2.0-bzr000',
'version': '2.2.0',
'build': 'bzr000'
}
Settings().setValue('core/application version', '2.0.5')
self.openlp.splash = MagicMock()
self.openlp.splash.isVisible.return_value = True
with patch('openlp.core.get_version') as mocked_get_version, \
patch('openlp.core.QtWidgets.QMessageBox.question') as mocked_question:
mocked_get_version.return_value = MOCKED_VERSION
mocked_question.return_value = QtWidgets.QMessageBox.No
# WHEN: We check if a backup should be created
self.openlp.backup_on_upgrade(old_install, True)
# THEN: It should ask if we want to create a backup
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
self.openlp.splash.hide.assert_called_once_with()
self.openlp.splash.show.assert_called_once_with()

Some files were not shown because too many files have changed in this diff Show More