forked from openlp/openlp
Merge branch 'tests_1' into 'master'
Tests part 1 See merge request openlp/openlp!136
This commit is contained in:
commit
3bda907d4d
@ -376,7 +376,7 @@ def main():
|
|||||||
Registry().register('application-qt', application)
|
Registry().register('application-qt', application)
|
||||||
Registry().register('application', app)
|
Registry().register('application', app)
|
||||||
Registry().set_flag('no_web_server', args.no_web_server)
|
Registry().set_flag('no_web_server', args.no_web_server)
|
||||||
# Create and install settings.
|
# Upgrade settings.
|
||||||
app.settings = settings
|
app.settings = settings
|
||||||
Registry().register('settings', settings)
|
Registry().register('settings', settings)
|
||||||
application.setApplicationVersion(get_version()['version'])
|
application.setApplicationVersion(get_version()['version'])
|
||||||
|
@ -749,7 +749,7 @@ class Settings(QtCore.QSettings):
|
|||||||
self.remove('SettingsImport')
|
self.remove('SettingsImport')
|
||||||
# Get the settings.
|
# Get the settings.
|
||||||
keys = self.allKeys()
|
keys = self.allKeys()
|
||||||
export_settings = QtCore.QSettings(str(temp_path), Settings.IniFormat)
|
export_settings = QtCore.QSettings(str(temp_path), QtCore.QSettings.IniFormat)
|
||||||
# Add a header section.
|
# Add a header section.
|
||||||
# This is to insure it's our conf file for import.
|
# This is to insure it's our conf file for import.
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
|
@ -335,7 +335,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
"""
|
"""
|
||||||
Load self.settings from disk.
|
Load settings from disk.
|
||||||
"""
|
"""
|
||||||
self.settings.beginGroup(self.settings_section)
|
self.settings.beginGroup(self.settings_section)
|
||||||
# The max recent files value does not have an interface and so never
|
# The max recent files value does not have an interface and so never
|
||||||
@ -395,7 +395,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
Save self.settings to disk.
|
Save settings to disk.
|
||||||
"""
|
"""
|
||||||
self.settings.beginGroup(self.settings_section)
|
self.settings.beginGroup(self.settings_section)
|
||||||
self.settings.setValue('default service enabled', self.service_name_check_box.isChecked())
|
self.settings.setValue('default service enabled', self.service_name_check_box.isChecked())
|
||||||
|
@ -42,7 +42,6 @@ from openlp.core.common.i18n import LanguageManager, UiStrings, translate
|
|||||||
from openlp.core.common.mixins import LogMixin, RegistryProperties
|
from openlp.core.common.mixins import LogMixin, RegistryProperties
|
||||||
from openlp.core.common.path import create_paths
|
from openlp.core.common.path import create_paths
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.display.screens import ScreenList
|
from openlp.core.display.screens import ScreenList
|
||||||
from openlp.core.lib.plugin import PluginStatus
|
from openlp.core.lib.plugin import PluginStatus
|
||||||
from openlp.core.lib.ui import create_action
|
from openlp.core.lib.ui import create_action
|
||||||
@ -874,7 +873,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
|||||||
create_paths(temp_dir_path)
|
create_paths(temp_dir_path)
|
||||||
temp_config_path = temp_dir_path / import_file_path.name
|
temp_config_path = temp_dir_path / import_file_path.name
|
||||||
shutil.copyfile(import_file_path, temp_config_path)
|
shutil.copyfile(import_file_path, temp_config_path)
|
||||||
import_settings = Settings(str(temp_config_path), Settings.IniFormat)
|
import_settings = QtCore.QSettings(str(temp_config_path), QtCore.QSettings.IniFormat)
|
||||||
|
|
||||||
self.log_info('hook upgrade_plugin_settings')
|
self.log_info('hook upgrade_plugin_settings')
|
||||||
self.plugin_manager.hook_upgrade_plugin_settings(import_settings)
|
self.plugin_manager.hook_upgrade_plugin_settings(import_settings)
|
||||||
@ -1376,11 +1375,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
|||||||
else:
|
else:
|
||||||
self.log_info('No data copy requested')
|
self.log_info('No data copy requested')
|
||||||
# Change the location of data directory in config file.
|
# Change the location of data directory in config file.
|
||||||
settings = QtCore.QSettings()
|
self.settings.setValue('advanced/data path', self.new_data_path)
|
||||||
settings.setValue('advanced/data path', self.new_data_path)
|
|
||||||
# Check if the new data path is our default.
|
# Check if the new data path is our default.
|
||||||
if self.new_data_path == AppLocation.get_directory(AppLocation.DataDir):
|
if self.new_data_path == AppLocation.get_directory(AppLocation.DataDir):
|
||||||
settings.remove('advanced/data path')
|
self.settings.remove('advanced/data path')
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def open_cmd_line_files(self, args):
|
def open_cmd_line_files(self, args):
|
||||||
|
@ -389,9 +389,9 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
|
|||||||
|
|
||||||
def save_options(self):
|
def save_options(self):
|
||||||
"""
|
"""
|
||||||
Save the self.settings and close the dialog.
|
Save the settings and close the dialog.
|
||||||
"""
|
"""
|
||||||
# Save the self.settings for this dialog.
|
# Save the settings for this dialog.
|
||||||
self.settings.beginGroup('advanced')
|
self.settings.beginGroup('advanced')
|
||||||
self.settings.setValue('print slide text', self.slide_text_check_box.isChecked())
|
self.settings.setValue('print slide text', self.slide_text_check_box.isChecked())
|
||||||
self.settings.setValue('add page break', self.page_break_after_text.isChecked())
|
self.settings.setValue('add page break', self.page_break_after_text.isChecked())
|
||||||
|
@ -338,7 +338,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
# Append the optical string to the media list
|
# Append the optical string to the media list
|
||||||
file_paths.append(optical)
|
file_paths.append(optical)
|
||||||
self.load_list([str(optical)])
|
self.load_list([str(optical)])
|
||||||
self.settigns.setValue(self.settings_section + '/media files', file_paths)
|
self.settings.setValue(self.settings_section + '/media files', file_paths)
|
||||||
|
|
||||||
def on_open_device_stream(self):
|
def on_open_device_stream(self):
|
||||||
"""
|
"""
|
||||||
|
@ -18,8 +18,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License #
|
# You should have received a copy of the GNU General Public License #
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# import sys
|
import pytest
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
@ -30,9 +29,7 @@ from openlp.core.state import State
|
|||||||
# Mock QtWebEngineWidgets
|
# Mock QtWebEngineWidgets
|
||||||
# sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
|
# sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
|
||||||
|
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.display.screens import ScreenList
|
|
||||||
from openlp.core.lib.serviceitem import ServiceItem
|
from openlp.core.lib.serviceitem import ServiceItem
|
||||||
from tests.utils import convert_file_service_item
|
from tests.utils import convert_file_service_item
|
||||||
from tests.utils.constants import RESOURCE_PATH
|
from tests.utils.constants import RESOURCE_PATH
|
||||||
@ -47,102 +44,105 @@ SCREEN = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestController(TestCase):
|
@pytest.fixture
|
||||||
|
def test_controller_env(settings):
|
||||||
|
mocked_live_controller = MagicMock()
|
||||||
|
desktop = MagicMock()
|
||||||
|
desktop.primaryScreen.return_value = SCREEN['primary']
|
||||||
|
desktop.screenCount.return_value = SCREEN['number']
|
||||||
|
desktop.screenGeometry.return_value = SCREEN['size']
|
||||||
|
with patch('openlp.core.display.screens.QtWidgets.QApplication.screens') as mocked_screens:
|
||||||
|
mocked_screens.return_value = [
|
||||||
|
MagicMock(**{'geometry.return_value': SCREEN['size']})
|
||||||
|
]
|
||||||
|
# Mock the renderer and its format_slide method
|
||||||
|
mocked_renderer = MagicMock()
|
||||||
|
|
||||||
|
def side_effect_return_arg(arg1, arg2):
|
||||||
|
return [arg1]
|
||||||
|
|
||||||
|
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
|
||||||
|
mocked_renderer.format_slide = mocked_slide_formater
|
||||||
|
Registry().register('live_controller', mocked_live_controller)
|
||||||
|
Registry().register('renderer', mocked_renderer)
|
||||||
|
flask_app.config['TESTING'] = True
|
||||||
|
client = flask_app.test_client()
|
||||||
|
return mocked_live_controller, client
|
||||||
|
|
||||||
|
|
||||||
|
def test_controller_text_empty(test_controller_env):
|
||||||
"""
|
"""
|
||||||
Test the Remote plugin deploy functions
|
Remote API Tests : test the controller text method can be called with empty service item
|
||||||
"""
|
"""
|
||||||
|
# GIVEN: A mocked service with a dummy service item
|
||||||
|
mocked_live_controller = test_controller_env[0]
|
||||||
|
client = test_controller_env[1]
|
||||||
|
mocked_service_item = MagicMock()
|
||||||
|
mocked_service_item.get_frames.return_value = []
|
||||||
|
mocked_service_item.unique_identifier = 'mock-service-item'
|
||||||
|
mocked_live_controller.service_item = mocked_service_item
|
||||||
|
|
||||||
def setUp(self):
|
# WHEN: I trigger the method
|
||||||
"""
|
ret = client.get('/api/controller/live/text').get_json()
|
||||||
Setup for tests
|
|
||||||
"""
|
|
||||||
Registry.create()
|
|
||||||
self.registry = Registry()
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
self.mocked_live_controller = MagicMock()
|
|
||||||
self.desktop = MagicMock()
|
|
||||||
self.desktop.primaryScreen.return_value = SCREEN['primary']
|
|
||||||
self.desktop.screenCount.return_value = SCREEN['number']
|
|
||||||
self.desktop.screenGeometry.return_value = SCREEN['size']
|
|
||||||
with patch('openlp.core.display.screens.QtWidgets.QApplication.screens') as mocked_screens:
|
|
||||||
mocked_screens.return_value = [
|
|
||||||
MagicMock(**{'geometry.return_value': SCREEN['size']})
|
|
||||||
]
|
|
||||||
self.screens = ScreenList.create(self.desktop)
|
|
||||||
# Mock the renderer and its format_slide method
|
|
||||||
self.mocked_renderer = MagicMock()
|
|
||||||
|
|
||||||
def side_effect_return_arg(arg1, arg2):
|
# THEN: I get a basic set of results
|
||||||
return [arg1]
|
assert ret['results']['item'] == 'mock-service-item'
|
||||||
self.mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
|
assert len(ret['results']['slides']) == 0
|
||||||
self.mocked_renderer.format_slide = self.mocked_slide_formater
|
|
||||||
Registry().register('live_controller', self.mocked_live_controller)
|
|
||||||
Registry().register('renderer', self.mocked_renderer)
|
|
||||||
flask_app.config['TESTING'] = True
|
|
||||||
self.client = flask_app.test_client()
|
|
||||||
|
|
||||||
def test_controller_text_empty(self):
|
|
||||||
"""
|
|
||||||
Remote API Tests : test the controller text method can be called with empty service item
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked service with a dummy service item
|
|
||||||
mocked_service_item = MagicMock()
|
|
||||||
mocked_service_item.get_frames.return_value = []
|
|
||||||
mocked_service_item.unique_identifier = 'mock-service-item'
|
|
||||||
self.mocked_live_controller.service_item = mocked_service_item
|
|
||||||
|
|
||||||
# WHEN: I trigger the method
|
def test_controller_text(test_controller_env):
|
||||||
ret = self.client.get('/api/controller/live/text').get_json()
|
"""
|
||||||
|
Remote API Tests : test the controller text method can be called with a real service item
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked service with a dummy service item
|
||||||
|
mocked_live_controller = test_controller_env[0]
|
||||||
|
client = test_controller_env[1]
|
||||||
|
line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj')
|
||||||
|
mocked_live_controller.service_item = ServiceItem(None)
|
||||||
|
State().load_settings()
|
||||||
|
State().add_service("media", 0)
|
||||||
|
State().update_pre_conditions("media", True)
|
||||||
|
State().flush_preconditions()
|
||||||
|
mocked_live_controller.service_item.set_from_service(line)
|
||||||
|
mocked_live_controller.service_item._create_slides()
|
||||||
|
# WHEN: I trigger the method
|
||||||
|
ret = client.get('/api/controller/live/text').get_json()
|
||||||
|
|
||||||
# THEN: I get a basic set of results
|
# THEN: I get a basic set of results
|
||||||
assert ret['results']['item'] == 'mock-service-item'
|
results = ret['results']
|
||||||
assert len(ret['results']['slides']) == 0
|
assert isinstance(ret, dict)
|
||||||
|
assert len(results['slides']) == 2
|
||||||
|
|
||||||
def test_controller_text(self):
|
|
||||||
"""
|
|
||||||
Remote API Tests : test the controller text method can be called with a real service item
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked service with a dummy service item
|
|
||||||
line = convert_file_service_item(TEST_PATH, 'serviceitem_custom_1.osj')
|
|
||||||
self.mocked_live_controller.service_item = ServiceItem(None)
|
|
||||||
State().load_settings()
|
|
||||||
State().add_service("media", 0)
|
|
||||||
State().update_pre_conditions("media", True)
|
|
||||||
State().flush_preconditions()
|
|
||||||
self.mocked_live_controller.service_item.set_from_service(line)
|
|
||||||
self.mocked_live_controller.service_item._create_slides()
|
|
||||||
# WHEN: I trigger the method
|
|
||||||
ret = self.client.get('/api/controller/live/text').get_json()
|
|
||||||
|
|
||||||
# THEN: I get a basic set of results
|
def test_controller_direction_next(test_controller_env):
|
||||||
results = ret['results']
|
"""
|
||||||
assert isinstance(ret, dict)
|
Text the live next method is triggered
|
||||||
assert len(results['slides']) == 2
|
"""
|
||||||
|
# GIVEN: A mocked service with a dummy service item
|
||||||
|
mocked_emit = MagicMock()
|
||||||
|
mocked_live_controller = test_controller_env[0]
|
||||||
|
client = test_controller_env[1]
|
||||||
|
mocked_live_controller.slidecontroller_live_next.emit = mocked_emit
|
||||||
|
mocked_live_controller.service_item = MagicMock()
|
||||||
|
|
||||||
def test_controller_direction_next(self):
|
# WHEN: I trigger the method
|
||||||
"""
|
client.get('/api/controller/live/next')
|
||||||
Text the live next method is triggered
|
# THEN: The correct method is called
|
||||||
"""
|
mocked_emit.assert_called_once_with()
|
||||||
# GIVEN: A mocked service with a dummy service item
|
|
||||||
mocked_emit = MagicMock()
|
|
||||||
self.mocked_live_controller.slidecontroller_live_next.emit = mocked_emit
|
|
||||||
self.mocked_live_controller.service_item = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: I trigger the method
|
|
||||||
self.client.get('/api/controller/live/next')
|
|
||||||
# THEN: The correct method is called
|
|
||||||
mocked_emit.assert_called_once_with()
|
|
||||||
|
|
||||||
def test_controller_direction_previous(self):
|
def test_controller_direction_previous(test_controller_env):
|
||||||
"""
|
"""
|
||||||
Text the live next method is triggered
|
Text the live next method is triggered
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked service with a dummy service item
|
# GIVEN: A mocked service with a dummy service item
|
||||||
mocked_emit = MagicMock()
|
mocked_emit = MagicMock()
|
||||||
self.mocked_live_controller.slidecontroller_live_previous.emit = mocked_emit
|
mocked_live_controller = test_controller_env[0]
|
||||||
self.mocked_live_controller.service_item = MagicMock()
|
client = test_controller_env[1]
|
||||||
|
mocked_live_controller.slidecontroller_live_previous.emit = mocked_emit
|
||||||
|
mocked_live_controller.service_item = MagicMock()
|
||||||
|
|
||||||
# WHEN: I trigger the method
|
# WHEN: I trigger the method
|
||||||
self.client.get('/api/controller/live/previous')
|
client.get('/api/controller/live/previous')
|
||||||
# THEN: The correct method is called
|
# THEN: The correct method is called
|
||||||
mocked_emit.assert_called_once_with()
|
mocked_emit.assert_called_once_with()
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# ---------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
|
||||||
# (at your option) any later version. #
|
|
||||||
# #
|
|
||||||
# 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, see <https://www.gnu.org/licenses/>. #
|
|
||||||
##########################################################################
|
|
||||||
"""
|
|
||||||
Functional tests to test the Http Server Class.
|
|
||||||
"""
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, patch
|
|
||||||
|
|
||||||
from openlp.core.api.http.server import HttpServer
|
|
||||||
from openlp.core.common.registry import Registry
|
|
||||||
|
|
||||||
|
|
||||||
class TestHttpServer(TestCase):
|
|
||||||
"""
|
|
||||||
A test suite to test starting the http server
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create the UI
|
|
||||||
"""
|
|
||||||
Registry().create()
|
|
||||||
Registry().register('service_list', MagicMock())
|
|
||||||
|
|
||||||
@patch('openlp.core.api.http.server.HttpWorker')
|
|
||||||
@patch('openlp.core.api.http.server.run_thread')
|
|
||||||
def test_server_start(self, mocked_run_thread, MockHttpWorker):
|
|
||||||
"""
|
|
||||||
Test the starting of the Waitress Server with the disable flag set off
|
|
||||||
"""
|
|
||||||
# GIVEN: A new httpserver
|
|
||||||
# WHEN: I start the server
|
|
||||||
Registry().set_flag('no_web_server', False)
|
|
||||||
HttpServer()
|
|
||||||
|
|
||||||
# THEN: the api environment should have been created
|
|
||||||
assert mocked_run_thread.call_count == 1, 'The qthread should have been called once'
|
|
||||||
assert MockHttpWorker.call_count == 1, 'The http thread should have been called once'
|
|
||||||
|
|
||||||
@patch('openlp.core.api.http.server.HttpWorker')
|
|
||||||
@patch('openlp.core.api.http.server.run_thread')
|
|
||||||
def test_server_start_not_required(self, mocked_run_thread, MockHttpWorker):
|
|
||||||
"""
|
|
||||||
Test the starting of the Waitress Server with the disable flag set off
|
|
||||||
"""
|
|
||||||
# GIVEN: A new httpserver
|
|
||||||
# WHEN: I start the server
|
|
||||||
Registry().set_flag('no_web_server', True)
|
|
||||||
HttpServer()
|
|
||||||
|
|
||||||
# THEN: the api environment should have been created
|
|
||||||
assert mocked_run_thread.call_count == 0, 'The qthread should not have have been called'
|
|
||||||
assert MockHttpWorker.call_count == 0, 'The http thread should not have been called'
|
|
@ -1,167 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# ---------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
|
||||||
# (at your option) any later version. #
|
|
||||||
# #
|
|
||||||
# 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, see <https://www.gnu.org/licenses/>. #
|
|
||||||
##########################################################################
|
|
||||||
"""
|
|
||||||
Functional tests to test the Http init.
|
|
||||||
"""
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock
|
|
||||||
|
|
||||||
from openlp.core.api.http import authenticate, check_auth, requires_auth
|
|
||||||
from openlp.core.common.registry import Registry
|
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestInit(TestCase, TestMixin):
|
|
||||||
"""
|
|
||||||
A test suite to test the functions on the init
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create the UI
|
|
||||||
"""
|
|
||||||
Registry().create()
|
|
||||||
Registry().register('service_list', MagicMock())
|
|
||||||
self.build_settings()
|
|
||||||
self.password = 'c3VwZXJmbHk6bGFtYXM='
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
def test_auth(self):
|
|
||||||
"""
|
|
||||||
Test the check_auth method with a match
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: a known user
|
|
||||||
Settings().setValue('api/user id', "superfly")
|
|
||||||
Settings().setValue('api/password', "lamas")
|
|
||||||
|
|
||||||
# WHEN : I check the authorisation
|
|
||||||
is_valid = check_auth(['aaaaa', self.password])
|
|
||||||
|
|
||||||
# THEN:
|
|
||||||
assert is_valid is True
|
|
||||||
|
|
||||||
def test_auth_falure(self):
|
|
||||||
"""
|
|
||||||
Test the check_auth method with a match
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: a known user
|
|
||||||
Settings().setValue('api/user id', 'superfly')
|
|
||||||
Settings().setValue('api/password', 'lamas')
|
|
||||||
|
|
||||||
# WHEN : I check the authorisation
|
|
||||||
is_valid = check_auth(['aaaaa', 'monkey123'])
|
|
||||||
|
|
||||||
# THEN:
|
|
||||||
assert is_valid is False
|
|
||||||
|
|
||||||
def test_requires_auth_disabled(self):
|
|
||||||
"""
|
|
||||||
Test the requires_auth wrapper with disabled security
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: A disabled security
|
|
||||||
Settings().setValue('api/authentication enabled', False)
|
|
||||||
|
|
||||||
# WHEN: I call the function
|
|
||||||
wrapped_function = requires_auth(func)
|
|
||||||
value = wrapped_function()
|
|
||||||
|
|
||||||
# THEN: the result will be as expected
|
|
||||||
assert value == 'called'
|
|
||||||
|
|
||||||
def test_requires_auth_enabled(self):
|
|
||||||
"""
|
|
||||||
Test the requires_auth wrapper with enabled security
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: A disabled security
|
|
||||||
Settings().setValue('api/authentication enabled', True)
|
|
||||||
|
|
||||||
# WHEN: I call the function
|
|
||||||
wrapped_function = requires_auth(func)
|
|
||||||
req = MagicMock()
|
|
||||||
value = wrapped_function(req)
|
|
||||||
|
|
||||||
# THEN: the result will be as expected
|
|
||||||
assert str(value) == str(authenticate())
|
|
||||||
|
|
||||||
def test_requires_auth_enabled_auth_error(self):
|
|
||||||
"""
|
|
||||||
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: A enabled security
|
|
||||||
Settings().setValue('api/authentication enabled', True)
|
|
||||||
|
|
||||||
# WHEN: I call the function with the wrong password
|
|
||||||
wrapped_function = requires_auth(func)
|
|
||||||
req = MagicMock()
|
|
||||||
req.authorization = ['Basic', 'cccccccc']
|
|
||||||
value = wrapped_function(req)
|
|
||||||
|
|
||||||
# THEN: the result will be as expected - try again
|
|
||||||
assert str(value) == str(authenticate())
|
|
||||||
|
|
||||||
def test_requires_auth_enabled_auth(self):
|
|
||||||
"""
|
|
||||||
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: An enabled security and a known user
|
|
||||||
Settings().setValue('api/authentication enabled', True)
|
|
||||||
Settings().setValue('api/user id', 'superfly')
|
|
||||||
Settings().setValue('api/password', 'lamas')
|
|
||||||
|
|
||||||
# WHEN: I call the function with the wrong password
|
|
||||||
wrapped_function = requires_auth(func)
|
|
||||||
req = MagicMock()
|
|
||||||
req.authorization = ['Basic', self.password]
|
|
||||||
value = wrapped_function(req)
|
|
||||||
|
|
||||||
# THEN: the result will be as expected - try again
|
|
||||||
assert str(value) == 'called'
|
|
||||||
|
|
||||||
def test_requires_auth_missing_credentials(self):
|
|
||||||
"""
|
|
||||||
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: An enabled security and a known user
|
|
||||||
Settings().setValue('api/authentication enabled', True)
|
|
||||||
Settings().setValue('api/user id', 'superfly')
|
|
||||||
Settings().setValue('api/password', 'lamas')
|
|
||||||
|
|
||||||
# WHEN: I call the function with no password
|
|
||||||
wrapped_function = requires_auth(func)
|
|
||||||
value = wrapped_function(0)
|
|
||||||
|
|
||||||
# THEN: the result will be as expected (unauthorized)
|
|
||||||
assert str(value) == str(authenticate())
|
|
||||||
|
|
||||||
|
|
||||||
def func(field=None):
|
|
||||||
return 'called'
|
|
59
tests/functional/openlp_core/api/http_server/test_http.py
Normal file
59
tests/functional/openlp_core/api/http_server/test_http.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# 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, see <https://www.gnu.org/licenses/>. #
|
||||||
|
##########################################################################
|
||||||
|
"""
|
||||||
|
Functional tests to test the Http Server Class.
|
||||||
|
"""
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from openlp.core.api.http.server import HttpServer
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.api.http.server.HttpWorker')
|
||||||
|
@patch('openlp.core.api.http.server.run_thread')
|
||||||
|
def test_server_start(mocked_run_thread, MockHttpWorker, registry):
|
||||||
|
"""
|
||||||
|
Test the starting of the Waitress Server with the disable flag set off
|
||||||
|
"""
|
||||||
|
# GIVEN: A new httpserver
|
||||||
|
# WHEN: I start the server
|
||||||
|
Registry().set_flag('no_web_server', False)
|
||||||
|
HttpServer()
|
||||||
|
|
||||||
|
# THEN: the api environment should have been created
|
||||||
|
assert mocked_run_thread.call_count == 1, 'The qthread should have been called once'
|
||||||
|
assert MockHttpWorker.call_count == 1, 'The http thread should have been called once'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.api.http.server.HttpWorker')
|
||||||
|
@patch('openlp.core.api.http.server.run_thread')
|
||||||
|
def test_server_start_not_required(mocked_run_thread, MockHttpWorker, registry):
|
||||||
|
"""
|
||||||
|
Test the starting of the Waitress Server with the disable flag set off
|
||||||
|
"""
|
||||||
|
# GIVEN: A new httpserver
|
||||||
|
# WHEN: I start the server
|
||||||
|
Registry().set_flag('no_web_server', True)
|
||||||
|
HttpServer()
|
||||||
|
|
||||||
|
# THEN: the api environment should have been created
|
||||||
|
assert mocked_run_thread.call_count == 0, 'The qthread should not have have been called'
|
||||||
|
assert MockHttpWorker.call_count == 0, 'The http thread should not have been called'
|
154
tests/functional/openlp_core/api/http_server/test_init.py
Normal file
154
tests/functional/openlp_core/api/http_server/test_init.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# 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, see <https://www.gnu.org/licenses/>. #
|
||||||
|
##########################################################################
|
||||||
|
"""
|
||||||
|
Functional tests to test the Http init.
|
||||||
|
"""
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from openlp.core.api.http import authenticate, check_auth, requires_auth
|
||||||
|
|
||||||
|
|
||||||
|
password = 'c3VwZXJmbHk6bGFtYXM='
|
||||||
|
|
||||||
|
|
||||||
|
def test_auth(settings):
|
||||||
|
"""
|
||||||
|
Test the check_auth method with a match
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: a known user
|
||||||
|
settings.setValue('api/user id', "superfly")
|
||||||
|
settings.setValue('api/password', "lamas")
|
||||||
|
|
||||||
|
# WHEN : I check the authorisation
|
||||||
|
is_valid = check_auth(['aaaaa', password])
|
||||||
|
|
||||||
|
# THEN:
|
||||||
|
assert is_valid is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_auth_falure(settings):
|
||||||
|
"""
|
||||||
|
Test the check_auth method with a match
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: a known user
|
||||||
|
settings.setValue('api/user id', 'superfly')
|
||||||
|
settings.setValue('api/password', 'lamas')
|
||||||
|
|
||||||
|
# WHEN : I check the authorisation
|
||||||
|
is_valid = check_auth(['aaaaa', 'monkey123'])
|
||||||
|
|
||||||
|
# THEN:
|
||||||
|
assert is_valid is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_requires_auth_disabled(settings):
|
||||||
|
"""
|
||||||
|
Test the requires_auth wrapper with disabled security
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: A disabled security
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
|
||||||
|
# WHEN: I call the function
|
||||||
|
wrapped_function = requires_auth(func)
|
||||||
|
value = wrapped_function()
|
||||||
|
|
||||||
|
# THEN: the result will be as expected
|
||||||
|
assert value == 'called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_requires_auth_enabled(settings):
|
||||||
|
"""
|
||||||
|
Test the requires_auth wrapper with enabled security
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: A disabled security
|
||||||
|
settings.setValue('api/authentication enabled', True)
|
||||||
|
|
||||||
|
# WHEN: I call the function
|
||||||
|
wrapped_function = requires_auth(func)
|
||||||
|
req = MagicMock()
|
||||||
|
value = wrapped_function(req)
|
||||||
|
|
||||||
|
# THEN: the result will be as expected
|
||||||
|
assert str(value) == str(authenticate())
|
||||||
|
|
||||||
|
|
||||||
|
def test_requires_auth_enabled_auth_error(settings):
|
||||||
|
"""
|
||||||
|
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: A enabled security
|
||||||
|
settings.setValue('api/authentication enabled', True)
|
||||||
|
|
||||||
|
# WHEN: I call the function with the wrong password
|
||||||
|
wrapped_function = requires_auth(func)
|
||||||
|
req = MagicMock()
|
||||||
|
req.authorization = ['Basic', 'cccccccc']
|
||||||
|
value = wrapped_function(req)
|
||||||
|
|
||||||
|
# THEN: the result will be as expected - try again
|
||||||
|
assert str(value) == str(authenticate())
|
||||||
|
|
||||||
|
|
||||||
|
def test_requires_auth_enabled_auth(settings):
|
||||||
|
"""
|
||||||
|
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: An enabled security and a known user
|
||||||
|
settings.setValue('api/authentication enabled', True)
|
||||||
|
settings.setValue('api/user id', 'superfly')
|
||||||
|
settings.setValue('api/password', 'lamas')
|
||||||
|
|
||||||
|
# WHEN: I call the function with the wrong password
|
||||||
|
wrapped_function = requires_auth(func)
|
||||||
|
req = MagicMock()
|
||||||
|
req.authorization = ['Basic', password]
|
||||||
|
value = wrapped_function(req)
|
||||||
|
|
||||||
|
# THEN: the result will be as expected - try again
|
||||||
|
assert str(value) == 'called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_requires_auth_missing_credentials(settings):
|
||||||
|
"""
|
||||||
|
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: An enabled security and a known user
|
||||||
|
settings.setValue('api/authentication enabled', True)
|
||||||
|
settings.setValue('api/user id', 'superfly')
|
||||||
|
settings.setValue('api/password', 'lamas')
|
||||||
|
|
||||||
|
# WHEN: I call the function with no password
|
||||||
|
wrapped_function = requires_auth(func)
|
||||||
|
value = wrapped_function(0)
|
||||||
|
|
||||||
|
# THEN: the result will be as expected (unauthorized)
|
||||||
|
assert str(value) == str(authenticate())
|
||||||
|
|
||||||
|
|
||||||
|
def func(field=None):
|
||||||
|
return 'called'
|
@ -21,101 +21,75 @@
|
|||||||
"""
|
"""
|
||||||
This module contains tests for the lib submodule of the Remotes plugin.
|
This module contains tests for the lib submodule of the Remotes plugin.
|
||||||
"""
|
"""
|
||||||
|
import pytest
|
||||||
import re
|
import re
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
from openlp.core.api.tab import ApiTab
|
from openlp.core.api.tab import ApiTab
|
||||||
from openlp.core.common import get_network_interfaces
|
from openlp.core.common import get_network_interfaces
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
__default_settings__ = {
|
|
||||||
'api/twelve hour': True,
|
|
||||||
'api/port': 4316,
|
|
||||||
'api/user id': 'openlp',
|
|
||||||
'api/password': 'password',
|
|
||||||
'api/authentication enabled': False,
|
|
||||||
'api/ip address': '0.0.0.0',
|
|
||||||
'api/thumbnails': True,
|
|
||||||
'remotes/download version': '0000_00_00'
|
|
||||||
}
|
|
||||||
ZERO_URL = '0.0.0.0'
|
ZERO_URL = '0.0.0.0'
|
||||||
|
|
||||||
|
|
||||||
class TestApiTab(TestCase, TestMixin):
|
@pytest.yield_fixture
|
||||||
|
def api_tab(settings):
|
||||||
|
Registry().set_flag('website_version', '00-00-0000')
|
||||||
|
parent = QtWidgets.QMainWindow()
|
||||||
|
form = ApiTab(parent)
|
||||||
|
yield form
|
||||||
|
del parent
|
||||||
|
del form
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_ip_address_default(api_tab):
|
||||||
"""
|
"""
|
||||||
Test the functions in the :mod:`lib` module.
|
Test the get_ip_address function with ZERO_URL
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
# GIVEN: list of local IP addresses for this machine
|
||||||
"""
|
ip_addresses = []
|
||||||
Create the UI
|
interfaces = get_network_interfaces()
|
||||||
"""
|
for _, interface in interfaces.items():
|
||||||
self.setup_application()
|
ip_addresses.append(interface['ip'])
|
||||||
self.build_settings()
|
|
||||||
Settings().extend_default_settings(__default_settings__)
|
|
||||||
self.parent = QtWidgets.QMainWindow()
|
|
||||||
Registry().create()
|
|
||||||
Registry().set_flag('website_version', '00-00-0000')
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
self.form = ApiTab(self.parent)
|
|
||||||
self.interfaces = get_network_interfaces()
|
|
||||||
|
|
||||||
def tearDown(self):
|
# WHEN: the default ip address is given
|
||||||
"""
|
ip_address = api_tab.get_ip_address(ZERO_URL)
|
||||||
Delete all the C++ objects at the end so that we don't have a segfault
|
|
||||||
"""
|
|
||||||
del self.parent
|
|
||||||
del self.form
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
def test_get_ip_address_default(self):
|
# THEN: the default ip address will be returned
|
||||||
"""
|
assert re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), \
|
||||||
Test the get_ip_address function with ZERO_URL
|
'The return value should be a valid ip address'
|
||||||
"""
|
assert ip_address in ip_addresses, 'The return address should be in the list of local IP addresses'
|
||||||
# GIVEN: list of local IP addresses for this machine
|
|
||||||
ip_addresses = []
|
|
||||||
for _, interface in self.interfaces.items():
|
|
||||||
ip_addresses.append(interface['ip'])
|
|
||||||
|
|
||||||
# WHEN: the default ip address is given
|
|
||||||
ip_address = self.form.get_ip_address(ZERO_URL)
|
|
||||||
|
|
||||||
# THEN: the default ip address will be returned
|
def test_get_ip_address_with_ip(api_tab):
|
||||||
assert re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), \
|
"""
|
||||||
'The return value should be a valid ip address'
|
Test the get_ip_address function with given ip address
|
||||||
assert ip_address in ip_addresses, 'The return address should be in the list of local IP addresses'
|
"""
|
||||||
|
# GIVEN: An ip address
|
||||||
|
given_ip = '192.168.1.1'
|
||||||
|
|
||||||
def test_get_ip_address_with_ip(self):
|
# WHEN: the default ip address is given
|
||||||
"""
|
ip_address = api_tab.get_ip_address(given_ip)
|
||||||
Test the get_ip_address function with given ip address
|
|
||||||
"""
|
|
||||||
# GIVEN: An ip address
|
|
||||||
given_ip = '192.168.1.1'
|
|
||||||
|
|
||||||
# WHEN: the default ip address is given
|
# THEN: the default ip address will be returned
|
||||||
ip_address = self.form.get_ip_address(given_ip)
|
assert ip_address == given_ip, 'The return value should be %s' % given_ip
|
||||||
|
|
||||||
# THEN: the default ip address will be returned
|
|
||||||
assert ip_address == given_ip, 'The return value should be %s' % given_ip
|
|
||||||
|
|
||||||
def test_set_urls(self):
|
def test_set_urls(api_tab):
|
||||||
"""
|
"""
|
||||||
Test the set_url function to generate correct url links
|
Test the set_url function to generate correct url links
|
||||||
"""
|
"""
|
||||||
# GIVEN: An ip address
|
# GIVEN: An ip address
|
||||||
self.form.address_edit.setText('192.168.1.1')
|
api_tab.address_edit.setText('192.168.1.1')
|
||||||
# WHEN: the urls are generated
|
# WHEN: the urls are generated
|
||||||
self.form.set_urls()
|
api_tab.set_urls()
|
||||||
# THEN: the following links are returned
|
# THEN: the following links are returned
|
||||||
assert self.form.remote_url.text() == "<a href=\"http://192.168.1.1:4316/\">http://192.168.1.1:4316/</a>", \
|
assert api_tab.remote_url.text() == "<a href=\"http://192.168.1.1:4316/\">http://192.168.1.1:4316/</a>", \
|
||||||
'The return value should be a fully formed link'
|
'The return value should be a fully formed link'
|
||||||
assert self.form.stage_url.text() == \
|
assert api_tab.stage_url.text() == \
|
||||||
"<a href=\"http://192.168.1.1:4316/stage\">http://192.168.1.1:4316/stage</a>", \
|
"<a href=\"http://192.168.1.1:4316/stage\">http://192.168.1.1:4316/stage</a>", \
|
||||||
'The return value should be a fully formed stage link'
|
'The return value should be a fully formed stage link'
|
||||||
assert self.form.live_url.text() == \
|
assert api_tab.live_url.text() == \
|
||||||
"<a href=\"http://192.168.1.1:4316/main\">http://192.168.1.1:4316/main</a>", \
|
"<a href=\"http://192.168.1.1:4316/main\">http://192.168.1.1:4316/main</a>", \
|
||||||
'The return value should be a fully formed main link'
|
'The return value should be a fully formed main link'
|
||||||
|
@ -21,122 +21,97 @@
|
|||||||
"""
|
"""
|
||||||
Functional tests to test the Http Server Class.
|
Functional tests to test the Http Server Class.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from openlp.core.api.poll import Poller
|
from openlp.core.api.poll import Poller
|
||||||
from openlp.core.api.websockets import WebSocketServer
|
from openlp.core.api.websockets import WebSocketServer
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
__default_settings__ = {
|
@pytest.yield_fixture
|
||||||
'api/twelve hour': True,
|
def poller(registry):
|
||||||
'api/port': 4316,
|
poll = Poller()
|
||||||
'api/user id': 'openlp',
|
yield poll
|
||||||
'api/password': 'password',
|
|
||||||
'api/authentication enabled': False,
|
|
||||||
'api/ip address': '0.0.0.0',
|
|
||||||
'api/thumbnails': True,
|
|
||||||
'songs/chord notation': True
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestWSServer(TestCase, TestMixin):
|
@patch('openlp.core.api.websockets.WebSocketWorker')
|
||||||
|
@patch('openlp.core.api.websockets.run_thread')
|
||||||
|
def test_serverstart(mocked_run_thread, MockWebSocketWorker, registry):
|
||||||
"""
|
"""
|
||||||
A test suite to test starting the websocket server
|
Test the starting of the WebSockets Server with the disabled flag set on
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
# GIVEN: A new httpserver
|
||||||
"""
|
# WHEN: I start the server
|
||||||
Create the UI
|
Registry().set_flag('no_web_server', False)
|
||||||
"""
|
WebSocketServer()
|
||||||
self.build_settings()
|
|
||||||
Settings().extend_default_settings(__default_settings__)
|
|
||||||
Registry().create()
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
self.poll = Poller()
|
|
||||||
|
|
||||||
def tearDown(self):
|
# THEN: the api environment should have been created
|
||||||
"""
|
assert mocked_run_thread.call_count == 1, 'The qthread should have been called once'
|
||||||
Delete all the C++ objects at the end so that we don't have a segfault
|
assert MockWebSocketWorker.call_count == 1, 'The http thread should have been called once'
|
||||||
"""
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
@patch('openlp.core.api.websockets.WebSocketWorker')
|
|
||||||
@patch('openlp.core.api.websockets.run_thread')
|
|
||||||
def test_serverstart(self, mocked_run_thread, MockWebSocketWorker):
|
|
||||||
"""
|
|
||||||
Test the starting of the WebSockets Server with the disabled flag set on
|
|
||||||
"""
|
|
||||||
# GIVEN: A new httpserver
|
|
||||||
# WHEN: I start the server
|
|
||||||
Registry().set_flag('no_web_server', False)
|
|
||||||
WebSocketServer()
|
|
||||||
|
|
||||||
# THEN: the api environment should have been created
|
@patch('openlp.core.api.websockets.WebSocketWorker')
|
||||||
assert mocked_run_thread.call_count == 1, 'The qthread should have been called once'
|
@patch('openlp.core.api.websockets.run_thread')
|
||||||
assert MockWebSocketWorker.call_count == 1, 'The http thread should have been called once'
|
def test_serverstart_not_required(mocked_run_thread, MockWebSocketWorker, registry):
|
||||||
|
"""
|
||||||
|
Test the starting of the WebSockets Server with the disabled flag set off
|
||||||
|
"""
|
||||||
|
# GIVEN: A new httpserver and the server is not required
|
||||||
|
# WHEN: I start the server
|
||||||
|
Registry().set_flag('no_web_server', True)
|
||||||
|
WebSocketServer()
|
||||||
|
|
||||||
@patch('openlp.core.api.websockets.WebSocketWorker')
|
# THEN: the api environment should have been created
|
||||||
@patch('openlp.core.api.websockets.run_thread')
|
assert mocked_run_thread.call_count == 0, 'The qthread should not have been called'
|
||||||
def test_serverstart_not_required(self, mocked_run_thread, MockWebSocketWorker):
|
assert MockWebSocketWorker.call_count == 0, 'The http thread should not have been called'
|
||||||
"""
|
|
||||||
Test the starting of the WebSockets Server with the disabled flag set off
|
|
||||||
"""
|
|
||||||
# GIVEN: A new httpserver and the server is not required
|
|
||||||
# WHEN: I start the server
|
|
||||||
Registry().set_flag('no_web_server', True)
|
|
||||||
WebSocketServer()
|
|
||||||
|
|
||||||
# THEN: the api environment should have been created
|
|
||||||
assert mocked_run_thread.call_count == 0, 'The qthread should not have been called'
|
|
||||||
assert MockWebSocketWorker.call_count == 0, 'The http thread should not have been called'
|
|
||||||
|
|
||||||
def test_main_poll(self):
|
def test_main_poll(poller):
|
||||||
"""
|
"""
|
||||||
Test the main_poll function returns the correct JSON
|
Test the main_poll function returns the correct JSON
|
||||||
"""
|
"""
|
||||||
# WHEN: the live controller has 5 slides
|
# WHEN: the live controller has 5 slides
|
||||||
mocked_live_controller = MagicMock()
|
mocked_live_controller = MagicMock()
|
||||||
mocked_live_controller.slide_count = 5
|
mocked_live_controller.slide_count = 5
|
||||||
Registry().register('live_controller', mocked_live_controller)
|
Registry().register('live_controller', mocked_live_controller)
|
||||||
# THEN: the live json should be generated
|
# THEN: the live json should be generated
|
||||||
main_json = self.poll.main_poll()
|
main_json = poller.main_poll()
|
||||||
assert b'{"results": {"slide_count": 5}}' == main_json, 'The return value should match the defined json'
|
assert b'{"results": {"slide_count": 5}}' == main_json, 'The return value should match the defined json'
|
||||||
|
|
||||||
def test_poll(self):
|
|
||||||
"""
|
def test_poll(poller, settings):
|
||||||
Test the poll function returns the correct JSON
|
"""
|
||||||
"""
|
Test the poll function returns the correct JSON
|
||||||
# GIVEN: the system is configured with a set of data
|
"""
|
||||||
mocked_service_manager = MagicMock()
|
# GIVEN: the system is configured with a set of data
|
||||||
mocked_service_manager.service_id = 21
|
mocked_service_manager = MagicMock()
|
||||||
mocked_live_controller = MagicMock()
|
mocked_service_manager.service_id = 21
|
||||||
mocked_live_controller.selected_row = 5
|
mocked_live_controller = MagicMock()
|
||||||
mocked_live_controller.service_item = MagicMock()
|
mocked_live_controller.selected_row = 5
|
||||||
mocked_live_controller.service_item.unique_identifier = '23-34-45'
|
mocked_live_controller.service_item = MagicMock()
|
||||||
mocked_live_controller.blank_screen.isChecked.return_value = True
|
mocked_live_controller.service_item.unique_identifier = '23-34-45'
|
||||||
mocked_live_controller.theme_screen.isChecked.return_value = False
|
mocked_live_controller.blank_screen.isChecked.return_value = True
|
||||||
mocked_live_controller.desktop_screen.isChecked.return_value = False
|
mocked_live_controller.theme_screen.isChecked.return_value = False
|
||||||
Registry().register('live_controller', mocked_live_controller)
|
mocked_live_controller.desktop_screen.isChecked.return_value = False
|
||||||
Registry().register('service_manager', mocked_service_manager)
|
Registry().register('live_controller', mocked_live_controller)
|
||||||
# WHEN: The poller polls
|
Registry().register('service_manager', mocked_service_manager)
|
||||||
with patch.object(self.poll, 'is_stage_active') as mocked_is_stage_active, \
|
# WHEN: The poller polls
|
||||||
patch.object(self.poll, 'is_live_active') as mocked_is_live_active, \
|
with patch.object(poller, 'is_stage_active') as mocked_is_stage_active, \
|
||||||
patch.object(self.poll, 'is_chords_active') as mocked_is_chords_active:
|
patch.object(poller, 'is_live_active') as mocked_is_live_active, \
|
||||||
mocked_is_stage_active.return_value = True
|
patch.object(poller, 'is_chords_active') as mocked_is_chords_active:
|
||||||
mocked_is_live_active.return_value = True
|
mocked_is_stage_active.return_value = True
|
||||||
mocked_is_chords_active.return_value = True
|
mocked_is_live_active.return_value = True
|
||||||
poll_json = self.poll.poll()
|
mocked_is_chords_active.return_value = True
|
||||||
# THEN: the live json should be generated and match expected results
|
poll_json = poller.poll()
|
||||||
assert poll_json['results']['blank'] is True, 'The blank return value should be True'
|
# THEN: the live json should be generated and match expected results
|
||||||
assert poll_json['results']['theme'] is False, 'The theme return value should be False'
|
assert poll_json['results']['blank'] is True, 'The blank return value should be True'
|
||||||
assert poll_json['results']['display'] is False, 'The display return value should be False'
|
assert poll_json['results']['theme'] is False, 'The theme return value should be False'
|
||||||
assert poll_json['results']['isSecure'] is False, 'The isSecure return value should be False'
|
assert poll_json['results']['display'] is False, 'The display return value should be False'
|
||||||
assert poll_json['results']['isAuthorised'] is False, 'The isAuthorised return value should be False'
|
assert poll_json['results']['isSecure'] is False, 'The isSecure return value should be False'
|
||||||
assert poll_json['results']['twelve'] is True, 'The twelve return value should be True'
|
assert poll_json['results']['isAuthorised'] is False, 'The isAuthorised return value should be False'
|
||||||
assert poll_json['results']['version'] == 3, 'The version return value should be 3'
|
assert poll_json['results']['twelve'] is True, 'The twelve return value should be True'
|
||||||
assert poll_json['results']['slide'] == 5, 'The slide return value should be 5'
|
assert poll_json['results']['version'] == 3, 'The version return value should be 3'
|
||||||
assert poll_json['results']['service'] == 21, 'The version return value should be 21'
|
assert poll_json['results']['slide'] == 5, 'The slide return value should be 5'
|
||||||
assert poll_json['results']['item'] == '23-34-45', 'The item return value should match 23-34-45'
|
assert poll_json['results']['service'] == 21, 'The version return value should be 21'
|
||||||
|
assert poll_json['results']['item'] == '23-34-45', 'The item return value should match 23-34-45'
|
||||||
|
@ -1,8 +1,27 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# 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, see <https://www.gnu.org/licenses/>. #
|
||||||
|
##########################################################################
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
|
|
||||||
|
|
||||||
def test_retrieve_live_item(flask_client):
|
def test_retrieve_live_item(flask_client):
|
||||||
@ -11,11 +30,10 @@ def test_retrieve_live_item(flask_client):
|
|||||||
assert len(res) == 0
|
assert len(res) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_controller_set_requires_login(flask_client):
|
def test_controller_set_requires_login(settings, flask_client):
|
||||||
pytest.skip('Need to figure out how to patch settings for one test only')
|
settings.setValue('api/authentication enabled', True)
|
||||||
# Settings().setValue('api/authentication enabled', True)
|
|
||||||
res = flask_client.post('/api/v2/controller/show', json=dict())
|
res = flask_client.post('/api/v2/controller/show', json=dict())
|
||||||
Settings().setValue('api/authentication enabled', False)
|
settings.setValue('api/authentication enabled', False)
|
||||||
assert res.status_code == 401
|
assert res.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
@ -33,9 +51,9 @@ def test_controller_set_calls_live_controller(flask_client, settings):
|
|||||||
|
|
||||||
|
|
||||||
def test_controller_direction_requires_login(flask_client, settings):
|
def test_controller_direction_requires_login(flask_client, settings):
|
||||||
Settings().setValue('api/authentication enabled', True)
|
settings.setValue('api/authentication enabled', True)
|
||||||
res = flask_client.post('/api/v2/controller/progress', json=dict())
|
res = flask_client.post('/api/v2/controller/progress', json=dict())
|
||||||
Settings().setValue('api/authentication enabled', False)
|
settings.setValue('api/authentication enabled', False)
|
||||||
assert res.status_code == 401
|
assert res.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,24 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# 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, see <https://www.gnu.org/licenses/>. #
|
||||||
|
##########################################################################
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.state import State
|
from openlp.core.state import State
|
||||||
from openlp.core.lib.plugin import PluginStatus, StringContent
|
from openlp.core.lib.plugin import PluginStatus, StringContent
|
||||||
|
|
||||||
@ -28,7 +47,7 @@ def test_plugins_returns_list(flask_client):
|
|||||||
|
|
||||||
|
|
||||||
def test_system_information(flask_client, settings):
|
def test_system_information(flask_client, settings):
|
||||||
Settings().setValue('api/authentication enabled', False)
|
settings.setValue('api/authentication enabled', False)
|
||||||
res = flask_client.get('/api/v2/core/system').get_json()
|
res = flask_client.get('/api/v2/core/system').get_json()
|
||||||
assert res['websocket_port'] > 0
|
assert res['websocket_port'] > 0
|
||||||
assert not res['login_required']
|
assert not res['login_required']
|
||||||
@ -78,9 +97,9 @@ def test_retrieving_image(flask_client):
|
|||||||
|
|
||||||
|
|
||||||
def test_toggle_display_requires_login(flask_client, settings):
|
def test_toggle_display_requires_login(flask_client, settings):
|
||||||
Settings().setValue('api/authentication enabled', True)
|
settings.setValue('api/authentication enabled', True)
|
||||||
res = flask_client.post('/api/v2/core/display')
|
res = flask_client.post('/api/v2/core/display')
|
||||||
Settings().setValue('api/authentication enabled', False)
|
settings.setValue('api/authentication enabled', False)
|
||||||
assert res.status_code == 401
|
assert res.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,20 +1,42 @@
|
|||||||
import pytest
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# 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, see <https://www.gnu.org/licenses/>. #
|
||||||
|
##########################################################################
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
|
|
||||||
|
|
||||||
def test_retrieve_service_items(flask_client, settings):
|
def test_retrieve_service_items(flask_client, settings):
|
||||||
pytest.skip()
|
mocked_live_controller = MagicMock()
|
||||||
|
mocked_live_controller.service_item = MagicMock()
|
||||||
|
fake_service_manager = MagicMock()
|
||||||
|
Registry().register('service_manager', fake_service_manager)
|
||||||
|
Registry().register('live_controller', mocked_live_controller)
|
||||||
res = flask_client.get('/api/v2/service/items').get_json()
|
res = flask_client.get('/api/v2/service/items').get_json()
|
||||||
assert len(res) == 0
|
assert len(res) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_service_set_requires_login(flask_client, settings):
|
def test_service_set_requires_login(flask_client, settings):
|
||||||
Settings().setValue('api/authentication enabled', True)
|
settings.setValue('api/authentication enabled', True)
|
||||||
res = flask_client.post('/api/v2/service/show', json=dict())
|
res = flask_client.post('/api/v2/service/show', json=dict())
|
||||||
Settings().setValue('api/authentication enabled', False)
|
settings.setValue('api/authentication enabled', False)
|
||||||
assert res.status_code == 401
|
assert res.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
@ -32,9 +54,9 @@ def test_service_set_calls_service_manager(flask_client, settings):
|
|||||||
|
|
||||||
|
|
||||||
def test_service_direction_requires_login(flask_client, settings):
|
def test_service_direction_requires_login(flask_client, settings):
|
||||||
Settings().setValue('api/authentication enabled', True)
|
settings.setValue('api/authentication enabled', True)
|
||||||
res = flask_client.post('/api/v2/service/progress', json=dict())
|
res = flask_client.post('/api/v2/service/progress', json=dict())
|
||||||
Settings().setValue('api/authentication enabled', False)
|
settings.setValue('api/authentication enabled', False)
|
||||||
assert res.status_code == 401
|
assert res.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,20 +21,25 @@
|
|||||||
"""
|
"""
|
||||||
Package to test the openlp.core.common.actions package.
|
Package to test the openlp.core.common.actions package.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
import pytest
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common.actions import ActionList, CategoryActionList
|
from openlp.core.common.actions import ActionList, CategoryActionList
|
||||||
from openlp.core.common.settings import Settings
|
from openlp.core.common.registry import Registry
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
MOCK_ACTION1 = MagicMock(**{'text.return_value': 'first'})
|
MOCK_ACTION1 = MagicMock(**{'text.return_value': 'first'})
|
||||||
MOCK_ACTION2 = MagicMock(**{'text.return_value': 'second'})
|
MOCK_ACTION2 = MagicMock(**{'text.return_value': 'second'})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.yield_fixture
|
||||||
|
def action_list(settings):
|
||||||
|
act_list = ActionList.get_instance()
|
||||||
|
yield act_list
|
||||||
|
|
||||||
|
|
||||||
def test_action_list_contains():
|
def test_action_list_contains():
|
||||||
"""
|
"""
|
||||||
Test the __contains__() method
|
Test the __contains__() method
|
||||||
@ -151,118 +156,98 @@ def test_action_list_remove():
|
|||||||
assert MOCK_ACTION1 not in category_list
|
assert MOCK_ACTION1 not in category_list
|
||||||
|
|
||||||
|
|
||||||
class TestActionList(TestCase, TestMixin):
|
def test_add_action_same_parent(action_list):
|
||||||
"""
|
"""
|
||||||
Test the ActionList class
|
ActionList test - Tests the add_action method. The actions have the same parent, the same shortcuts and both
|
||||||
|
have the QtCore.Qt.WindowShortcut shortcut context set.
|
||||||
"""
|
"""
|
||||||
|
# GIVEN: Two actions with the same shortcuts.
|
||||||
|
parent = QtCore.QObject()
|
||||||
|
action1 = QtWidgets.QAction(parent)
|
||||||
|
action1.setObjectName('action1')
|
||||||
|
action_with_same_shortcuts1 = QtWidgets.QAction(parent)
|
||||||
|
action_with_same_shortcuts1.setObjectName('action_with_same_shortcuts1')
|
||||||
|
# Add default shortcuts to Settings class.
|
||||||
|
default_shortcuts = {
|
||||||
|
'shortcuts/action1': [QtGui.QKeySequence(QtCore.Qt.Key_A), QtGui.QKeySequence(QtCore.Qt.Key_B)],
|
||||||
|
'shortcuts/action_with_same_shortcuts1': [QtGui.QKeySequence(QtCore.Qt.Key_B),
|
||||||
|
QtGui.QKeySequence(QtCore.Qt.Key_A)]
|
||||||
|
}
|
||||||
|
Registry().get('settings').extend_default_settings(default_shortcuts)
|
||||||
|
|
||||||
def setUp(self):
|
# WHEN: Add the two actions to the action list.
|
||||||
"""
|
action_list.add_action(action1, 'example_category')
|
||||||
Prepare the tests
|
action_list.add_action(action_with_same_shortcuts1, 'example_category')
|
||||||
"""
|
# Remove the actions again.
|
||||||
self.setup_application()
|
action_list.remove_action(action1, 'example_category')
|
||||||
self.action_list = ActionList.get_instance()
|
action_list.remove_action(action_with_same_shortcuts1, 'example_category')
|
||||||
self.build_settings()
|
|
||||||
self.settings = Settings()
|
|
||||||
self.settings.beginGroup('shortcuts')
|
|
||||||
|
|
||||||
def tearDown(self):
|
# THEN: As both actions have the same shortcuts, they should be removed from one action.
|
||||||
"""
|
assert len(action1.shortcuts()) == 2, 'The action should have two shortcut assigned.'
|
||||||
Clean up
|
assert len(action_with_same_shortcuts1.shortcuts()) == 0, 'The action should not have a shortcut assigned.'
|
||||||
"""
|
|
||||||
self.settings.endGroup()
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
def test_add_action_same_parent(self):
|
|
||||||
"""
|
|
||||||
ActionList test - Tests the add_action method. The actions have the same parent, the same shortcuts and both
|
|
||||||
have the QtCore.Qt.WindowShortcut shortcut context set.
|
|
||||||
"""
|
|
||||||
# GIVEN: Two actions with the same shortcuts.
|
|
||||||
parent = QtCore.QObject()
|
|
||||||
action1 = QtWidgets.QAction(parent)
|
|
||||||
action1.setObjectName('action1')
|
|
||||||
action_with_same_shortcuts1 = QtWidgets.QAction(parent)
|
|
||||||
action_with_same_shortcuts1.setObjectName('action_with_same_shortcuts1')
|
|
||||||
# Add default shortcuts to Settings class.
|
|
||||||
default_shortcuts = {
|
|
||||||
'shortcuts/action1': [QtGui.QKeySequence(QtCore.Qt.Key_A), QtGui.QKeySequence(QtCore.Qt.Key_B)],
|
|
||||||
'shortcuts/action_with_same_shortcuts1': [QtGui.QKeySequence(QtCore.Qt.Key_B),
|
|
||||||
QtGui.QKeySequence(QtCore.Qt.Key_A)]
|
|
||||||
}
|
|
||||||
Settings.extend_default_settings(default_shortcuts)
|
|
||||||
|
|
||||||
# WHEN: Add the two actions to the action list.
|
def test_add_action_different_parent(action_list):
|
||||||
self.action_list.add_action(action1, 'example_category')
|
"""
|
||||||
self.action_list.add_action(action_with_same_shortcuts1, 'example_category')
|
ActionList test - Tests the add_action method. The actions have the different parent, the same shortcuts and
|
||||||
# Remove the actions again.
|
both have the QtCore.Qt.WindowShortcut shortcut context set.
|
||||||
self.action_list.remove_action(action1, 'example_category')
|
"""
|
||||||
self.action_list.remove_action(action_with_same_shortcuts1, 'example_category')
|
# GIVEN: Two actions with the same shortcuts.
|
||||||
|
parent = QtCore.QObject()
|
||||||
|
action2 = QtWidgets.QAction(parent)
|
||||||
|
action2.setObjectName('action2')
|
||||||
|
second_parent = QtCore.QObject()
|
||||||
|
action_with_same_shortcuts2 = QtWidgets.QAction(second_parent)
|
||||||
|
action_with_same_shortcuts2.setObjectName('action_with_same_shortcuts2')
|
||||||
|
# Add default shortcuts to Settings class.
|
||||||
|
default_shortcuts = {
|
||||||
|
'shortcuts/action2': [QtGui.QKeySequence(QtCore.Qt.Key_C), QtGui.QKeySequence(QtCore.Qt.Key_D)],
|
||||||
|
'shortcuts/action_with_same_shortcuts2': [QtGui.QKeySequence(QtCore.Qt.Key_D),
|
||||||
|
QtGui.QKeySequence(QtCore.Qt.Key_C)]
|
||||||
|
}
|
||||||
|
Registry().get('settings').extend_default_settings(default_shortcuts)
|
||||||
|
|
||||||
# THEN: As both actions have the same shortcuts, they should be removed from one action.
|
# WHEN: Add the two actions to the action list.
|
||||||
assert len(action1.shortcuts()) == 2, 'The action should have two shortcut assigned.'
|
action_list.add_action(action2, 'example_category')
|
||||||
assert len(action_with_same_shortcuts1.shortcuts()) == 0, 'The action should not have a shortcut assigned.'
|
action_list.add_action(action_with_same_shortcuts2, 'example_category')
|
||||||
|
# Remove the actions again.
|
||||||
|
action_list.remove_action(action2, 'example_category')
|
||||||
|
action_list.remove_action(action_with_same_shortcuts2, 'example_category')
|
||||||
|
|
||||||
def test_add_action_different_parent(self):
|
# THEN: As both actions have the same shortcuts, they should be removed from one action.
|
||||||
"""
|
assert len(action2.shortcuts()) == 2, 'The action should have two shortcut assigned.'
|
||||||
ActionList test - Tests the add_action method. The actions have the different parent, the same shortcuts and
|
assert len(action_with_same_shortcuts2.shortcuts()) == 0, 'The action should not have a shortcut assigned.'
|
||||||
both have the QtCore.Qt.WindowShortcut shortcut context set.
|
|
||||||
"""
|
|
||||||
# GIVEN: Two actions with the same shortcuts.
|
|
||||||
parent = QtCore.QObject()
|
|
||||||
action2 = QtWidgets.QAction(parent)
|
|
||||||
action2.setObjectName('action2')
|
|
||||||
second_parent = QtCore.QObject()
|
|
||||||
action_with_same_shortcuts2 = QtWidgets.QAction(second_parent)
|
|
||||||
action_with_same_shortcuts2.setObjectName('action_with_same_shortcuts2')
|
|
||||||
# Add default shortcuts to Settings class.
|
|
||||||
default_shortcuts = {
|
|
||||||
'shortcuts/action2': [QtGui.QKeySequence(QtCore.Qt.Key_C), QtGui.QKeySequence(QtCore.Qt.Key_D)],
|
|
||||||
'shortcuts/action_with_same_shortcuts2': [QtGui.QKeySequence(QtCore.Qt.Key_D),
|
|
||||||
QtGui.QKeySequence(QtCore.Qt.Key_C)]
|
|
||||||
}
|
|
||||||
Settings.extend_default_settings(default_shortcuts)
|
|
||||||
|
|
||||||
# WHEN: Add the two actions to the action list.
|
|
||||||
self.action_list.add_action(action2, 'example_category')
|
|
||||||
self.action_list.add_action(action_with_same_shortcuts2, 'example_category')
|
|
||||||
# Remove the actions again.
|
|
||||||
self.action_list.remove_action(action2, 'example_category')
|
|
||||||
self.action_list.remove_action(action_with_same_shortcuts2, 'example_category')
|
|
||||||
|
|
||||||
# THEN: As both actions have the same shortcuts, they should be removed from one action.
|
def test_add_action_different_context(action_list):
|
||||||
assert len(action2.shortcuts()) == 2, 'The action should have two shortcut assigned.'
|
"""
|
||||||
assert len(action_with_same_shortcuts2.shortcuts()) == 0, 'The action should not have a shortcut assigned.'
|
ActionList test - Tests the add_action method. The actions have the different parent, the same shortcuts and
|
||||||
|
both have the QtCore.Qt.WidgetShortcut shortcut context set.
|
||||||
|
"""
|
||||||
|
# GIVEN: Two actions with the same shortcuts.
|
||||||
|
parent = QtCore.QObject()
|
||||||
|
action3 = QtWidgets.QAction(parent)
|
||||||
|
action3.setObjectName('action3')
|
||||||
|
action3.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
||||||
|
second_parent = QtCore.QObject()
|
||||||
|
action_with_same_shortcuts3 = QtWidgets.QAction(second_parent)
|
||||||
|
action_with_same_shortcuts3.setObjectName('action_with_same_shortcuts3')
|
||||||
|
action_with_same_shortcuts3.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
||||||
|
# Add default shortcuts to Settings class.
|
||||||
|
default_shortcuts = {
|
||||||
|
'shortcuts/action3': [QtGui.QKeySequence(QtCore.Qt.Key_E), QtGui.QKeySequence(QtCore.Qt.Key_F)],
|
||||||
|
'shortcuts/action_with_same_shortcuts3': [QtGui.QKeySequence(QtCore.Qt.Key_E),
|
||||||
|
QtGui.QKeySequence(QtCore.Qt.Key_F)]
|
||||||
|
}
|
||||||
|
Registry().get('settings').extend_default_settings(default_shortcuts)
|
||||||
|
|
||||||
def test_add_action_different_context(self):
|
# WHEN: Add the two actions to the action list.
|
||||||
"""
|
action_list.add_action(action3, 'example_category2')
|
||||||
ActionList test - Tests the add_action method. The actions have the different parent, the same shortcuts and
|
action_list.add_action(action_with_same_shortcuts3, 'example_category2')
|
||||||
both have the QtCore.Qt.WidgetShortcut shortcut context set.
|
# Remove the actions again.
|
||||||
"""
|
action_list.remove_action(action3, 'example_category2')
|
||||||
# GIVEN: Two actions with the same shortcuts.
|
action_list.remove_action(action_with_same_shortcuts3, 'example_category2')
|
||||||
parent = QtCore.QObject()
|
|
||||||
action3 = QtWidgets.QAction(parent)
|
|
||||||
action3.setObjectName('action3')
|
|
||||||
action3.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
|
||||||
second_parent = QtCore.QObject()
|
|
||||||
action_with_same_shortcuts3 = QtWidgets.QAction(second_parent)
|
|
||||||
action_with_same_shortcuts3.setObjectName('action_with_same_shortcuts3')
|
|
||||||
action_with_same_shortcuts3.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
|
||||||
# Add default shortcuts to Settings class.
|
|
||||||
default_shortcuts = {
|
|
||||||
'shortcuts/action3': [QtGui.QKeySequence(QtCore.Qt.Key_E), QtGui.QKeySequence(QtCore.Qt.Key_F)],
|
|
||||||
'shortcuts/action_with_same_shortcuts3': [QtGui.QKeySequence(QtCore.Qt.Key_E),
|
|
||||||
QtGui.QKeySequence(QtCore.Qt.Key_F)]
|
|
||||||
}
|
|
||||||
Settings.extend_default_settings(default_shortcuts)
|
|
||||||
|
|
||||||
# WHEN: Add the two actions to the action list.
|
# THEN: Both action should keep their shortcuts.
|
||||||
self.action_list.add_action(action3, 'example_category2')
|
assert len(action3.shortcuts()) == 2, 'The action should have two shortcut assigned.'
|
||||||
self.action_list.add_action(action_with_same_shortcuts3, 'example_category2')
|
assert len(action_with_same_shortcuts3.shortcuts()) == 2, 'The action should have two shortcuts assigned.'
|
||||||
# Remove the actions again.
|
|
||||||
self.action_list.remove_action(action3, 'example_category2')
|
|
||||||
self.action_list.remove_action(action_with_same_shortcuts3, 'example_category2')
|
|
||||||
|
|
||||||
# THEN: Both action should keep their shortcuts.
|
|
||||||
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.'
|
|
||||||
|
@ -22,304 +22,318 @@
|
|||||||
Functional tests to test the AppLocation class and related methods.
|
Functional tests to test the AppLocation class and related methods.
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase, skipUnless
|
from unittest import skipUnless
|
||||||
from unittest.mock import MagicMock, call, patch
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
from openlp.core.common import Singleton, clean_button_text, de_hump, extension_loader, is_linux, is_macosx, is_win, \
|
from openlp.core.common import Singleton, clean_button_text, de_hump, extension_loader, is_linux, is_macosx, is_win, \
|
||||||
is_64bit_instance, normalize_str, path_to_module, trace_error_handler
|
is_64bit_instance, normalize_str, path_to_module, trace_error_handler
|
||||||
|
|
||||||
|
|
||||||
class TestCommonFunctions(TestCase):
|
def test_extension_loader_no_files_found():
|
||||||
"""
|
"""
|
||||||
A test suite to test out various functions in the openlp.core.common module.
|
Test the `extension_loader` function when no files are found
|
||||||
"""
|
"""
|
||||||
def test_extension_loader_no_files_found(self):
|
# GIVEN: A mocked `Path.glob` method which does not match any files
|
||||||
"""
|
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
||||||
Test the `extension_loader` function when no files are found
|
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
||||||
"""
|
patch.object(Path, 'glob', return_value=[]), \
|
||||||
# GIVEN: A mocked `Path.glob` method which does not match any files
|
patch('openlp.core.common.importlib.import_module') as mocked_import_module:
|
||||||
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
|
||||||
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
|
||||||
patch.object(Path, 'glob', return_value=[]), \
|
|
||||||
patch('openlp.core.common.importlib.import_module') as mocked_import_module:
|
|
||||||
|
|
||||||
# WHEN: Calling `extension_loader`
|
# WHEN: Calling `extension_loader`
|
||||||
extension_loader('glob', ['file2.py', 'file3.py'])
|
extension_loader('glob', ['file2.py', 'file3.py'])
|
||||||
|
|
||||||
# THEN: `extension_loader` should not try to import any files
|
# THEN: `extension_loader` should not try to import any files
|
||||||
assert mocked_import_module.called is False
|
assert mocked_import_module.called is False
|
||||||
|
|
||||||
def test_extension_loader_files_found(self):
|
|
||||||
"""
|
|
||||||
Test the `extension_loader` function when it successfully finds and loads some files
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked `Path.glob` method which returns a list of files
|
|
||||||
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
|
||||||
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
|
||||||
patch.object(Path, 'glob', return_value=[
|
|
||||||
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'),
|
|
||||||
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'),
|
|
||||||
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'),
|
|
||||||
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file4.py')]), \
|
|
||||||
patch('openlp.core.common.importlib.import_module') as mocked_import_module:
|
|
||||||
|
|
||||||
# WHEN: Calling `extension_loader` with a list of files to exclude
|
def test_extension_loader_files_found():
|
||||||
extension_loader('glob', ['file2.py', 'file3.py'])
|
"""
|
||||||
|
Test the `extension_loader` function when it successfully finds and loads some files
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked `Path.glob` method which returns a list of files
|
||||||
|
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
||||||
|
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
||||||
|
patch.object(Path, 'glob', return_value=[
|
||||||
|
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'),
|
||||||
|
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'),
|
||||||
|
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'),
|
||||||
|
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file4.py')]), \
|
||||||
|
patch('openlp.core.common.importlib.import_module') as mocked_import_module:
|
||||||
|
|
||||||
# THEN: `extension_loader` should only try to import the files that are matched by the blob, excluding the
|
# WHEN: Calling `extension_loader` with a list of files to exclude
|
||||||
# files listed in the `excluded_files` argument
|
extension_loader('glob', ['file2.py', 'file3.py'])
|
||||||
mocked_import_module.assert_has_calls([call('openlp.import_dir.file1'),
|
|
||||||
call('openlp.import_dir.file4')])
|
|
||||||
|
|
||||||
def test_extension_loader_import_error(self):
|
# THEN: `extension_loader` should only try to import the files that are matched by the blob, excluding the
|
||||||
"""
|
# files listed in the `excluded_files` argument
|
||||||
Test the `extension_loader` function when `SourceFileLoader` raises a `ImportError`
|
mocked_import_module.assert_has_calls([call('openlp.import_dir.file1'),
|
||||||
"""
|
call('openlp.import_dir.file4')])
|
||||||
# GIVEN: A mocked `import_module` which raises an `ImportError`
|
|
||||||
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
|
||||||
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
|
||||||
patch.object(Path, 'glob', return_value=[
|
|
||||||
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
|
|
||||||
patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \
|
|
||||||
patch('openlp.core.common.log') as mocked_logger:
|
|
||||||
|
|
||||||
# WHEN: Calling `extension_loader`
|
|
||||||
extension_loader('glob')
|
|
||||||
|
|
||||||
# THEN: The `ImportError` should be caught and logged
|
def test_extension_loader_import_error():
|
||||||
assert mocked_logger.exception.called
|
"""
|
||||||
|
Test the `extension_loader` function when `SourceFileLoader` raises a `ImportError`
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked `import_module` which raises an `ImportError`
|
||||||
|
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
||||||
|
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
||||||
|
patch.object(Path, 'glob', return_value=[
|
||||||
|
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
|
||||||
|
patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \
|
||||||
|
patch('openlp.core.common.log') as mocked_logger:
|
||||||
|
|
||||||
def test_extension_loader_os_error(self):
|
# WHEN: Calling `extension_loader`
|
||||||
"""
|
extension_loader('glob')
|
||||||
Test the `extension_loader` function when `import_module` raises a `ImportError`
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked `SourceFileLoader` which raises an `OSError`
|
|
||||||
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
|
||||||
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
|
||||||
patch.object(Path, 'glob', return_value=[
|
|
||||||
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
|
|
||||||
patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \
|
|
||||||
patch('openlp.core.common.log') as mocked_logger:
|
|
||||||
|
|
||||||
# WHEN: Calling `extension_loader`
|
# THEN: The `ImportError` should be caught and logged
|
||||||
extension_loader('glob')
|
assert mocked_logger.exception.called
|
||||||
|
|
||||||
# THEN: The `OSError` should be caught and logged
|
|
||||||
assert mocked_logger.exception.called
|
|
||||||
|
|
||||||
def test_de_hump_conversion(self):
|
def test_extension_loader_os_error():
|
||||||
"""
|
"""
|
||||||
Test the de_hump function with a class name
|
Test the `extension_loader` function when `import_module` raises a `ImportError`
|
||||||
"""
|
"""
|
||||||
# GIVEN: a Class name in Camel Case
|
# GIVEN: A mocked `SourceFileLoader` which raises an `OSError`
|
||||||
string = "MyClass"
|
with patch('openlp.core.common.applocation.AppLocation.get_directory',
|
||||||
|
return_value=Path('/', 'app', 'dir', 'openlp')), \
|
||||||
|
patch.object(Path, 'glob', return_value=[
|
||||||
|
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
|
||||||
|
patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \
|
||||||
|
patch('openlp.core.common.log') as mocked_logger:
|
||||||
|
|
||||||
# WHEN: we call de_hump
|
# WHEN: Calling `extension_loader`
|
||||||
new_string = de_hump(string)
|
extension_loader('glob')
|
||||||
|
|
||||||
# THEN: the new string should be converted to python format
|
# THEN: The `OSError` should be caught and logged
|
||||||
assert new_string == "my_class", 'The class name should have been converted'
|
assert mocked_logger.exception.called
|
||||||
|
|
||||||
def test_de_hump_static(self):
|
|
||||||
"""
|
|
||||||
Test the de_hump function with a python string
|
|
||||||
"""
|
|
||||||
# GIVEN: a Class name in Camel Case
|
|
||||||
string = "my_class"
|
|
||||||
|
|
||||||
# WHEN: we call de_hump
|
def test_de_hump_conversion():
|
||||||
new_string = de_hump(string)
|
"""
|
||||||
|
Test the de_hump function with a class name
|
||||||
|
"""
|
||||||
|
# GIVEN: a Class name in Camel Case
|
||||||
|
string = "MyClass"
|
||||||
|
|
||||||
# THEN: the new string should be converted to python format
|
# WHEN: we call de_hump
|
||||||
assert new_string == "my_class", 'The class name should have been preserved'
|
new_string = de_hump(string)
|
||||||
|
|
||||||
def test_path_to_module(self):
|
# THEN: the new string should be converted to python format
|
||||||
"""
|
assert new_string == "my_class", 'The class name should have been converted'
|
||||||
Test `path_to_module` when supplied with a `Path` object
|
|
||||||
"""
|
|
||||||
# GIVEN: A `Path` object
|
|
||||||
path = Path('core', 'ui', 'media', 'vlcplayer.py')
|
|
||||||
|
|
||||||
# WHEN: Calling path_to_module with the `Path` object
|
|
||||||
result = path_to_module(path)
|
|
||||||
|
|
||||||
# THEN: path_to_module should return the module name
|
def test_de_hump_static():
|
||||||
assert result == 'openlp.core.ui.media.vlcplayer'
|
"""
|
||||||
|
Test the de_hump function with a python string
|
||||||
|
"""
|
||||||
|
# GIVEN: a Class name in Camel Case
|
||||||
|
string = "my_class"
|
||||||
|
|
||||||
def test_trace_error_handler(self):
|
# WHEN: we call de_hump
|
||||||
"""
|
new_string = de_hump(string)
|
||||||
Test the trace_error_handler() method
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects
|
|
||||||
with patch('openlp.core.common.traceback') as mocked_traceback:
|
|
||||||
mocked_traceback.extract_stack.return_value = [('openlp.fake', 56, None, 'trace_error_handler_test')]
|
|
||||||
mocked_logger = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: trace_error_handler() is called
|
# THEN: the new string should be converted to python format
|
||||||
trace_error_handler(mocked_logger)
|
assert new_string == "my_class", 'The class name should have been preserved'
|
||||||
|
|
||||||
# THEN: The mocked_logger.error() method should have been called with the correct parameters
|
|
||||||
mocked_logger.error.assert_called_with(
|
|
||||||
'OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test')
|
|
||||||
|
|
||||||
def test_singleton_metaclass_multiple_init(self):
|
def test_path_to_module():
|
||||||
"""
|
"""
|
||||||
Test that a class using the Singleton Metaclass is only initialised once despite being called several times and
|
Test `path_to_module` when supplied with a `Path` object
|
||||||
that the same instance is returned each time..
|
"""
|
||||||
"""
|
# GIVEN: A `Path` object
|
||||||
# GIVEN: The Singleton Metaclass and a test class using it
|
path = Path('core', 'ui', 'media', 'vlcplayer.py')
|
||||||
class SingletonClass(metaclass=Singleton):
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
with patch.object(SingletonClass, '__init__', return_value=None) as patched_init:
|
# WHEN: Calling path_to_module with the `Path` object
|
||||||
|
result = path_to_module(path)
|
||||||
|
|
||||||
# WHEN: Initialising the class multiple times
|
# THEN: path_to_module should return the module name
|
||||||
inst_1 = SingletonClass()
|
assert result == 'openlp.core.ui.media.vlcplayer'
|
||||||
inst_2 = SingletonClass()
|
|
||||||
|
|
||||||
# THEN: The __init__ method of the SingletonClass should have only been called once, and both returned values
|
|
||||||
# should be the same instance.
|
|
||||||
assert inst_1 is inst_2
|
|
||||||
assert patched_init.call_count == 1
|
|
||||||
|
|
||||||
def test_singleton_metaclass_multiple_classes(self):
|
def test_trace_error_handler():
|
||||||
"""
|
"""
|
||||||
Test that multiple classes using the Singleton Metaclass return the different an appropriate instances.
|
Test the trace_error_handler() method
|
||||||
"""
|
"""
|
||||||
# GIVEN: Two different classes using the Singleton Metaclass
|
# GIVEN: Mocked out objects
|
||||||
class SingletonClass1(metaclass=Singleton):
|
with patch('openlp.core.common.traceback') as mocked_traceback:
|
||||||
def __init__(self):
|
mocked_traceback.extract_stack.return_value = [('openlp.fake', 56, None, 'trace_error_handler_test')]
|
||||||
pass
|
mocked_logger = MagicMock()
|
||||||
|
|
||||||
class SingletonClass2(metaclass=Singleton):
|
# WHEN: trace_error_handler() is called
|
||||||
def __init__(self):
|
trace_error_handler(mocked_logger)
|
||||||
pass
|
|
||||||
|
|
||||||
# WHEN: Initialising both classes
|
# THEN: The mocked_logger.error() method should have been called with the correct parameters
|
||||||
s_c1 = SingletonClass1()
|
mocked_logger.error.assert_called_with(
|
||||||
s_c2 = SingletonClass2()
|
'OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test')
|
||||||
|
|
||||||
# THEN: The instances should be an instance of the appropriate class
|
|
||||||
assert isinstance(s_c1, SingletonClass1)
|
|
||||||
assert isinstance(s_c2, SingletonClass2)
|
|
||||||
|
|
||||||
def test_is_win(self):
|
def test_singleton_metaclass_multiple_init():
|
||||||
"""
|
"""
|
||||||
Test the is_win() function
|
Test that a class using the Singleton Metaclass is only initialised once despite being called several times and
|
||||||
"""
|
that the same instance is returned each time..
|
||||||
# GIVEN: Mocked out objects
|
"""
|
||||||
with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys:
|
# GIVEN: The Singleton Metaclass and a test class using it
|
||||||
|
class SingletonClass(metaclass=Singleton):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
# WHEN: The mocked os.name and sys.platform are set to 'nt' and 'win32' repectivly
|
with patch.object(SingletonClass, '__init__', return_value=None) as patched_init:
|
||||||
mocked_os.name = 'nt'
|
|
||||||
mocked_sys.platform = 'win32'
|
|
||||||
|
|
||||||
# THEN: The three platform functions should perform properly
|
# WHEN: Initialising the class multiple times
|
||||||
assert is_win() is True, 'is_win() should return True'
|
inst_1 = SingletonClass()
|
||||||
assert is_macosx() is False, 'is_macosx() should return False'
|
inst_2 = SingletonClass()
|
||||||
assert is_linux() is False, 'is_linux() should return False'
|
|
||||||
|
|
||||||
def test_is_macosx(self):
|
# THEN: The __init__ method of the SingletonClass should have only been called once, and both returned values
|
||||||
"""
|
# should be the same instance.
|
||||||
Test the is_macosx() function
|
assert inst_1 is inst_2
|
||||||
"""
|
assert patched_init.call_count == 1
|
||||||
# GIVEN: Mocked out objects
|
|
||||||
with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# WHEN: The mocked os.name and sys.platform are set to 'posix' and 'darwin' repectivly
|
|
||||||
mocked_os.name = 'posix'
|
|
||||||
mocked_sys.platform = 'darwin'
|
|
||||||
|
|
||||||
# THEN: The three platform functions should perform properly
|
def test_singleton_metaclass_multiple_classes():
|
||||||
assert is_macosx() is True, 'is_macosx() should return True'
|
"""
|
||||||
assert is_win() is False, 'is_win() should return False'
|
Test that multiple classes using the Singleton Metaclass return the different an appropriate instances.
|
||||||
assert is_linux() is False, 'is_linux() should return False'
|
"""
|
||||||
|
# GIVEN: Two different classes using the Singleton Metaclass
|
||||||
|
class SingletonClass1(metaclass=Singleton):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def test_is_linux(self):
|
class SingletonClass2(metaclass=Singleton):
|
||||||
"""
|
def __init__(self):
|
||||||
Test the is_linux() function
|
pass
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects
|
|
||||||
with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# WHEN: The mocked os.name and sys.platform are set to 'posix' and 'linux3' repectively
|
# WHEN: Initialising both classes
|
||||||
mocked_os.name = 'posix'
|
s_c1 = SingletonClass1()
|
||||||
mocked_sys.platform = 'linux3'
|
s_c2 = SingletonClass2()
|
||||||
|
|
||||||
# THEN: The three platform functions should perform properly
|
# THEN: The instances should be an instance of the appropriate class
|
||||||
assert is_linux() is True, 'is_linux() should return True'
|
assert isinstance(s_c1, SingletonClass1)
|
||||||
assert is_win() is False, 'is_win() should return False'
|
assert isinstance(s_c2, SingletonClass2)
|
||||||
assert is_macosx() is False, 'is_macosx() should return False'
|
|
||||||
|
|
||||||
@skipUnless(is_linux(), 'This can only run on Linux')
|
|
||||||
def test_is_linux_distro(self):
|
|
||||||
"""
|
|
||||||
Test the is_linux() function for a particular Linux distribution
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects
|
|
||||||
with patch('openlp.core.common.os') as mocked_os, \
|
|
||||||
patch('openlp.core.common.sys') as mocked_sys, \
|
|
||||||
patch('openlp.core.common.distro_id') as mocked_distro_id:
|
|
||||||
|
|
||||||
# WHEN: The mocked os.name and sys.platform are set to 'posix' and 'linux3' repectively
|
def test_is_win():
|
||||||
# and the distro is Fedora
|
"""
|
||||||
mocked_os.name = 'posix'
|
Test the is_win() function
|
||||||
mocked_sys.platform = 'linux3'
|
"""
|
||||||
mocked_distro_id.return_value = 'fedora'
|
# GIVEN: Mocked out objects
|
||||||
|
with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys:
|
||||||
|
|
||||||
# THEN: The three platform functions should perform properly
|
# WHEN: The mocked os.name and sys.platform are set to 'nt' and 'win32' repectivly
|
||||||
assert is_linux(distro='fedora') is True, 'is_linux(distro="fedora") should return True'
|
mocked_os.name = 'nt'
|
||||||
assert is_win() is False, 'is_win() should return False'
|
mocked_sys.platform = 'win32'
|
||||||
assert is_macosx() is False, 'is_macosx() should return False'
|
|
||||||
|
|
||||||
def test_is_64bit_instance(self):
|
# THEN: The three platform functions should perform properly
|
||||||
"""
|
assert is_win() is True, 'is_win() should return True'
|
||||||
Test the is_64bit_instance() function
|
assert is_macosx() is False, 'is_macosx() should return False'
|
||||||
"""
|
assert is_linux() is False, 'is_linux() should return False'
|
||||||
# GIVEN: Mocked out objects
|
|
||||||
with patch('openlp.core.common.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# WHEN: The mocked sys.maxsize is set to 32-bit
|
|
||||||
mocked_sys.maxsize = 2**32
|
|
||||||
|
|
||||||
# THEN: The result should be False
|
def test_is_macosx():
|
||||||
assert is_64bit_instance() is False, 'is_64bit_instance() should return False'
|
"""
|
||||||
|
Test the is_macosx() function
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects
|
||||||
|
with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys:
|
||||||
|
|
||||||
def test_normalize_str_leaves_newlines(self):
|
# WHEN: The mocked os.name and sys.platform are set to 'posix' and 'darwin' repectivly
|
||||||
# GIVEN: a string containing newlines
|
mocked_os.name = 'posix'
|
||||||
string = 'something\nelse'
|
mocked_sys.platform = 'darwin'
|
||||||
# WHEN: normalize is called
|
|
||||||
normalized_string = normalize_str(string)
|
|
||||||
# THEN: string is unchanged
|
|
||||||
assert normalized_string == string
|
|
||||||
|
|
||||||
def test_normalize_str_removes_null_byte(self):
|
# THEN: The three platform functions should perform properly
|
||||||
# GIVEN: a string containing a null byte
|
assert is_macosx() is True, 'is_macosx() should return True'
|
||||||
string = 'somet\x00hing'
|
assert is_win() is False, 'is_win() should return False'
|
||||||
# WHEN: normalize is called
|
assert is_linux() is False, 'is_linux() should return False'
|
||||||
normalized_string = normalize_str(string)
|
|
||||||
# THEN: nullbyte is removed
|
|
||||||
assert normalized_string == 'something'
|
|
||||||
|
|
||||||
def test_normalize_str_replaces_crlf_with_lf(self):
|
|
||||||
# GIVEN: a string containing crlf
|
|
||||||
string = 'something\r\nelse'
|
|
||||||
# WHEN: normalize is called
|
|
||||||
normalized_string = normalize_str(string)
|
|
||||||
# THEN: crlf is replaced with lf
|
|
||||||
assert normalized_string == 'something\nelse'
|
|
||||||
|
|
||||||
def test_clean_button_text(self):
|
def test_is_linux():
|
||||||
"""
|
"""
|
||||||
Test the clean_button_text() function.
|
Test the is_linux() function
|
||||||
"""
|
"""
|
||||||
# GIVEN: Button text
|
# GIVEN: Mocked out objects
|
||||||
input_text = '&Next >'
|
with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys:
|
||||||
expected_text = 'Next'
|
|
||||||
|
|
||||||
# WHEN: The button caption is sent through the clean_button_text function
|
# WHEN: The mocked os.name and sys.platform are set to 'posix' and 'linux3' repectively
|
||||||
actual_text = clean_button_text(input_text)
|
mocked_os.name = 'posix'
|
||||||
|
mocked_sys.platform = 'linux3'
|
||||||
|
|
||||||
# THEN: The text should have been cleaned
|
# THEN: The three platform functions should perform properly
|
||||||
assert expected_text == actual_text, 'The text should be clean'
|
assert is_linux() is True, 'is_linux() should return True'
|
||||||
|
assert is_win() is False, 'is_win() should return False'
|
||||||
|
assert is_macosx() is False, 'is_macosx() should return False'
|
||||||
|
|
||||||
|
|
||||||
|
@skipUnless(is_linux(), 'This can only run on Linux')
|
||||||
|
def test_is_linux_distro():
|
||||||
|
"""
|
||||||
|
Test the is_linux() function for a particular Linux distribution
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects
|
||||||
|
with patch('openlp.core.common.os') as mocked_os, \
|
||||||
|
patch('openlp.core.common.sys') as mocked_sys, \
|
||||||
|
patch('openlp.core.common.distro_id') as mocked_distro_id:
|
||||||
|
|
||||||
|
# WHEN: The mocked os.name and sys.platform are set to 'posix' and 'linux3' repectively
|
||||||
|
# and the distro is Fedora
|
||||||
|
mocked_os.name = 'posix'
|
||||||
|
mocked_sys.platform = 'linux3'
|
||||||
|
mocked_distro_id.return_value = 'fedora'
|
||||||
|
|
||||||
|
# THEN: The three platform functions should perform properly
|
||||||
|
assert is_linux(distro='fedora') is True, 'is_linux(distro="fedora") should return True'
|
||||||
|
assert is_win() is False, 'is_win() should return False'
|
||||||
|
assert is_macosx() is False, 'is_macosx() should return False'
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_64bit_instance():
|
||||||
|
"""
|
||||||
|
Test the is_64bit_instance() function
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects
|
||||||
|
with patch('openlp.core.common.sys') as mocked_sys:
|
||||||
|
|
||||||
|
# WHEN: The mocked sys.maxsize is set to 32-bit
|
||||||
|
mocked_sys.maxsize = 2**32
|
||||||
|
|
||||||
|
# THEN: The result should be False
|
||||||
|
assert is_64bit_instance() is False, 'is_64bit_instance() should return False'
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize_str_leaves_newlines():
|
||||||
|
# GIVEN: a string containing newlines
|
||||||
|
string = 'something\nelse'
|
||||||
|
# WHEN: normalize is called
|
||||||
|
normalized_string = normalize_str(string)
|
||||||
|
# THEN: string is unchanged
|
||||||
|
assert normalized_string == string
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize_str_removes_null_byte():
|
||||||
|
# GIVEN: a string containing a null byte
|
||||||
|
string = 'somet\x00hing'
|
||||||
|
# WHEN: normalize is called
|
||||||
|
normalized_string = normalize_str(string)
|
||||||
|
# THEN: nullbyte is removed
|
||||||
|
assert normalized_string == 'something'
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize_str_replaces_crlf_with_lf():
|
||||||
|
# GIVEN: a string containing crlf
|
||||||
|
string = 'something\r\nelse'
|
||||||
|
# WHEN: normalize is called
|
||||||
|
normalized_string = normalize_str(string)
|
||||||
|
# THEN: crlf is replaced with lf
|
||||||
|
assert normalized_string == 'something\nelse'
|
||||||
|
|
||||||
|
|
||||||
|
def test_clean_button_text():
|
||||||
|
"""
|
||||||
|
Test the clean_button_text() function.
|
||||||
|
"""
|
||||||
|
# GIVEN: Button text
|
||||||
|
input_text = '&Next >'
|
||||||
|
expected_text = 'Next'
|
||||||
|
|
||||||
|
# WHEN: The button caption is sent through the clean_button_text function
|
||||||
|
actual_text = clean_button_text(input_text)
|
||||||
|
|
||||||
|
# THEN: The text should have been cleaned
|
||||||
|
assert expected_text == actual_text, 'The text should be clean'
|
||||||
|
@ -23,10 +23,10 @@ Package to test the openlp.core.common.db package.
|
|||||||
"""
|
"""
|
||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
|
import pytest
|
||||||
import shutil
|
import shutil
|
||||||
import time
|
import time
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
@ -35,69 +35,63 @@ from openlp.core.lib.db import get_upgrade_op, init_db
|
|||||||
from tests.utils.constants import TEST_RESOURCES_PATH
|
from tests.utils.constants import TEST_RESOURCES_PATH
|
||||||
|
|
||||||
|
|
||||||
class TestUtilsDBFunctions(TestCase):
|
@pytest.yield_fixture
|
||||||
|
def op():
|
||||||
|
tmp_folder = mkdtemp()
|
||||||
|
db_path = os.path.join(TEST_RESOURCES_PATH, 'songs', 'songs-1.9.7.sqlite')
|
||||||
|
db_tmp_path = os.path.join(tmp_folder, 'songs-1.9.7.sqlite')
|
||||||
|
shutil.copyfile(db_path, db_tmp_path)
|
||||||
|
db_url = 'sqlite:///' + db_tmp_path
|
||||||
|
session, metadata = init_db(db_url)
|
||||||
|
upgrade_op = get_upgrade_op(session)
|
||||||
|
yield upgrade_op
|
||||||
|
session.close()
|
||||||
|
session = None
|
||||||
|
gc.collect()
|
||||||
|
retries = 0
|
||||||
|
while retries < 5:
|
||||||
|
try:
|
||||||
|
if os.path.exists(tmp_folder):
|
||||||
|
shutil.rmtree(tmp_folder)
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
time.sleep(1)
|
||||||
|
retries += 1
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create temp folder for keeping db file
|
|
||||||
"""
|
|
||||||
self.tmp_folder = mkdtemp()
|
|
||||||
db_path = os.path.join(TEST_RESOURCES_PATH, 'songs', 'songs-1.9.7.sqlite')
|
|
||||||
self.db_tmp_path = os.path.join(self.tmp_folder, 'songs-1.9.7.sqlite')
|
|
||||||
shutil.copyfile(db_path, self.db_tmp_path)
|
|
||||||
db_url = 'sqlite:///' + self.db_tmp_path
|
|
||||||
self.session, metadata = init_db(db_url)
|
|
||||||
self.op = get_upgrade_op(self.session)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def test_delete_column(op):
|
||||||
"""
|
"""
|
||||||
Clean up
|
Test deleting a single column in a table
|
||||||
"""
|
"""
|
||||||
self.session.close()
|
# GIVEN: A temporary song db
|
||||||
self.session = None
|
|
||||||
gc.collect()
|
|
||||||
retries = 0
|
|
||||||
while retries < 5:
|
|
||||||
try:
|
|
||||||
if os.path.exists(self.tmp_folder):
|
|
||||||
shutil.rmtree(self.tmp_folder)
|
|
||||||
break
|
|
||||||
except Exception:
|
|
||||||
time.sleep(1)
|
|
||||||
retries += 1
|
|
||||||
|
|
||||||
def test_delete_column(self):
|
# WHEN: Deleting a columns in a table
|
||||||
"""
|
drop_column(op, 'songs', 'song_book_id')
|
||||||
Test deleting a single column in a table
|
|
||||||
"""
|
|
||||||
# GIVEN: A temporary song db
|
|
||||||
|
|
||||||
# WHEN: Deleting a columns in a table
|
# THEN: The column should have been deleted
|
||||||
drop_column(self.op, 'songs', 'song_book_id')
|
meta = sqlalchemy.MetaData(bind=op.get_bind())
|
||||||
|
meta.reflect()
|
||||||
|
columns = meta.tables['songs'].columns
|
||||||
|
|
||||||
# THEN: The column should have been deleted
|
for column in columns:
|
||||||
meta = sqlalchemy.MetaData(bind=self.op.get_bind())
|
if column.name == 'song_book_id':
|
||||||
meta.reflect()
|
assert "The column 'song_book_id' should have been deleted."
|
||||||
columns = meta.tables['songs'].columns
|
|
||||||
|
|
||||||
for column in columns:
|
|
||||||
if column.name == 'song_book_id':
|
|
||||||
self.fail("The column 'song_book_id' should have been deleted.")
|
|
||||||
|
|
||||||
def test_delete_columns(self):
|
def test_delete_columns(op):
|
||||||
"""
|
"""
|
||||||
Test deleting multiple columns in a table
|
Test deleting multiple columns in a table
|
||||||
"""
|
"""
|
||||||
# GIVEN: A temporary song db
|
# GIVEN: A temporary song db
|
||||||
|
|
||||||
# WHEN: Deleting a columns in a table
|
# WHEN: Deleting a columns in a table
|
||||||
drop_columns(self.op, 'songs', ['song_book_id', 'song_number'])
|
drop_columns(op, 'songs', ['song_book_id', 'song_number'])
|
||||||
|
|
||||||
# THEN: The columns should have been deleted
|
# THEN: The columns should have been deleted
|
||||||
meta = sqlalchemy.MetaData(bind=self.op.get_bind())
|
meta = sqlalchemy.MetaData(bind=op.get_bind())
|
||||||
meta.reflect()
|
meta.reflect()
|
||||||
columns = meta.tables['songs'].columns
|
columns = meta.tables['songs'].columns
|
||||||
|
|
||||||
for column in columns:
|
for column in columns:
|
||||||
if column.name == 'song_book_id' or column.name == 'song_number':
|
if column.name == 'song_book_id' or column.name == 'song_number':
|
||||||
self.fail("The column '%s' should have been deleted." % column.name)
|
assert "The column '%s' should have been deleted." % column.name
|
||||||
|
@ -22,314 +22,314 @@
|
|||||||
Functional tests to test the AppLocation class and related methods.
|
Functional tests to test the AppLocation class and related methods.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import pytest
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from openlp.core.common.httputils import ProxyMode, download_file, get_proxy_settings, get_url_file_size, \
|
from openlp.core.common.httputils import ProxyMode, download_file, get_proxy_settings, get_url_file_size, \
|
||||||
get_user_agent, get_web_page
|
get_user_agent, get_web_page
|
||||||
from openlp.core.common.registry import Registry
|
|
||||||
from openlp.core.common.settings import Settings
|
from openlp.core.common.settings import Settings
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestHttpUtils(TestCase, TestMixin):
|
@pytest.yield_fixture
|
||||||
|
def temp_file(settings):
|
||||||
|
tmp_file = os.path.join(tempfile.gettempdir(), 'testfile')
|
||||||
|
yield tmp_file
|
||||||
|
if os.path.isfile(tmp_file):
|
||||||
|
os.remove(tmp_file)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_user_agent_linux():
|
||||||
"""
|
"""
|
||||||
A test suite to test out various http helper functions.
|
Test that getting a user agent on Linux returns a user agent suitable for Linux
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||||
self.tempfile = os.path.join(tempfile.gettempdir(), 'testfile')
|
|
||||||
Registry.create()
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
|
|
||||||
def tearDown(self):
|
# GIVEN: The system is Linux
|
||||||
if os.path.isfile(self.tempfile):
|
mocked_sys.platform = 'linux2'
|
||||||
os.remove(self.tempfile)
|
|
||||||
|
|
||||||
def test_get_user_agent_linux(self):
|
# WHEN: We call get_user_agent()
|
||||||
"""
|
user_agent = get_user_agent()
|
||||||
Test that getting a user agent on Linux returns a user agent suitable for Linux
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is Linux
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
mocked_sys.platform = 'linux2'
|
result = 'Linux' in user_agent or 'CrOS' in user_agent
|
||||||
|
assert result is True, 'The user agent should be a valid Linux user agent'
|
||||||
# WHEN: We call get_user_agent()
|
|
||||||
user_agent = get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
result = 'Linux' in user_agent or 'CrOS' in user_agent
|
|
||||||
assert result is True, 'The user agent should be a valid Linux user agent'
|
|
||||||
|
|
||||||
def test_get_user_agent_windows(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on Windows returns a user agent suitable for Windows
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is Windows
|
|
||||||
mocked_sys.platform = 'win32'
|
|
||||||
|
|
||||||
# WHEN: We call get_user_agent()
|
|
||||||
user_agent = get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
assert 'Windows' in user_agent, 'The user agent should be a valid Windows user agent'
|
|
||||||
|
|
||||||
def test_get_user_agent_macos(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on OS X returns a user agent suitable for OS X
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is macOS
|
|
||||||
mocked_sys.platform = 'darwin'
|
|
||||||
|
|
||||||
# WHEN: We call get_user_agent()
|
|
||||||
user_agent = get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
assert 'Mac OS X' in user_agent, 'The user agent should be a valid OS X user agent'
|
|
||||||
|
|
||||||
def test_get_user_agent_default(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is something else
|
|
||||||
mocked_sys.platform = 'freebsd'
|
|
||||||
|
|
||||||
# WHEN: We call get_user_agent()
|
|
||||||
user_agent = get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
assert 'NetBSD'in user_agent, 'The user agent should be the default user agent'
|
|
||||||
|
|
||||||
def test_get_web_page_no_url(self):
|
|
||||||
"""
|
|
||||||
Test that sending a URL of None to the get_web_page method returns None
|
|
||||||
"""
|
|
||||||
# GIVEN: A None url
|
|
||||||
test_url = None
|
|
||||||
|
|
||||||
# WHEN: We try to get the test URL
|
|
||||||
result = get_web_page(test_url)
|
|
||||||
|
|
||||||
# THEN: None should be returned
|
|
||||||
assert result is None, 'The return value of get_web_page should be None'
|
|
||||||
|
|
||||||
@patch('openlp.core.common.httputils.requests')
|
|
||||||
@patch('openlp.core.common.httputils.get_user_agent')
|
|
||||||
@patch('openlp.core.common.httputils.Registry')
|
|
||||||
def test_get_web_page(self, MockRegistry, mocked_get_user_agent, mocked_requests):
|
|
||||||
"""
|
|
||||||
Test that the get_web_page method works correctly
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects and a fake URL
|
|
||||||
mocked_requests.get.return_value = MagicMock(text='text')
|
|
||||||
mocked_get_user_agent.return_value = 'user_agent'
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
mocked_requests.get.assert_called_once_with(fake_url, headers={'User-Agent': 'user_agent'},
|
|
||||||
proxies=None, timeout=30.0)
|
|
||||||
mocked_get_user_agent.assert_called_once_with()
|
|
||||||
assert MockRegistry.call_count == 1, 'The Registry() object should have been called once'
|
|
||||||
assert returned_page == 'text', 'The returned page should be the mock object'
|
|
||||||
|
|
||||||
@patch('openlp.core.common.httputils.requests')
|
|
||||||
@patch('openlp.core.common.httputils.get_user_agent')
|
|
||||||
def test_get_web_page_with_header(self, mocked_get_user_agent, mocked_requests):
|
|
||||||
"""
|
|
||||||
Test that adding a header to the call to get_web_page() adds the header to the request
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects, a fake URL and a fake header
|
|
||||||
mocked_requests.get.return_value = MagicMock(text='text')
|
|
||||||
mocked_get_user_agent.return_value = 'user_agent'
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
fake_headers = {'Fake-Header': 'fake value'}
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url, headers=fake_headers)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
expected_headers = dict(fake_headers)
|
|
||||||
expected_headers.update({'User-Agent': 'user_agent'})
|
|
||||||
mocked_requests.get.assert_called_once_with(fake_url, headers=expected_headers,
|
|
||||||
proxies=None, timeout=30.0)
|
|
||||||
mocked_get_user_agent.assert_called_with()
|
|
||||||
assert returned_page == 'text', 'The returned page should be the mock object'
|
|
||||||
|
|
||||||
@patch('openlp.core.common.httputils.requests')
|
|
||||||
@patch('openlp.core.common.httputils.get_user_agent')
|
|
||||||
def test_get_web_page_with_user_agent_in_headers(self, mocked_get_user_agent, mocked_requests):
|
|
||||||
"""
|
|
||||||
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects, a fake URL and a fake header
|
|
||||||
mocked_requests.get.return_value = MagicMock(text='text')
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
user_agent_headers = {'User-Agent': 'OpenLP/2.2.0'}
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url, headers=user_agent_headers)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
mocked_requests.get.assert_called_once_with(fake_url, headers=user_agent_headers,
|
|
||||||
proxies=None, timeout=30.0)
|
|
||||||
assert mocked_get_user_agent.call_count == 0, 'get_user_agent() should not have been called'
|
|
||||||
assert returned_page == 'text', 'The returned page should be "test"'
|
|
||||||
|
|
||||||
@patch('openlp.core.common.httputils.requests')
|
|
||||||
@patch('openlp.core.common.httputils.get_user_agent')
|
|
||||||
@patch('openlp.core.common.httputils.Registry')
|
|
||||||
def test_get_web_page_update_openlp(self, MockRegistry, mocked_get_user_agent, mocked_requests):
|
|
||||||
"""
|
|
||||||
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects, a fake URL
|
|
||||||
mocked_requests.get.return_value = MagicMock(text='text')
|
|
||||||
mocked_get_user_agent.return_value = 'user_agent'
|
|
||||||
mocked_registry_object = MagicMock()
|
|
||||||
mocked_application_object = MagicMock()
|
|
||||||
mocked_registry_object.get.return_value = mocked_application_object
|
|
||||||
MockRegistry.return_value = mocked_registry_object
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url, update_openlp=True)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
mocked_requests.get.assert_called_once_with(fake_url, headers={'User-Agent': 'user_agent'},
|
|
||||||
proxies=None, timeout=30.0)
|
|
||||||
mocked_get_user_agent.assert_called_once_with()
|
|
||||||
mocked_registry_object.get.assert_called_with('application')
|
|
||||||
mocked_application_object.process_events.assert_called_with()
|
|
||||||
assert returned_page == 'text', 'The returned page should be the mock object'
|
|
||||||
|
|
||||||
@patch('openlp.core.common.httputils.requests')
|
|
||||||
def test_get_url_file_size(self, mocked_requests):
|
|
||||||
"""
|
|
||||||
Test that calling "get_url_file_size" works correctly
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked out objects, a fake URL
|
|
||||||
mocked_requests.head.return_value = MagicMock(headers={'Content-Length': 100})
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
|
|
||||||
# WHEN: The get_url_file_size() method is called
|
|
||||||
file_size = get_url_file_size(fake_url)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
mocked_requests.head.assert_called_once_with(fake_url, allow_redirects=True, proxies=None, timeout=30.0)
|
|
||||||
assert file_size == 100
|
|
||||||
|
|
||||||
@patch('openlp.core.common.httputils.requests')
|
|
||||||
def test_socket_timeout(self, mocked_requests):
|
|
||||||
"""
|
|
||||||
Test socket timeout gets caught
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download
|
|
||||||
mocked_requests.get.side_effect = OSError
|
|
||||||
|
|
||||||
# WHEN: Attempt to retrieve a file
|
|
||||||
download_file(MagicMock(), url='http://localhost/test', file_path=Path(self.tempfile))
|
|
||||||
|
|
||||||
# THEN: socket.timeout should have been caught
|
|
||||||
# NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files
|
|
||||||
assert os.path.exists(self.tempfile) is False, 'tempfile should have been deleted'
|
|
||||||
|
|
||||||
|
|
||||||
class TestGetProxySettings(TestCase, TestMixin):
|
def test_get_user_agent_windows():
|
||||||
def setUp(self):
|
"""
|
||||||
self.build_settings()
|
Test that getting a user agent on Windows returns a user agent suitable for Windows
|
||||||
Registry.create()
|
"""
|
||||||
Registry().register('settings', Settings())
|
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||||
self.addCleanup(self.destroy_settings)
|
|
||||||
|
|
||||||
def test_no_proxy_mode(self):
|
# GIVEN: The system is Windows
|
||||||
"""
|
mocked_sys.platform = 'win32'
|
||||||
Test that a dictionary with http and https values are set to None is returned, when `NO_PROXY` mode is specified
|
|
||||||
"""
|
|
||||||
# GIVEN: A `proxy mode` setting of NO_PROXY
|
|
||||||
Settings().setValue('advanced/proxy mode', ProxyMode.NO_PROXY)
|
|
||||||
|
|
||||||
# WHEN: Calling `get_proxy_settings`
|
# WHEN: We call get_user_agent()
|
||||||
result = get_proxy_settings()
|
user_agent = get_user_agent()
|
||||||
|
|
||||||
# THEN: The returned value should be a dictionary with http and https values set to None
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
assert result == {'http': None, 'https': None}
|
assert 'Windows' in user_agent, 'The user agent should be a valid Windows user agent'
|
||||||
|
|
||||||
def test_system_proxy_mode(self):
|
|
||||||
"""
|
|
||||||
Test that None is returned, when `SYSTEM_PROXY` mode is specified
|
|
||||||
"""
|
|
||||||
# GIVEN: A `proxy mode` setting of SYSTEM_PROXY
|
|
||||||
Settings().setValue('advanced/proxy mode', ProxyMode.SYSTEM_PROXY)
|
|
||||||
|
|
||||||
# WHEN: Calling `get_proxy_settings`
|
def test_get_user_agent_macos():
|
||||||
result = get_proxy_settings()
|
"""
|
||||||
|
Test that getting a user agent on OS X returns a user agent suitable for OS X
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||||
|
|
||||||
# THEN: The returned value should be None
|
# GIVEN: The system is macOS
|
||||||
assert result is None
|
mocked_sys.platform = 'darwin'
|
||||||
|
|
||||||
def test_manual_proxy_mode_no_auth(self):
|
# WHEN: We call get_user_agent()
|
||||||
"""
|
user_agent = get_user_agent()
|
||||||
Test that the correct proxy addresses are returned when basic authentication is not used
|
|
||||||
"""
|
|
||||||
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with proxy servers, but no auth credentials are supplied
|
|
||||||
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
|
||||||
Settings().setValue('advanced/proxy http', 'testhttp.server:port')
|
|
||||||
Settings().setValue('advanced/proxy https', 'testhttps.server:port')
|
|
||||||
Settings().setValue('advanced/proxy username', '')
|
|
||||||
Settings().setValue('advanced/proxy password', '')
|
|
||||||
|
|
||||||
# WHEN: Calling `get_proxy_settings`
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
result = get_proxy_settings()
|
assert 'Mac OS X' in user_agent, 'The user agent should be a valid OS X user agent'
|
||||||
|
|
||||||
# THEN: The returned value should be the proxy servers without authentication
|
|
||||||
assert result == {'http': 'http://testhttp.server:port', 'https': 'https://testhttps.server:port'}
|
|
||||||
|
|
||||||
def test_manual_proxy_mode_auth(self):
|
def test_get_user_agent_default():
|
||||||
"""
|
"""
|
||||||
Test that the correct proxy addresses are returned when basic authentication is used
|
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
|
||||||
"""
|
"""
|
||||||
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with proxy servers and auth credentials supplied
|
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||||
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
|
||||||
Settings().setValue('advanced/proxy http', 'testhttp.server:port')
|
|
||||||
Settings().setValue('advanced/proxy https', 'testhttps.server:port')
|
|
||||||
Settings().setValue('advanced/proxy username', 'user')
|
|
||||||
Settings().setValue('advanced/proxy password', 'pass')
|
|
||||||
|
|
||||||
# WHEN: Calling `get_proxy_settings`
|
# GIVEN: The system is something else
|
||||||
result = get_proxy_settings()
|
mocked_sys.platform = 'freebsd'
|
||||||
|
|
||||||
# THEN: The returned value should be the proxy servers with the authentication credentials
|
# WHEN: We call get_user_agent()
|
||||||
assert result == {'http': 'http://user:pass@testhttp.server:port',
|
user_agent = get_user_agent()
|
||||||
'https': 'https://user:pass@testhttps.server:port'}
|
|
||||||
|
|
||||||
def test_manual_proxy_mode_no_servers(self):
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
"""
|
assert 'NetBSD'in user_agent, 'The user agent should be the default user agent'
|
||||||
Test that the system proxies are overidden when the MANUAL_PROXY mode is specified, but no server addresses are
|
|
||||||
supplied
|
|
||||||
"""
|
|
||||||
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with no servers specified
|
|
||||||
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
|
||||||
Settings().setValue('advanced/proxy http', '')
|
|
||||||
Settings().setValue('advanced/proxy https', '')
|
|
||||||
Settings().setValue('advanced/proxy username', 'user')
|
|
||||||
Settings().setValue('advanced/proxy password', 'pass')
|
|
||||||
|
|
||||||
# WHEN: Calling `get_proxy_settings`
|
|
||||||
result = get_proxy_settings()
|
|
||||||
|
|
||||||
# THEN: The returned value should be the proxy servers set to None
|
def test_get_web_page_no_url():
|
||||||
assert result == {'http': None, 'https': None}
|
"""
|
||||||
|
Test that sending a URL of None to the get_web_page method returns None
|
||||||
|
"""
|
||||||
|
# GIVEN: A None url
|
||||||
|
test_url = None
|
||||||
|
|
||||||
|
# WHEN: We try to get the test URL
|
||||||
|
result = get_web_page(test_url)
|
||||||
|
|
||||||
|
# THEN: None should be returned
|
||||||
|
assert result is None, 'The return value of get_web_page should be None'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.requests')
|
||||||
|
@patch('openlp.core.common.httputils.get_user_agent')
|
||||||
|
@patch('openlp.core.common.httputils.Registry')
|
||||||
|
def test_get_web_page(MockRegistry, mocked_get_user_agent, mocked_requests):
|
||||||
|
"""
|
||||||
|
Test that the get_web_page method works correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects and a fake URL
|
||||||
|
mocked_requests.get.return_value = MagicMock(text='text')
|
||||||
|
mocked_get_user_agent.return_value = 'user_agent'
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
mocked_requests.get.assert_called_once_with(fake_url, headers={'User-Agent': 'user_agent'},
|
||||||
|
proxies=None, timeout=30.0)
|
||||||
|
mocked_get_user_agent.assert_called_once_with()
|
||||||
|
assert MockRegistry.call_count == 1, 'The Registry() object should have been called once'
|
||||||
|
assert returned_page == 'text', 'The returned page should be the mock object'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.requests')
|
||||||
|
@patch('openlp.core.common.httputils.get_user_agent')
|
||||||
|
def test_get_web_page_with_header(mocked_get_user_agent, mocked_requests, settings):
|
||||||
|
"""
|
||||||
|
Test that adding a header to the call to get_web_page() adds the header to the request
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects, a fake URL and a fake header
|
||||||
|
mocked_requests.get.return_value = MagicMock(text='text')
|
||||||
|
mocked_get_user_agent.return_value = 'user_agent'
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
fake_headers = {'Fake-Header': 'fake value'}
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url, headers=fake_headers)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
expected_headers = dict(fake_headers)
|
||||||
|
expected_headers.update({'User-Agent': 'user_agent'})
|
||||||
|
mocked_requests.get.assert_called_once_with(fake_url, headers=expected_headers,
|
||||||
|
proxies=None, timeout=30.0)
|
||||||
|
mocked_get_user_agent.assert_called_with()
|
||||||
|
assert returned_page == 'text', 'The returned page should be the mock object'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.requests')
|
||||||
|
@patch('openlp.core.common.httputils.get_user_agent')
|
||||||
|
def test_get_web_page_with_user_agent_in_headers(mocked_get_user_agent, mocked_requests):
|
||||||
|
"""
|
||||||
|
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects, a fake URL and a fake header
|
||||||
|
mocked_requests.get.return_value = MagicMock(text='text')
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
user_agent_headers = {'User-Agent': 'OpenLP/2.2.0'}
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url, headers=user_agent_headers)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
mocked_requests.get.assert_called_once_with(fake_url, headers=user_agent_headers,
|
||||||
|
proxies=None, timeout=30.0)
|
||||||
|
assert mocked_get_user_agent.call_count == 0, 'get_user_agent() should not have been called'
|
||||||
|
assert returned_page == 'text', 'The returned page should be "test"'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.requests')
|
||||||
|
@patch('openlp.core.common.httputils.get_user_agent')
|
||||||
|
@patch('openlp.core.common.httputils.Registry')
|
||||||
|
def test_get_web_page_update_openlp(MockRegistry, mocked_get_user_agent, mocked_requests):
|
||||||
|
"""
|
||||||
|
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects, a fake URL
|
||||||
|
mocked_requests.get.return_value = MagicMock(text='text')
|
||||||
|
mocked_get_user_agent.return_value = 'user_agent'
|
||||||
|
mocked_registry_object = MagicMock()
|
||||||
|
mocked_application_object = MagicMock()
|
||||||
|
mocked_registry_object.get.return_value = mocked_application_object
|
||||||
|
MockRegistry.return_value = mocked_registry_object
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url, update_openlp=True)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
mocked_requests.get.assert_called_once_with(fake_url, headers={'User-Agent': 'user_agent'},
|
||||||
|
proxies=None, timeout=30.0)
|
||||||
|
mocked_get_user_agent.assert_called_once_with()
|
||||||
|
mocked_registry_object.get.assert_called_with('application')
|
||||||
|
mocked_application_object.process_events.assert_called_with()
|
||||||
|
assert returned_page == 'text', 'The returned page should be the mock object'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.requests')
|
||||||
|
def test_get_url_file_size(mocked_requests):
|
||||||
|
"""
|
||||||
|
Test that calling "get_url_file_size" works correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked out objects, a fake URL
|
||||||
|
mocked_requests.head.return_value = MagicMock(headers={'Content-Length': 100})
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
|
||||||
|
# WHEN: The get_url_file_size() method is called
|
||||||
|
file_size = get_url_file_size(fake_url)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
mocked_requests.head.assert_called_once_with(fake_url, allow_redirects=True, proxies=None, timeout=30.0)
|
||||||
|
assert file_size == 100
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.requests')
|
||||||
|
def test_socket_timeout(mocked_requests, temp_file):
|
||||||
|
"""
|
||||||
|
Test socket timeout gets caught
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download
|
||||||
|
mocked_requests.get.side_effect = OSError
|
||||||
|
|
||||||
|
# WHEN: Attempt to retrieve a file
|
||||||
|
download_file(MagicMock(), url='http://localhost/test', file_path=Path(temp_file))
|
||||||
|
|
||||||
|
# THEN: socket.timeout should have been caught
|
||||||
|
# NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files
|
||||||
|
assert os.path.exists(temp_file) is False, 'temp_file should have been deleted'
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_proxy_mode(settings):
|
||||||
|
"""
|
||||||
|
Test that a dictionary with http and https values are set to None is returned, when `NO_PROXY` mode is specified
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of NO_PROXY
|
||||||
|
settings.setValue('advanced/proxy mode', ProxyMode.NO_PROXY)
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be a dictionary with http and https values set to None
|
||||||
|
assert result == {'http': None, 'https': None}
|
||||||
|
|
||||||
|
|
||||||
|
def test_system_proxy_mode(settings):
|
||||||
|
"""
|
||||||
|
Test that None is returned, when `SYSTEM_PROXY` mode is specified
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of SYSTEM_PROXY
|
||||||
|
settings.setValue('advanced/proxy mode', ProxyMode.SYSTEM_PROXY)
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be None
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_manual_proxy_mode_no_auth():
|
||||||
|
"""
|
||||||
|
Test that the correct proxy addresses are returned when basic authentication is not used
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with proxy servers, but no auth credentials are supplied
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
Settings().setValue('advanced/proxy http', 'testhttp.server:port')
|
||||||
|
Settings().setValue('advanced/proxy https', 'testhttps.server:port')
|
||||||
|
Settings().setValue('advanced/proxy username', '')
|
||||||
|
Settings().setValue('advanced/proxy password', '')
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be the proxy servers without authentication
|
||||||
|
assert result == {'http': 'http://testhttp.server:port', 'https': 'https://testhttps.server:port'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_manual_proxy_mode_auth():
|
||||||
|
"""
|
||||||
|
Test that the correct proxy addresses are returned when basic authentication is used
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with proxy servers and auth credentials supplied
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
Settings().setValue('advanced/proxy http', 'testhttp.server:port')
|
||||||
|
Settings().setValue('advanced/proxy https', 'testhttps.server:port')
|
||||||
|
Settings().setValue('advanced/proxy username', 'user')
|
||||||
|
Settings().setValue('advanced/proxy password', 'pass')
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be the proxy servers with the authentication credentials
|
||||||
|
assert result == {'http': 'http://user:pass@testhttp.server:port',
|
||||||
|
'https': 'https://user:pass@testhttps.server:port'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_manual_proxy_mode_no_servers():
|
||||||
|
"""
|
||||||
|
Test that the system proxies are overidden when the MANUAL_PROXY mode is specified, but no server addresses are
|
||||||
|
supplied
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with no servers specified
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
Settings().setValue('advanced/proxy http', '')
|
||||||
|
Settings().setValue('advanced/proxy https', '')
|
||||||
|
Settings().setValue('advanced/proxy username', 'user')
|
||||||
|
Settings().setValue('advanced/proxy password', 'pass')
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be the proxy servers set to None
|
||||||
|
assert result == {'http': None, 'https': None}
|
||||||
|
|
||||||
|
|
||||||
def test_mode_arg_specified(mock_settings):
|
def test_mode_arg_specified(mock_settings):
|
||||||
|
@ -23,347 +23,347 @@ Functional tests to test the AppLocation class and related methods.
|
|||||||
"""
|
"""
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, PropertyMock, call, patch
|
from unittest.mock import MagicMock, PropertyMock, call, patch
|
||||||
|
|
||||||
from openlp.core.common import add_actions, clean_filename, delete_file, get_file_encoding, get_filesystem_encoding, \
|
from openlp.core.common import add_actions, clean_filename, delete_file, get_file_encoding, get_filesystem_encoding, \
|
||||||
get_uno_command, get_uno_instance
|
get_uno_command, get_uno_instance
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestInit(TestCase, TestMixin):
|
def test_add_actions_empty_list():
|
||||||
"""
|
"""
|
||||||
A test suite to test out various methods around the common __init__ class.
|
Test that no actions are added when the list is empty
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and an empty list
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
empty_list = []
|
||||||
|
|
||||||
|
# WHEN: The empty list is added to the mocked target
|
||||||
|
add_actions(mocked_target, empty_list)
|
||||||
|
|
||||||
|
# THEN: The add method on the mocked target is never called
|
||||||
|
assert mocked_target.addSeparator.call_count == 0, 'addSeparator method should not have been called'
|
||||||
|
assert mocked_target.addAction.call_count == 0, 'addAction method should not have been called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_actions_none_action():
|
||||||
|
"""
|
||||||
|
Test that a separator is added when a None action is in the list
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and a list with None in it
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
separator_list = [None]
|
||||||
|
|
||||||
|
# WHEN: The list is added to the mocked target
|
||||||
|
add_actions(mocked_target, separator_list)
|
||||||
|
|
||||||
|
# THEN: The addSeparator method is called, but the addAction method is never called
|
||||||
|
mocked_target.addSeparator.assert_called_with()
|
||||||
|
assert mocked_target.addAction.call_count == 0, 'addAction method should not have been called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_actions_add_action():
|
||||||
|
"""
|
||||||
|
Test that an action is added when a valid action is in the list
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and a list with an action in it
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
action_list = ['action']
|
||||||
|
|
||||||
|
# WHEN: The list is added to the mocked target
|
||||||
|
add_actions(mocked_target, action_list)
|
||||||
|
|
||||||
|
# THEN: The addSeparator method is not called, and the addAction method is called
|
||||||
|
assert mocked_target.addSeparator.call_count == 0, 'addSeparator method should not have been called'
|
||||||
|
mocked_target.addAction.assert_called_with('action')
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_actions_action_and_none():
|
||||||
|
"""
|
||||||
|
Test that an action and a separator are added when a valid action and None are in the list
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and a list with an action and None in it
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
action_list = ['action', None]
|
||||||
|
|
||||||
|
# WHEN: The list is added to the mocked target
|
||||||
|
add_actions(mocked_target, action_list)
|
||||||
|
|
||||||
|
# THEN: The addSeparator method is called, and the addAction method is called
|
||||||
|
mocked_target.addSeparator.assert_called_with()
|
||||||
|
mocked_target.addAction.assert_called_with('action')
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_uno_instance_pipe():
|
||||||
|
"""
|
||||||
|
Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI
|
||||||
|
"""
|
||||||
|
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "pipe"
|
||||||
|
mock_resolver = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: get_uno_instance() is called
|
||||||
|
get_uno_instance(mock_resolver)
|
||||||
|
|
||||||
|
# THEN: the resolve method is called with the correct argument
|
||||||
|
mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_uno_instance_socket():
|
||||||
|
"""
|
||||||
|
Test that when the UNO connection type is other than "pipe" the resolver is given the "socket" URI
|
||||||
|
"""
|
||||||
|
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "socket"
|
||||||
|
mock_resolver = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: get_uno_instance() is called
|
||||||
|
get_uno_instance(mock_resolver, 'socket')
|
||||||
|
|
||||||
|
# THEN: the resolve method is called with the correct argument
|
||||||
|
mock_resolver.resolve.assert_called_with('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_uno_command_libreoffice_command_exists():
|
||||||
|
"""
|
||||||
|
Test the ``get_uno_command`` function uses the libreoffice command when available.
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
# GIVEN: A patched 'which' method which returns a path when called with 'libreoffice'
|
||||||
"""
|
with patch('openlp.core.common.which',
|
||||||
Create an instance and a few example actions.
|
**{'side_effect': lambda command: {'libreoffice': '/usr/bin/libreoffice'}[command]}):
|
||||||
"""
|
# WHEN: Calling get_uno_command
|
||||||
self.build_settings()
|
result = get_uno_command()
|
||||||
|
|
||||||
def tearDown(self):
|
# THEN: The command 'libreoffice' should be called with the appropriate parameters
|
||||||
"""
|
assert result == 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \
|
||||||
Clean up
|
' "--accept=pipe,name=openlp_pipe;urp;"'
|
||||||
"""
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
def test_add_actions_empty_list(self):
|
|
||||||
"""
|
|
||||||
Test that no actions are added when the list is empty
|
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and an empty list
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
empty_list = []
|
|
||||||
|
|
||||||
# WHEN: The empty list is added to the mocked target
|
def test_get_uno_command_only_soffice_command_exists():
|
||||||
add_actions(mocked_target, empty_list)
|
"""
|
||||||
|
Test the ``get_uno_command`` function uses the soffice command when the libreoffice command is not available.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
# THEN: The add method on the mocked target is never called
|
# GIVEN: A patched 'which' method which returns None when called with 'libreoffice' and a path when called with
|
||||||
assert mocked_target.addSeparator.call_count == 0, 'addSeparator method should not have been called'
|
# 'soffice'
|
||||||
assert mocked_target.addAction.call_count == 0, 'addAction method should not have been called'
|
with patch('openlp.core.common.which',
|
||||||
|
**{'side_effect': lambda command: {'libreoffice': None, 'soffice': '/usr/bin/soffice'}[
|
||||||
|
command]}):
|
||||||
|
# WHEN: Calling get_uno_command
|
||||||
|
result = get_uno_command()
|
||||||
|
|
||||||
def test_add_actions_none_action(self):
|
# THEN: The command 'soffice' should be called with the appropriate parameters
|
||||||
"""
|
assert result == 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \
|
||||||
Test that a separator is added when a None action is in the list
|
' "--accept=pipe,name=openlp_pipe;urp;"'
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and a list with None in it
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
separator_list = [None]
|
|
||||||
|
|
||||||
# WHEN: The list is added to the mocked target
|
|
||||||
add_actions(mocked_target, separator_list)
|
|
||||||
|
|
||||||
# THEN: The addSeparator method is called, but the addAction method is never called
|
def test_get_uno_command_when_no_command_exists():
|
||||||
mocked_target.addSeparator.assert_called_with()
|
"""
|
||||||
assert mocked_target.addAction.call_count == 0, 'addAction method should not have been called'
|
Test the ``get_uno_command`` function raises an FileNotFoundError when neither the libreoffice or soffice
|
||||||
|
commands are available.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
def test_add_actions_add_action(self):
|
# GIVEN: A patched 'which' method which returns None
|
||||||
"""
|
with patch('openlp.core.common.which', **{'return_value': None}):
|
||||||
Test that an action is added when a valid action is in the list
|
# WHEN: Calling get_uno_command
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and a list with an action in it
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
action_list = ['action']
|
|
||||||
|
|
||||||
# WHEN: The list is added to the mocked target
|
# THEN: a FileNotFoundError exception should be raised
|
||||||
add_actions(mocked_target, action_list)
|
assert FileNotFoundError, get_uno_command
|
||||||
|
|
||||||
# THEN: The addSeparator method is not called, and the addAction method is called
|
|
||||||
assert mocked_target.addSeparator.call_count == 0, 'addSeparator method should not have been called'
|
|
||||||
mocked_target.addAction.assert_called_with('action')
|
|
||||||
|
|
||||||
def test_add_actions_action_and_none(self):
|
def test_get_uno_command_connection_type():
|
||||||
"""
|
"""
|
||||||
Test that an action and a separator are added when a valid action and None are in the list
|
Test the ``get_uno_command`` function when the connection type is anything other than pipe.
|
||||||
"""
|
:return:
|
||||||
# GIVEN: a mocked action list, and a list with an action and None in it
|
"""
|
||||||
mocked_target = MagicMock()
|
|
||||||
action_list = ['action', None]
|
|
||||||
|
|
||||||
# WHEN: The list is added to the mocked target
|
# GIVEN: A patched 'which' method which returns 'libreoffice'
|
||||||
add_actions(mocked_target, action_list)
|
with patch('openlp.core.common.which', **{'return_value': 'libreoffice'}):
|
||||||
|
# WHEN: Calling get_uno_command with a connection type other than pipe
|
||||||
|
result = get_uno_command('socket')
|
||||||
|
|
||||||
# THEN: The addSeparator method is called, and the addAction method is called
|
# THEN: The connection parameters should be set for socket
|
||||||
mocked_target.addSeparator.assert_called_with()
|
assert result == 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \
|
||||||
mocked_target.addAction.assert_called_with('action')
|
' "--accept=socket,host=localhost,port=2002;urp;"'
|
||||||
|
|
||||||
def test_get_uno_instance_pipe(self):
|
|
||||||
"""
|
|
||||||
Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI
|
|
||||||
"""
|
|
||||||
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "pipe"
|
|
||||||
mock_resolver = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: get_uno_instance() is called
|
def test_get_filesystem_encoding_sys_function_not_called():
|
||||||
get_uno_instance(mock_resolver)
|
"""
|
||||||
|
Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function
|
||||||
|
"""
|
||||||
|
# GIVEN: sys.getfilesystemencoding returns "cp1252"
|
||||||
|
with patch('openlp.core.common.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
||||||
|
patch('openlp.core.common.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
||||||
|
mocked_getfilesystemencoding.return_value = 'cp1252'
|
||||||
|
|
||||||
# THEN: the resolve method is called with the correct argument
|
# WHEN: get_filesystem_encoding() is called
|
||||||
mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
|
result = get_filesystem_encoding()
|
||||||
|
|
||||||
def test_get_uno_instance_socket(self):
|
# THEN: getdefaultencoding should have been called
|
||||||
"""
|
mocked_getfilesystemencoding.assert_called_with()
|
||||||
Test that when the UNO connection type is other than "pipe" the resolver is given the "socket" URI
|
assert mocked_getdefaultencoding.called == 0, 'getdefaultencoding should not have been called'
|
||||||
"""
|
assert 'cp1252' == result, 'The result should be "cp1252"'
|
||||||
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "socket"
|
|
||||||
mock_resolver = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: get_uno_instance() is called
|
|
||||||
get_uno_instance(mock_resolver, 'socket')
|
|
||||||
|
|
||||||
# THEN: the resolve method is called with the correct argument
|
def test_get_filesystem_encoding_sys_function_is_called():
|
||||||
mock_resolver.resolve.assert_called_with('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
"""
|
||||||
|
Test the get_filesystem_encoding() function calls the sys.getdefaultencoding() function
|
||||||
|
"""
|
||||||
|
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
|
||||||
|
with patch('openlp.core.common.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
||||||
|
patch('openlp.core.common.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
||||||
|
mocked_getfilesystemencoding.return_value = None
|
||||||
|
mocked_getdefaultencoding.return_value = 'utf-8'
|
||||||
|
|
||||||
def test_get_uno_command_libreoffice_command_exists(self):
|
# WHEN: get_filesystem_encoding() is called
|
||||||
"""
|
result = get_filesystem_encoding()
|
||||||
Test the ``get_uno_command`` function uses the libreoffice command when available.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns a path when called with 'libreoffice'
|
# THEN: getdefaultencoding should have been called
|
||||||
with patch('openlp.core.common.which',
|
mocked_getfilesystemencoding.assert_called_with()
|
||||||
**{'side_effect': lambda command: {'libreoffice': '/usr/bin/libreoffice'}[command]}):
|
mocked_getdefaultencoding.assert_called_with()
|
||||||
# WHEN: Calling get_uno_command
|
assert 'utf-8' == result, 'The result should be "utf-8"'
|
||||||
result = get_uno_command()
|
|
||||||
|
|
||||||
# THEN: The command 'libreoffice' should be called with the appropriate parameters
|
|
||||||
assert result == 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \
|
|
||||||
' "--accept=pipe,name=openlp_pipe;urp;"'
|
|
||||||
|
|
||||||
def test_get_uno_command_only_soffice_command_exists(self):
|
def test_clean_filename():
|
||||||
"""
|
"""
|
||||||
Test the ``get_uno_command`` function uses the soffice command when the libreoffice command is not available.
|
Test the clean_filename() function
|
||||||
:return:
|
"""
|
||||||
"""
|
# GIVEN: A invalid file name and the valid file name.
|
||||||
|
invalid_name = 'A_file_with_invalid_characters_[\\/:*?"<>|+[]%].py'
|
||||||
|
wanted_name = 'A_file_with_invalid_characters________________.py'
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns None when called with 'libreoffice' and a path when called with
|
# WHEN: Clean the name.
|
||||||
# 'soffice'
|
result = clean_filename(invalid_name)
|
||||||
with patch('openlp.core.common.which',
|
|
||||||
**{'side_effect': lambda command: {'libreoffice': None, 'soffice': '/usr/bin/soffice'}[
|
|
||||||
command]}):
|
|
||||||
# WHEN: Calling get_uno_command
|
|
||||||
result = get_uno_command()
|
|
||||||
|
|
||||||
# THEN: The command 'soffice' should be called with the appropriate parameters
|
# THEN: The file name should be cleaned.
|
||||||
assert result == 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \
|
assert wanted_name == result, 'The file name should not contain any special characters.'
|
||||||
' "--accept=pipe,name=openlp_pipe;urp;"'
|
|
||||||
|
|
||||||
def test_get_uno_command_when_no_command_exists(self):
|
|
||||||
"""
|
|
||||||
Test the ``get_uno_command`` function raises an FileNotFoundError when neither the libreoffice or soffice
|
|
||||||
commands are available.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns None
|
def test_delete_file_no_path():
|
||||||
with patch('openlp.core.common.which', **{'return_value': None}):
|
"""
|
||||||
# WHEN: Calling get_uno_command
|
Test the delete_file function when called with out a valid path
|
||||||
|
"""
|
||||||
|
# GIVEN: A blank path
|
||||||
|
# WEHN: Calling delete_file
|
||||||
|
result = delete_file(None)
|
||||||
|
|
||||||
# THEN: a FileNotFoundError exception should be raised
|
# THEN: delete_file should return False
|
||||||
self.assertRaises(FileNotFoundError, get_uno_command)
|
assert result is False, "delete_file should return False when called with None"
|
||||||
|
|
||||||
def test_get_uno_command_connection_type(self):
|
|
||||||
"""
|
|
||||||
Test the ``get_uno_command`` function when the connection type is anything other than pipe.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns 'libreoffice'
|
def test_delete_file_path_success():
|
||||||
with patch('openlp.core.common.which', **{'return_value': 'libreoffice'}):
|
"""
|
||||||
# WHEN: Calling get_uno_command with a connection type other than pipe
|
Test the delete_file function when it successfully deletes a file
|
||||||
result = get_uno_command('socket')
|
"""
|
||||||
|
# GIVEN: A mocked os which returns True when os.path.exists is called
|
||||||
|
with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
|
||||||
|
|
||||||
# THEN: The connection parameters should be set for socket
|
# WHEN: Calling delete_file with a file path
|
||||||
assert result == 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \
|
result = delete_file(Path('path', 'file.ext'))
|
||||||
' "--accept=socket,host=localhost,port=2002;urp;"'
|
|
||||||
|
|
||||||
def test_get_filesystem_encoding_sys_function_not_called(self):
|
# THEN: delete_file should return True
|
||||||
"""
|
assert result is True, 'delete_file should return True when it successfully deletes a file'
|
||||||
Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function
|
|
||||||
"""
|
|
||||||
# GIVEN: sys.getfilesystemencoding returns "cp1252"
|
|
||||||
with patch('openlp.core.common.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
|
||||||
patch('openlp.core.common.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
|
||||||
mocked_getfilesystemencoding.return_value = 'cp1252'
|
|
||||||
|
|
||||||
# WHEN: get_filesystem_encoding() is called
|
|
||||||
result = get_filesystem_encoding()
|
|
||||||
|
|
||||||
# THEN: getdefaultencoding should have been called
|
def test_delete_file_path_no_file_exists():
|
||||||
mocked_getfilesystemencoding.assert_called_with()
|
"""
|
||||||
assert mocked_getdefaultencoding.called == 0, 'getdefaultencoding should not have been called'
|
Test the `delete_file` function when the file to remove does not exist
|
||||||
assert 'cp1252' == result, 'The result should be "cp1252"'
|
"""
|
||||||
|
# GIVEN: A patched `exists` methods on the Path object, which returns False
|
||||||
|
with patch.object(Path, 'exists', return_value=False), \
|
||||||
|
patch.object(Path, 'unlink') as mocked_unlink:
|
||||||
|
|
||||||
def test_get_filesystem_encoding_sys_function_is_called(self):
|
# WHEN: Calling `delete_file with` a file path
|
||||||
"""
|
result = delete_file(Path('path', 'file.ext'))
|
||||||
Test the get_filesystem_encoding() function calls the sys.getdefaultencoding() function
|
|
||||||
"""
|
|
||||||
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
|
|
||||||
with patch('openlp.core.common.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
|
||||||
patch('openlp.core.common.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
|
||||||
mocked_getfilesystemencoding.return_value = None
|
|
||||||
mocked_getdefaultencoding.return_value = 'utf-8'
|
|
||||||
|
|
||||||
# WHEN: get_filesystem_encoding() is called
|
# THEN: The function should not attempt to delete the file and it should return True
|
||||||
result = get_filesystem_encoding()
|
assert mocked_unlink.called is False
|
||||||
|
assert result is True, 'delete_file should return True when the file doesnt exist'
|
||||||
|
|
||||||
# THEN: getdefaultencoding should have been called
|
|
||||||
mocked_getfilesystemencoding.assert_called_with()
|
|
||||||
mocked_getdefaultencoding.assert_called_with()
|
|
||||||
assert 'utf-8' == result, 'The result should be "utf-8"'
|
|
||||||
|
|
||||||
def test_clean_filename(self):
|
def test_delete_file_path_exception():
|
||||||
"""
|
"""
|
||||||
Test the clean_filename() function
|
Test the delete_file function when an exception is raised
|
||||||
"""
|
"""
|
||||||
# GIVEN: A invalid file name and the valid file name.
|
# GIVEN: A test `Path` object with a patched exists method which raises an OSError
|
||||||
invalid_name = 'A_file_with_invalid_characters_[\\/:*?"<>|+[]%].py'
|
# called.
|
||||||
wanted_name = 'A_file_with_invalid_characters________________.py'
|
with patch.object(Path, 'exists') as mocked_exists, \
|
||||||
|
patch('openlp.core.common.log') as mocked_log:
|
||||||
|
mocked_exists.side_effect = OSError
|
||||||
|
|
||||||
# WHEN: Clean the name.
|
# WHEN: Calling delete_file with a the test Path object
|
||||||
result = clean_filename(invalid_name)
|
result = delete_file(Path('path', 'file.ext'))
|
||||||
|
|
||||||
# THEN: The file name should be cleaned.
|
# THEN: The exception should be logged and `delete_file` should return False
|
||||||
assert wanted_name == result, 'The file name should not contain any special characters.'
|
assert mocked_log.exception.called
|
||||||
|
assert result is False, 'delete_file should return False when an OSError is raised'
|
||||||
|
|
||||||
def test_delete_file_no_path(self):
|
|
||||||
"""
|
|
||||||
Test the delete_file function when called with out a valid path
|
|
||||||
"""
|
|
||||||
# GIVEN: A blank path
|
|
||||||
# WEHN: Calling delete_file
|
|
||||||
result = delete_file(None)
|
|
||||||
|
|
||||||
# THEN: delete_file should return False
|
def test_get_file_encoding_done():
|
||||||
assert result is False, "delete_file should return False when called with None"
|
"""
|
||||||
|
Test get_file_encoding when the detector sets done to True
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked UniversalDetector instance with done attribute set to True after first iteration
|
||||||
|
with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
|
||||||
|
patch.object(Path, 'open', return_value=BytesIO(b'data' * 260)) as mocked_open:
|
||||||
|
encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
|
||||||
|
mocked_universal_detector_inst = MagicMock(**{'close.return_value': encoding_result})
|
||||||
|
type(mocked_universal_detector_inst).done = PropertyMock(side_effect=[False, True])
|
||||||
|
mocked_universal_detector.return_value = mocked_universal_detector_inst
|
||||||
|
|
||||||
def test_delete_file_path_success(self):
|
# WHEN: Calling get_file_encoding
|
||||||
"""
|
result = get_file_encoding(Path('file name'))
|
||||||
Test the delete_file function when it successfully deletes a file
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked os which returns True when os.path.exists is called
|
|
||||||
with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
|
|
||||||
|
|
||||||
# WHEN: Calling delete_file with a file path
|
# THEN: The feed method of UniversalDetector should only br called once before returning a result
|
||||||
result = delete_file(Path('path', 'file.ext'))
|
mocked_open.assert_called_once_with('rb')
|
||||||
|
assert mocked_universal_detector_inst.feed.mock_calls == [call(b'data' * 256)]
|
||||||
|
mocked_universal_detector_inst.close.assert_called_once_with()
|
||||||
|
assert result == 'UTF-8'
|
||||||
|
|
||||||
# THEN: delete_file should return True
|
|
||||||
assert result is True, 'delete_file should return True when it successfully deletes a file'
|
|
||||||
|
|
||||||
def test_delete_file_path_no_file_exists(self):
|
def test_get_file_encoding_eof():
|
||||||
"""
|
"""
|
||||||
Test the `delete_file` function when the file to remove does not exist
|
Test get_file_encoding when the end of the file is reached
|
||||||
"""
|
"""
|
||||||
# GIVEN: A patched `exists` methods on the Path object, which returns False
|
# GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test
|
||||||
with patch.object(Path, 'exists', return_value=False), \
|
# data (enough to run the iterator twice)
|
||||||
patch.object(Path, 'unlink') as mocked_unlink:
|
with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
|
||||||
|
patch.object(Path, 'open', return_value=BytesIO(b'data' * 260)) as mocked_open:
|
||||||
|
encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
|
||||||
|
mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,
|
||||||
|
**{'done': False, 'close.return_value': encoding_result})
|
||||||
|
mocked_universal_detector.return_value = mocked_universal_detector_inst
|
||||||
|
|
||||||
# WHEN: Calling `delete_file with` a file path
|
# WHEN: Calling get_file_encoding
|
||||||
result = delete_file(Path('path', 'file.ext'))
|
result = get_file_encoding(Path('file name'))
|
||||||
|
|
||||||
# THEN: The function should not attempt to delete the file and it should return True
|
# THEN: The feed method of UniversalDetector should have been called twice before returning a result
|
||||||
assert mocked_unlink.called is False
|
mocked_open.assert_called_once_with('rb')
|
||||||
assert result is True, 'delete_file should return True when the file doesnt exist'
|
assert mocked_universal_detector_inst.feed.mock_calls == [call(b'data' * 256), call(b'data' * 4)]
|
||||||
|
mocked_universal_detector_inst.close.assert_called_once_with()
|
||||||
|
assert result == 'UTF-8'
|
||||||
|
|
||||||
def test_delete_file_path_exception(self):
|
|
||||||
"""
|
|
||||||
Test the delete_file function when an exception is raised
|
|
||||||
"""
|
|
||||||
# GIVEN: A test `Path` object with a patched exists method which raises an OSError
|
|
||||||
# called.
|
|
||||||
with patch.object(Path, 'exists') as mocked_exists, \
|
|
||||||
patch('openlp.core.common.log') as mocked_log:
|
|
||||||
mocked_exists.side_effect = OSError
|
|
||||||
|
|
||||||
# WHEN: Calling delete_file with a the test Path object
|
def test_get_file_encoding_oserror():
|
||||||
result = delete_file(Path('path', 'file.ext'))
|
"""
|
||||||
|
Test get_file_encoding when the end of the file is reached
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test
|
||||||
|
# data (enough to run the iterator twice)
|
||||||
|
with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
|
||||||
|
patch('builtins.open', side_effect=OSError), \
|
||||||
|
patch('openlp.core.common.log') as mocked_log:
|
||||||
|
encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
|
||||||
|
mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,
|
||||||
|
**{'done': False, 'close.return_value': encoding_result})
|
||||||
|
mocked_universal_detector.return_value = mocked_universal_detector_inst
|
||||||
|
|
||||||
# THEN: The exception should be logged and `delete_file` should return False
|
# WHEN: Calling get_file_encoding
|
||||||
assert mocked_log.exception.called
|
result = get_file_encoding(Path('file name'))
|
||||||
assert result is False, 'delete_file should return False when an OSError is raised'
|
|
||||||
|
|
||||||
def test_get_file_encoding_done(self):
|
# THEN: log.exception should be called and get_file_encoding should return None
|
||||||
"""
|
mocked_log.exception.assert_called_once_with('Error detecting file encoding')
|
||||||
Test get_file_encoding when the detector sets done to True
|
mocked_universal_detector_inst.feed.assert_not_called()
|
||||||
"""
|
mocked_universal_detector_inst.close.assert_called_once_with()
|
||||||
# GIVEN: A mocked UniversalDetector instance with done attribute set to True after first iteration
|
assert result == 'UTF-8'
|
||||||
with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
|
|
||||||
patch.object(Path, 'open', return_value=BytesIO(b'data' * 260)) as mocked_open:
|
|
||||||
encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
|
|
||||||
mocked_universal_detector_inst = MagicMock(**{'close.return_value': encoding_result})
|
|
||||||
type(mocked_universal_detector_inst).done = PropertyMock(side_effect=[False, True])
|
|
||||||
mocked_universal_detector.return_value = mocked_universal_detector_inst
|
|
||||||
|
|
||||||
# WHEN: Calling get_file_encoding
|
|
||||||
result = get_file_encoding(Path('file name'))
|
|
||||||
|
|
||||||
# THEN: The feed method of UniversalDetector should only br called once before returning a result
|
|
||||||
mocked_open.assert_called_once_with('rb')
|
|
||||||
assert mocked_universal_detector_inst.feed.mock_calls == [call(b'data' * 256)]
|
|
||||||
mocked_universal_detector_inst.close.assert_called_once_with()
|
|
||||||
assert result == 'UTF-8'
|
|
||||||
|
|
||||||
def test_get_file_encoding_eof(self):
|
|
||||||
"""
|
|
||||||
Test get_file_encoding when the end of the file is reached
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test
|
|
||||||
# data (enough to run the iterator twice)
|
|
||||||
with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
|
|
||||||
patch.object(Path, 'open', return_value=BytesIO(b'data' * 260)) as mocked_open:
|
|
||||||
encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
|
|
||||||
mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,
|
|
||||||
**{'done': False, 'close.return_value': encoding_result})
|
|
||||||
mocked_universal_detector.return_value = mocked_universal_detector_inst
|
|
||||||
|
|
||||||
# WHEN: Calling get_file_encoding
|
|
||||||
result = get_file_encoding(Path('file name'))
|
|
||||||
|
|
||||||
# THEN: The feed method of UniversalDetector should have been called twice before returning a result
|
|
||||||
mocked_open.assert_called_once_with('rb')
|
|
||||||
assert mocked_universal_detector_inst.feed.mock_calls == [call(b'data' * 256), call(b'data' * 4)]
|
|
||||||
mocked_universal_detector_inst.close.assert_called_once_with()
|
|
||||||
assert result == 'UTF-8'
|
|
||||||
|
|
||||||
def test_get_file_encoding_oserror(self):
|
|
||||||
"""
|
|
||||||
Test get_file_encoding when the end of the file is reached
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test
|
|
||||||
# data (enough to run the iterator twice)
|
|
||||||
with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
|
|
||||||
patch('builtins.open', side_effect=OSError), \
|
|
||||||
patch('openlp.core.common.log') as mocked_log:
|
|
||||||
encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
|
|
||||||
mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,
|
|
||||||
**{'done': False, 'close.return_value': encoding_result})
|
|
||||||
mocked_universal_detector.return_value = mocked_universal_detector_inst
|
|
||||||
|
|
||||||
# WHEN: Calling get_file_encoding
|
|
||||||
result = get_file_encoding(Path('file name'))
|
|
||||||
|
|
||||||
# THEN: log.exception should be called and get_file_encoding should return None
|
|
||||||
mocked_log.exception.assert_called_once_with('Error detecting file encoding')
|
|
||||||
mocked_universal_detector_inst.feed.assert_not_called()
|
|
||||||
mocked_universal_detector_inst.close.assert_called_once_with()
|
|
||||||
assert result == 'UTF-8'
|
|
||||||
|
@ -29,7 +29,6 @@ sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
|
|||||||
|
|
||||||
from openlp.core.app import parse_options
|
from openlp.core.app import parse_options
|
||||||
from openlp.core.common import is_win
|
from openlp.core.common import is_win
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_options_basic():
|
def test_parse_options_basic():
|
||||||
@ -239,7 +238,7 @@ def test_backup_on_upgrade_first_install(mocked_question, mocked_get_version, qa
|
|||||||
qapp.backup_on_upgrade(old_install, False)
|
qapp.backup_on_upgrade(old_install, False)
|
||||||
|
|
||||||
# THEN: It should not ask if we want to create a backup
|
# THEN: It should not ask if we want to create a backup
|
||||||
assert Settings().value('core/application version') == '2.4.0', 'Version should be the same!'
|
assert settings.value('core/application version') == '2.4.0', 'Version should be the same!'
|
||||||
assert mocked_question.call_count == 0, 'No question should have been asked!'
|
assert mocked_question.call_count == 0, 'No question should have been asked!'
|
||||||
|
|
||||||
|
|
||||||
@ -266,7 +265,7 @@ def test_backup_on_upgrade(mocked_question, mocked_get_version, qapp, settings):
|
|||||||
qapp.backup_on_upgrade(old_install, True)
|
qapp.backup_on_upgrade(old_install, True)
|
||||||
|
|
||||||
# THEN: It should ask if we want to create a backup
|
# THEN: It should ask if we want to create a backup
|
||||||
assert Settings().value('core/application version') == '2.9.0', 'Version should be upgraded!'
|
assert settings.value('core/application version') == '2.9.0', 'Version should be upgraded!'
|
||||||
assert mocked_question.call_count == 1, 'A question should have been asked!'
|
assert mocked_question.call_count == 1, 'A question should have been asked!'
|
||||||
qapp.splash.hide.assert_called_once_with()
|
qapp.splash.hide.assert_called_once_with()
|
||||||
qapp.splash.show.assert_called_once_with()
|
qapp.splash.show.assert_called_once_with()
|
||||||
|
@ -28,20 +28,6 @@ from openlp.core.ui.settingsform import SettingsForm
|
|||||||
from openlp.core.ui.themestab import ThemesTab
|
from openlp.core.ui.themestab import ThemesTab
|
||||||
|
|
||||||
|
|
||||||
def test_creation(mock_settings):
|
|
||||||
"""
|
|
||||||
Test that Themes Tab is created.
|
|
||||||
"""
|
|
||||||
# GIVEN: A new Advanced Tab
|
|
||||||
settings_form = SettingsForm(None)
|
|
||||||
|
|
||||||
# WHEN: I create an advanced tab
|
|
||||||
themes_tab = ThemesTab(settings_form)
|
|
||||||
|
|
||||||
# THEN:
|
|
||||||
assert "Themes" == themes_tab.tab_title, 'The tab title should be Theme'
|
|
||||||
|
|
||||||
|
|
||||||
def test_save_triggers_processes_true(mock_settings):
|
def test_save_triggers_processes_true(mock_settings):
|
||||||
"""
|
"""
|
||||||
Test that the global theme event is triggered when the tab is visited.
|
Test that the global theme event is triggered when the tab is visited.
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
"""
|
"""
|
||||||
Package to test the openlp.core.ui.mainwindow package.
|
Package to test the openlp.core.ui.mainwindow package.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase, skipIf
|
from unittest import TestCase, skipIf, skip
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from PyQt5 import QtGui
|
from PyQt5 import QtGui
|
||||||
@ -56,6 +56,7 @@ class TestMainWindow(TestCase, TestMixin):
|
|||||||
mocked_plugin.status = PluginStatus.Active
|
mocked_plugin.status = PluginStatus.Active
|
||||||
mocked_plugin.icon = QtGui.QIcon()
|
mocked_plugin.icon = QtGui.QIcon()
|
||||||
Registry().register('mock_plugin', mocked_plugin)
|
Registry().register('mock_plugin', mocked_plugin)
|
||||||
|
State().load_settings()
|
||||||
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
|
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
|
||||||
# Mock classes and methods used by mainwindow.
|
# Mock classes and methods used by mainwindow.
|
||||||
with patch('openlp.core.ui.mainwindow.SettingsForm'), \
|
with patch('openlp.core.ui.mainwindow.SettingsForm'), \
|
||||||
@ -77,6 +78,7 @@ class TestMainWindow(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
del self.main_window
|
del self.main_window
|
||||||
|
|
||||||
|
@skip('Fix when migrate to PyTest')
|
||||||
def test_restore_current_media_manager_item(self):
|
def test_restore_current_media_manager_item(self):
|
||||||
"""
|
"""
|
||||||
Regression test for bug #1152509.
|
Regression test for bug #1152509.
|
||||||
|
@ -46,6 +46,7 @@ class TestBibleManager(TestCase, TestMixin):
|
|||||||
with patch('openlp.core.common.applocation.AppLocation.get_section_data_path') as mocked_get_data_path, \
|
with patch('openlp.core.common.applocation.AppLocation.get_section_data_path') as mocked_get_data_path, \
|
||||||
patch('openlp.core.common.applocation.AppLocation.get_files') as mocked_get_files:
|
patch('openlp.core.common.applocation.AppLocation.get_files') as mocked_get_files:
|
||||||
Registry().register('settings', Settings())
|
Registry().register('settings', Settings())
|
||||||
|
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_files()
|
||||||
mocked_get_files.return_value = ["tests.sqlite"]
|
mocked_get_files.return_value = ["tests.sqlite"]
|
||||||
mocked_get_data_path.return_value = TEST_RESOURCES_PATH + "/bibles"
|
mocked_get_data_path.return_value = TEST_RESOURCES_PATH + "/bibles"
|
||||||
self.manager = BibleManager(MagicMock())
|
self.manager = BibleManager(MagicMock())
|
||||||
|
Loading…
Reference in New Issue
Block a user