From 0836d26bdc54d9be45e4c665a7b7a3851ed89921 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Tue, 29 Mar 2022 18:29:12 +0000 Subject: [PATCH] projector.editform refactoring and tests --- openlp/core/projectors/constants.py | 1 + openlp/core/projectors/editform.py | 357 +++++++----- openlp/core/projectors/manager.py | 29 +- .../{test_misc.py => test_misc_commands.py} | 0 tests/openlp_core/projectors/conftest.py | 24 + .../projectors/editform/test_accept_me.py | 535 ++++++++++++++++++ .../projectors/editform/test_misc_editform.py | 146 +++++ .../projectors/manager/test_boostrap.py | 18 +- .../projectors/test_projector_editform.py | 76 --- 9 files changed, 956 insertions(+), 230 deletions(-) rename tests/openlp_core/projectors/commands/{test_misc.py => test_misc_commands.py} (100%) create mode 100644 tests/openlp_core/projectors/editform/test_accept_me.py create mode 100644 tests/openlp_core/projectors/editform/test_misc_editform.py delete mode 100644 tests/openlp_core/projectors/test_projector_editform.py diff --git a/openlp/core/projectors/constants.py b/openlp/core/projectors/constants.py index 3648a9d42..984b872d0 100644 --- a/openlp/core/projectors/constants.py +++ b/openlp/core/projectors/constants.py @@ -40,6 +40,7 @@ PJLINK_SUFFIX = CR PJLINK_SVER_MAX_LEN = 32 PJLINK_TIMEOUT = 30.0 PJLINK_TOKEN_SIZE = 8 # PJLINK 1 : where is 8 characters +PJLINK_VALID_PORTS = range(1000, 32768) # Error and status codes S_OK = E_OK = 0 # E_OK included since I sometimes forget diff --git a/openlp/core/projectors/editform.py b/openlp/core/projectors/editform.py index 3a436e576..0457b3938 100644 --- a/openlp/core/projectors/editform.py +++ b/openlp/core/projectors/editform.py @@ -26,9 +26,9 @@ import logging from PyQt5 import QtCore, QtWidgets -from openlp.core.common import verify_ip_address +from openlp.core.common import verify_ip_address, Singleton from openlp.core.common.i18n import translate -from openlp.core.projectors.constants import PJLINK_PORT +from openlp.core.projectors.constants import PJLINK_PORT, PJLINK_VALID_PORTS from openlp.core.projectors.db import Projector from openlp.core.ui.icons import UiIcons @@ -38,6 +38,82 @@ log.debug('editform loaded') # TODO: Fix db entries for input source(s) +_translate_group = 'OpenLP.ProjectorEditForm' + + +class MessageList(metaclass=Singleton): + """ + Consolidate the messages here. Simplify calls to QMessageBox. + """ + def __init__(self): + self.AddressDuplicate = {'title': translate(_translate_group, 'Duplicate Address'), + 'text': translate(_translate_group, + 'IP:port combination are already in the database

' + 'Please Enter a different IP:port combination.') + } + self.DatabaseError = {'title': translate(_translate_group, 'Database Error'), + 'text': translate(_translate_group, + 'There was an error saving projector information.

' + 'See the log for the error') + } + self.DatabaseID = {'title': translate(_translate_group, 'Database ID Error'), + 'text': translate(_translate_group, + 'Mismatch between this entry and the database.

' + 'See the log for possible issues.') + } + self.DatabaseMultiple = {'title': translate(_translate_group, 'Multiple Records'), + 'text': translate(_translate_group, + 'Multiple entries found in the database

' + 'Ensure Name and/or IP/Port data is unique') + } + self.IPBlank = {'title': translate(_translate_group, 'IP Address Not Set'), + 'text': translate(_translate_group, + 'You must enter an IP address.

' + 'Please enter a valid IP address.') + } + self.IPInvalid = {'title': translate(_translate_group, 'Invalid IP Address'), + 'text': translate(_translate_group, + 'IP address is not valid.

' + 'Please enter a valid IP address.') + } + self.NameBlank = {'title': translate(_translate_group, 'Name Not Set'), + 'text': translate(_translate_group, + 'You must enter a name for this entry.

' + 'Please enter a unique name for this entry.') + } + self.NameDuplicate = {'title': translate(_translate_group, 'Duplicate Name'), + 'text': translate(_translate_group, + 'Entries must have unique names.

' + 'Please enter a different name.') + } + self.ProjectorInvalid = {'title': translate(_translate_group, 'Invalid Projector'), + 'text': translate(_translate_group, + 'Projector instance not a valid PJLink or Projector Instance' + '

See log for issue') + } + self.PortBlank = {'title': translate(_translate_group, 'Port Not Set'), + 'text': translate(_translate_group, + 'You must enter a port number for this entry.

' + 'Please enter a valid port number.') + } + self.PortInvalid = {'title': translate(_translate_group, 'Invalid Port Number'), + 'text': translate(_translate_group, + 'Port numbers below 1000 are reserved for admin use only.
' + 'Port numbers above 32767 are not currently usable.

' + 'Please enter a valid port number between 1000 and 32767 inclusive.' + f'

Default PJLink port is {PJLINK_PORT}') + } + + @staticmethod + def show_warning(message, form=None): + """ + Display QMessageBox.warning() + """ + return QtWidgets.QMessageBox.warning(form, message['title'], message['text']) + + +Message = MessageList() + class Ui_ProjectorEditForm(object): """ @@ -57,58 +133,61 @@ class Ui_ProjectorEditForm(object): self.dialog_layout.setObjectName('dialog_layout') self.dialog_layout.setSpacing(8) self.dialog_layout.setContentsMargins(8, 8, 8, 8) - # IP Address - self.ip_label = QtWidgets.QLabel(edit_projector_dialog) - self.ip_label.setObjectName('projector_edit_ip_label') - self.ip_text_edit = QtWidgets.QLineEdit(edit_projector_dialog) - self.ip_text_edit.setObjectName('projector_edit_ip_text') - self.ip_text_label = QtWidgets.QLabel(edit_projector_dialog) - self.ip_text_label.setObjectName('projector_show_ip_text') - self.dialog_layout.addWidget(self.ip_label, 0, 0) - # For new projector, use edit widget - self.dialog_layout.addWidget(self.ip_text_edit, 0, 1) - # For edit projector, use show widget - self.dialog_layout.addWidget(self.ip_text_label, 0, 1) - # Port number - self.port_label = QtWidgets.QLabel(edit_projector_dialog) - self.port_label.setObjectName('projector_edit_ip_label') - self.port_text = QtWidgets.QLineEdit(edit_projector_dialog) - self.port_text.setObjectName('projector_edit_port_text') - self.dialog_layout.addWidget(self.port_label, 1, 0) - self.dialog_layout.addWidget(self.port_text, 1, 1) - # PIN - self.pin_label = QtWidgets.QLabel(edit_projector_dialog) - self.pin_label.setObjectName('projector_edit_pin_label') - self.pin_text = QtWidgets.QLineEdit(edit_projector_dialog) - self.pin_label.setObjectName('projector_edit_pin_text') - self.dialog_layout.addWidget(self.pin_label, 2, 0) - self.dialog_layout.addWidget(self.pin_text, 2, 1) # Name + _row = 0 # If I decide to rearrange the layout again self.name_label = QtWidgets.QLabel(edit_projector_dialog) self.name_label.setObjectName('projector_edit_name_label') self.name_text = QtWidgets.QLineEdit(edit_projector_dialog) self.name_text.setObjectName('projector_edit_name_text') - self.dialog_layout.addWidget(self.name_label, 3, 0) - self.dialog_layout.addWidget(self.name_text, 3, 1) + self.dialog_layout.addWidget(self.name_label, _row, 0) + self.dialog_layout.addWidget(self.name_text, _row, 1) + # IP Address + _row += 1 + self.ip_label = QtWidgets.QLabel(edit_projector_dialog) + self.ip_label.setObjectName('projector_edit_ip_label') + self.ip_text = QtWidgets.QLineEdit(edit_projector_dialog) + self.ip_text.setObjectName('projector_edit_ip_text') + self.dialog_layout.addWidget(self.ip_label, _row, 0) + self.dialog_layout.addWidget(self.ip_text, _row, 1) + # Port number + _row += 1 + self.port_label = QtWidgets.QLabel(edit_projector_dialog) + self.port_label.setObjectName('projector_edit_ip_label') + self.port_text = QtWidgets.QLineEdit(edit_projector_dialog) + self.port_text.setObjectName('projector_edit_port_text') + self.dialog_layout.addWidget(self.port_label, _row, 0) + self.dialog_layout.addWidget(self.port_text, _row, 1) + # PIN + _row += 1 + self.pin_label = QtWidgets.QLabel(edit_projector_dialog) + self.pin_label.setObjectName('projector_edit_pin_label') + self.pin_text = QtWidgets.QLineEdit(edit_projector_dialog) + self.pin_label.setObjectName('projector_edit_pin_text') + self.dialog_layout.addWidget(self.pin_label, _row, 0) + self.dialog_layout.addWidget(self.pin_text, _row, 1) # Location + _row += 1 self.location_label = QtWidgets.QLabel(edit_projector_dialog) self.location_label.setObjectName('projector_edit_location_label') self.location_text = QtWidgets.QLineEdit(edit_projector_dialog) self.location_text.setObjectName('projector_edit_location_text') - self.dialog_layout.addWidget(self.location_label, 4, 0) - self.dialog_layout.addWidget(self.location_text, 4, 1) + self.dialog_layout.addWidget(self.location_label, _row, 0) + self.dialog_layout.addWidget(self.location_text, _row, 1) # Notes + _row += 1 self.notes_label = QtWidgets.QLabel(edit_projector_dialog) self.notes_label.setObjectName('projector_edit_notes_label') self.notes_text = QtWidgets.QPlainTextEdit(edit_projector_dialog) self.notes_text.setObjectName('projector_edit_notes_text') - self.dialog_layout.addWidget(self.notes_label, 5, 0, alignment=QtCore.Qt.AlignTop) - self.dialog_layout.addWidget(self.notes_text, 5, 1) + self.dialog_layout.addWidget(self.notes_label, _row, 0, alignment=QtCore.Qt.AlignTop) + self.dialog_layout.addWidget(self.notes_text, _row, 1) # Time for the buttons - self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Help | - QtWidgets.QDialogButtonBox.Save | - QtWidgets.QDialogButtonBox.Cancel) - self.dialog_layout.addWidget(self.button_box, 8, 0, 1, 2) + self.button_box_edit = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Help | + QtWidgets.QDialogButtonBox.Save | + QtWidgets.QDialogButtonBox.Cancel) + self.dialog_layout.addWidget(self.button_box_edit, 8, 0, 1, 2) + self.button_box_view = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok) + self.dialog_layout.addWidget(self.button_box_view, 8, 0, 1, 2) def retranslate_ui(self, edit_projector_dialog): if self.new_projector: @@ -118,8 +197,7 @@ class Ui_ProjectorEditForm(object): title = translate('OpenLP.ProjectorEditForm', 'Edit Projector') edit_projector_dialog.setWindowTitle(title) self.ip_label.setText(translate('OpenLP.ProjectorEditForm', 'IP Address')) - self.ip_text_edit.setText(self.projector.ip) - self.ip_text_label.setText(self.projector.ip) + self.ip_text.setText(self.projector.ip) self.port_label.setText(translate('OpenLP.ProjectorEditForm', 'Port Number')) self.port_text.setText(str(self.projector.port)) self.pin_label.setText(translate('OpenLP.ProjectorEditForm', 'PIN')) @@ -138,39 +216,51 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm): Class to add or edit a projector entry in the database. Fields that are editable: - ip = Column(String(100)) (Only edit for new projector) + name = Column(String(20)) + ip = Column(String(100)) port = Column(String(8)) pin = Column(String(20)) - name = Column(String(20)) location = Column(String(30)) notes = Column(String(200)) """ - newProjector = QtCore.pyqtSignal(str) - editProjector = QtCore.pyqtSignal(object) + updateProjectors = QtCore.pyqtSignal() def __init__(self, parent=None, projectordb=None): - super(ProjectorEditForm, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint | - QtCore.Qt.WindowCloseButtonHint) + self.parent = parent self.projectordb = projectordb + self.new_projector = False + super(ProjectorEditForm, self).__init__(parent, + QtCore.Qt.WindowSystemMenuHint | + QtCore.Qt.WindowTitleHint | + QtCore.Qt.WindowCloseButtonHint) self.setup_ui(self) - self.button_box.accepted.connect(self.accept_me) - self.button_box.helpRequested.connect(self.help_me) - self.button_box.rejected.connect(self.cancel_me) + self.button_box_edit.accepted.connect(self.accept_me) + self.button_box_edit.helpRequested.connect(self.help_me) + self.button_box_edit.rejected.connect(self.cancel_me) + self.button_box_view.accepted.connect(self.cancel_me) - def exec(self, projector=None): + def exec(self, projector=None, edit=True): if projector is None: self.projector = Projector() self.new_projector = True - self.ip_text_edit.setVisible(True) - self.ip_text_edit.setFocus() - self.ip_text_label.setVisible(False) else: + if not isinstance(projector, Projector): + log.warning('edit_form() Projector type not valid for this form') + log.warning(f'editform() projector type is {type(projector)}') + return Message.show_warning(Message.ProjectorInvalid) self.projector = projector self.new_projector = False - self.ip_text_edit.setVisible(False) - self.ip_text_label.setVisible(True) - # Since it's already defined, IP address is unchangeable, so focus on port number - self.port_text.setFocus() + + self.button_box_edit.setVisible(edit) + self.button_box_view.setVisible(not edit) + self.name_text.setReadOnly(not edit) + self.ip_text.setReadOnly(not edit) + self.port_text.setReadOnly(not edit) + self.pin_text.setReadOnly(not edit) + self.location_text.setReadOnly(not edit) + self.notes_text.setReadOnly(not edit) + if edit: + self.name_text.setFocus() self.retranslate_ui(self) reply = QtWidgets.QDialog.exec(self) return reply @@ -178,91 +268,80 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm): @QtCore.pyqtSlot() def accept_me(self): """ - Validate input before accepting input. + Validate inputs before accepting. """ log.debug('accept_me() signal received') - valid = True - if len(self.name_text.text().strip()) < 1: - QtWidgets.QMessageBox.warning(self, - translate('OpenLP.ProjectorEdit', 'Name Not Set'), - translate('OpenLP.ProjectorEdit', - 'You must enter a name for this entry.
' - 'Please enter a new name for this entry.')) - valid = False - return - name = self.name_text.text().strip() - record = self.projectordb.get_projector_by_name(name) - if record is not None and record.id != self.projector.id: - QtWidgets.QMessageBox.warning(self, - translate('OpenLP.ProjectorEdit', 'Duplicate Name'), - translate('OpenLP.ProjectorEdit', - 'There is already an entry with name "{name}" in ' - 'the database as ID "{record}".
' - 'Please enter a different name.'.format(name=name, - record=record.id))) - valid = False - return + + # Verify name + _name = self.name_text.text().strip() + + if len(_name) < 1: + return Message.show_warning(message=Message.NameBlank) + _record = self.projectordb.get_projector(name=_name) + if len(_record) == 0: + if self.new_projector: + if self.projector.id is not None: + log.warning(f'editform(): No record found but projector had id={self.projector.id}') + return Message.show_warning(message=Message.DatabaseError) + else: + if self.projector.name.strip() == _name: + log.warning(f'editform(): No record found when there should be name="{_name}"') + return Message.show_warning(message=Message.DatabaseError) + elif len(_record) == 1 and self.new_projector: + log.warning(f'editform(): Name "{_name}" already in database') + return Message.show_warning(message=Message.NameDuplicate) + elif len(_record) > 1: + log.warning(f'editform(): Multiple records found for name "{_name}"') + for item in _record: + log.warning(f'editform() Found record={item.id} name="{item.name}"') + return Message.show_warning(message=Message.DatabaseMultiple) + + # Verify IP address + _ip = self.ip_text.text().strip() + if len(_ip) < 1: + return Message.show_warning(message=Message.IPBlank) + elif not verify_ip_address(_ip): + return Message.show_warning(message=Message.IPInvalid) + + # Verify valid port + _port = self.port_text.text().strip() + if len(_port) < 1: + return Message.show_warning(message=Message.PortBlank) + elif not _port.isdecimal(): + return Message.show_warning(message=Message.PortInvalid) + elif int(_port) not in PJLINK_VALID_PORTS: + return Message.show_warning(message=Message.PortInvalid) + _port = int(_port) + + # Verify valid ip:port address + check = self.projectordb.get_projector(ip=_ip, port=str(_port)) + if len(check) == 1: + if self.projector.id != check[0].id: + log.warning(f'editform(): Address already in database {_ip}:{_port}') + return Message.show_warning(message=Message.AddressDuplicate) + elif len(check) > 1: + log.warning(f'editform(): Multiple records found for {_ip}:{_port}') + for chk in check: + log.warning(f'editform(): record={chk.id} name="{chk.name}" adx={chk.ip}:{chk.port}') + return Message.show_warning(message=Message.DatabaseMultiple) + + self.projector.name = _name + self.projector.ip = _ip + self.projector.port = _port + self.projector.pin = self.pin_text.text() + self.projector.location = self.location_text.text() + self.projector.notes = self.notes_text.toPlainText() + # TODO: Update calls when update_projector fixed if self.new_projector: - # Only validate a new entry - otherwise it's been previously verified - adx = self.ip_text_edit.text() - valid = verify_ip_address(adx) - if valid: - # With a valid IP - check if it's already in database so we don't duplicate - ip = self.projectordb.get_projector_by_ip(adx) - if ip is None: - valid = True - self.new_projector = True - elif ip.id != self.projector.id: - QtWidgets.QMessageBox.warning(self, - translate('OpenLP.ProjectorWizard', 'Duplicate IP Address'), - translate('OpenLP.ProjectorWizard', - 'IP address "{ip}"
is already in the database ' - 'as ID {data}.

Please Enter a different ' - 'IP address.'.format(ip=adx, data=ip.id))) - return - else: - QtWidgets.QMessageBox.warning(self, - translate('OpenLP.ProjectorWizard', 'Invalid IP Address'), - translate('OpenLP.ProjectorWizard', - 'IP address "{ip}"
is not a valid IP address.' - '

Please enter a valid IP address.'.format(ip=adx))) - valid = False - return - port = int(self.port_text.text()) - if port < 1000 or port > 32767: - QtWidgets.QMessageBox.warning(self, - translate('OpenLP.ProjectorWizard', 'Invalid Port Number'), - translate('OpenLP.ProjectorWizard', - 'Port numbers below 1000 are reserved for admin use only, ' - '
and port numbers above 32767 are not currently usable.' - '

Please enter a valid port number between ' - '1000 and 32767.

' - 'Default PJLink port is {port}'.format(port=PJLINK_PORT))) - valid = False - if valid: - if self.new_projector: - self.projector.ip = self.ip_text_edit.text() - self.projector.pin = self.pin_text.text() - self.projector.port = int(self.port_text.text()) - self.projector.name = self.name_text.text() - self.projector.location = self.location_text.text() - self.projector.notes = self.notes_text.toPlainText() - if self.new_projector: - saved = self.projectordb.add_projector(self.projector) - else: - saved = self.projectordb.update_projector(self.projector) - if not saved: - QtWidgets.QMessageBox.warning(self, - translate('OpenLP.ProjectorEditForm', 'Database Error'), - translate('OpenLP.ProjectorEditForm', - 'There was an error saving projector ' - 'information. See the log for the error')) - return saved - if self.new_projector: - self.newProjector.emit(adx) - else: - self.editProjector.emit(self.projector) - self.close() + _saved = self.projectordb.add_projector(self.projector) + else: + _saved = self.projectordb.update_projector(self.projector) + if not _saved: + return Message.show_warning(message=Message.DatabaseError) + + self.updateProjectors.emit() + self.projector = None + self.close() @QtCore.pyqtSlot() def help_me(self): diff --git a/openlp/core/projectors/manager.py b/openlp/core/projectors/manager.py index 04ece3c9e..df5643a3d 100644 --- a/openlp/core/projectors/manager.py +++ b/openlp/core/projectors/manager.py @@ -205,6 +205,11 @@ class UiProjectorManager(object): '&Edit Projector'), icon=UiIcons().edit, triggers=self.on_edit_projector) + self.view_action = create_widget_action(self.menu, + text=translate('OpenLP.ProjectorManager', + '&View Projector'), + icon=UiIcons().edit, + triggers=self.on_view_projector) self.menu.addSeparator() self.connect_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', @@ -248,6 +253,11 @@ class UiProjectorManager(object): '&Show Projector Screen'), icon=UiIcons().projector, triggers=self.on_show_projector) + self.view_action = create_widget_action(self.menu, + text=translate('OpenLP.ProjectorManager', + '&Show Projector Screen'), + icon=UiIcons().projector, + triggers=self.on_view_projector) self.menu.addSeparator() self.delete_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', @@ -321,8 +331,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM log.debug('Loading all projectors') self._load_projectors() self.projector_form = ProjectorEditForm(self, projectordb=self.projectordb) - self.projector_form.newProjector.connect(self.add_projector_from_wizard) - self.projector_form.editProjector.connect(self.edit_projector_from_wizard) + self.projector_form.updateProjectors.connect(self._load_projectors) self.projector_list_widget.itemSelectionChanged.connect(self.update_icons) def udp_listen_add(self, port=PJLINK_PORT): @@ -385,6 +394,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM log.debug(f'({projector_name}) Building menu - visible = {visible}') self.delete_action.setVisible(True) self.edit_action.setVisible(True) + self.view_action.setVisible(True) self.connect_action.setVisible(not visible) self.disconnect_action.setVisible(visible) self.status_action.setVisible(visible) @@ -687,6 +697,19 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM message += '{key}: {data}
'.format(key=key, data=STATUS_MSG[val]) QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message) + def on_view_projector(self, opt=None): + """ + Calls edit dialog as readonly with selected projector to show information + + :param opt: Needed by PyQt5 + """ + list_item = self.projector_list_widget.item(self.projector_list_widget.currentRow()) + projector = list_item.data(QtCore.Qt.UserRole) + if projector is None: + return + self.old_projector = projector + self.projector_form.exec(projector.db_item, edit=False) + def _add_projector(self, projector): """ Helper app to build a projector instance @@ -771,7 +794,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM def _load_projectors(self): """' - Load projectors - only call when initializing + Load projectors - only call when initializing or after database changes """ log.debug('_load_projectors()') self.projector_list_widget.clear() diff --git a/tests/openlp_core/projectors/commands/test_misc.py b/tests/openlp_core/projectors/commands/test_misc_commands.py similarity index 100% rename from tests/openlp_core/projectors/commands/test_misc.py rename to tests/openlp_core/projectors/commands/test_misc_commands.py diff --git a/tests/openlp_core/projectors/conftest.py b/tests/openlp_core/projectors/conftest.py index 9a42319c1..f4d162c22 100644 --- a/tests/openlp_core/projectors/conftest.py +++ b/tests/openlp_core/projectors/conftest.py @@ -27,8 +27,10 @@ from pathlib import PurePath from unittest.mock import patch from openlp.core.projectors.db import Projector, ProjectorDB +from openlp.core.projectors.editform import ProjectorEditForm from openlp.core.projectors.manager import ProjectorManager from openlp.core.projectors.pjlink import PJLink + from tests.helpers.projector import FakePJLink from tests.resources.projector.data import TEST_DB, TEST1_DATA, TEST2_DATA, TEST3_DATA @@ -118,6 +120,28 @@ def projectordb(temp_folder, settings): del proj +@pytest.fixture() +def projector_editform(projectordb): + with patch('openlp.core.projectors.editform.QtWidgets.QMessageBox') as mock_msg_box, \ + patch('openlp.core.projectors.editform.QtWidgets.QDialog') as mock_dialog_box: + _form = ProjectorEditForm(projectordb=projectordb) + _form.mock_msg_box = mock_msg_box + _form.mock_dialog_box = mock_dialog_box + yield _form + del _form + + +@pytest.fixture() +def projector_editform_mtdb(projectordb_mtdb): + with patch('openlp.core.projectors.editform.QtWidgets.QMessageBox') as mock_msg_box, \ + patch('openlp.core.projectors.editform.QtWidgets.QDialog') as mock_dialog_box: + _form = ProjectorEditForm(projectordb=projectordb_mtdb) + _form.mock_msg_box = mock_msg_box + _form.mock_dialog_box = mock_dialog_box + yield _form + del _form + + @pytest.fixture() def pjlink(): pj_link = PJLink(Projector(**TEST1_DATA), no_poll=True) diff --git a/tests/openlp_core/projectors/editform/test_accept_me.py b/tests/openlp_core/projectors/editform/test_accept_me.py new file mode 100644 index 000000000..fe2c1b612 --- /dev/null +++ b/tests/openlp_core/projectors/editform/test_accept_me.py @@ -0,0 +1,535 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# OpenLP - Open Source Lyrics Projection # +# ---------------------------------------------------------------------- # +# Copyright (c) 2008-2022 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 . # +########################################################################## +""" +Test ProjectorEditForm.accept_me +""" +import logging + +import openlp.core.projectors.db +import openlp.core.projectors.editform + +from unittest.mock import DEFAULT, patch + +from openlp.core.projectors.constants import PJLINK_VALID_PORTS +from openlp.core.projectors.db import Projector +from tests.resources.projector.data import TEST1_DATA + +_test_module = openlp.core.projectors.editform.__name__ +_test_module_db = openlp.core.projectors.db.__name__ +Message = openlp.core.projectors.editform.Message + + +def test_name_NameBlank(projector_editform_mtdb, caplog): + """ + Test when name field blank + """ + # GIVEN: Test setup + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received')] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText('') + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.NameBlank['title'], + Message.NameBlank['text'] + ) + + +def test_name_DatabaseError_id(projector_editform_mtdb, caplog): + """ + Test with mismatch ID between Projector() and DB + """ + # GIVEN: Test setup + t_id = TEST1_DATA['id'] + t_name = TEST1_DATA['name'] + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + (_test_module, logging.WARNING, + f'editform(): No record found but projector had id={t_id}')] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.projector.id = t_id + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.DatabaseError['title'], + Message.DatabaseError['text'] + ) + + +def test_name_DatabaseError_name(projector_editform_mtdb, caplog): + """ + Test with mismatch between name and DB + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + (_test_module, logging.WARNING, + f'editform(): No record found when there should be name="{t_name}"')] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.projector.name = t_name + projector_editform_mtdb.new_projector = False + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.DatabaseError['title'], + Message.DatabaseError['text'] + ) + + +def test_name_NameDuplicate(projector_editform, caplog): + """ + Test when name duplicate + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + # As long as the new record port number is different, we should be good + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + (_test_module, logging.WARNING, f'editform(): Name "{t_name}" already in database') + ] + projector_editform.exec() + projector_editform.name_text.setText(t_name) + projector_editform.projector.name = t_name + + # WHEN: Called + caplog.clear() + projector_editform.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform.mock_msg_box.warning.assert_called_once_with(None, + Message.NameDuplicate['title'], + Message.NameDuplicate['text'] + ) + + +def test_name_DatabaseMultiple(projector_editform, caplog): + """ + Test when multiple database records have the same name + """ + # GIVEN: Test setup + # Save another instance of TEST1_DATA + t_proj = Projector(**TEST1_DATA) + t_proj.id = None + projector_editform.projectordb.save_object(t_proj) + + # Test variables + t_id1 = TEST1_DATA['id'] + # There should only be 3 records in the DB, TEST[1,2,3]_DATA + # The above save_object() should have created record 4 + t_id2 = t_proj.id + t_name = TEST1_DATA['name'] + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + (_test_module, logging.WARNING, f'editform(): Multiple records found for name "{t_name}"'), + (_test_module, logging.WARNING, f'editform() Found record={t_id1} name="{t_name}"'), + (_test_module, logging.WARNING, f'editform() Found record={t_id2} name="{t_name}"') + ] + projector_editform.exec() + projector_editform.name_text.setText(t_name) + + # WHEN: Called + caplog.clear() + projector_editform.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform.mock_msg_box.warning.assert_called_once_with(None, + Message.DatabaseMultiple['title'], + Message.DatabaseMultiple['text'] + ) + + +def test_ip_IPBlank(projector_editform_mtdb, caplog): + """ + Test when IP field blank + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name')] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.ip_text.setText('') + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.IPBlank['title'], + Message.IPBlank['text'] + ) + + +def test_ip_IPInvalid(projector_editform_mtdb, caplog): + """ + Test when IP invalid + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + t_ip = 'a' + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name')] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.ip_text.setText(t_ip) + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.IPInvalid['title'], + Message.IPInvalid['text'] + ) + + +def test_port_PortBlank(projector_editform_mtdb, caplog): + """ + Test when port field blank + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + t_ip = TEST1_DATA['ip'] + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + ] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.ip_text.setText(t_ip) + projector_editform_mtdb.port_text.setText('') + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.PortBlank['title'], + Message.PortBlank['text'] + ) + + +def test_port_PortInvalid_not_decimal(projector_editform_mtdb, caplog): + """ + Test when port not a decimal digit + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + t_ip = TEST1_DATA['ip'] + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + ] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.ip_text.setText(t_ip) + projector_editform_mtdb.port_text.setText('a') + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.PortInvalid['title'], + Message.PortInvalid['text'] + ) + + +def test_port_PortInvalid_low(projector_editform_mtdb, caplog): + """ + Test when port number less than PJLINK_VALID_PORTS lower value + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + t_ip = TEST1_DATA['ip'] + t_port = PJLINK_VALID_PORTS.start - 1 + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + ] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.ip_text.setText(t_ip) + projector_editform_mtdb.port_text.setText(str(t_port)) + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.PortInvalid['title'], + Message.PortInvalid['text'] + ) + + +def test_port_PortInvalid_high(projector_editform_mtdb, caplog): + """ + Test when port number greater than PJLINK_VALID_PORTS higher value + """ + # GIVEN: Test setup + t_name = TEST1_DATA['name'] + t_ip = TEST1_DATA['ip'] + t_port = PJLINK_VALID_PORTS.stop + 1 + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + ] + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_name) + projector_editform_mtdb.ip_text.setText(t_ip) + projector_editform_mtdb.port_text.setText(str(t_port)) + + # WHEN: Called + caplog.clear() + projector_editform_mtdb.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.PortInvalid['title'], + Message.PortInvalid['text'] + ) + + +def test_adx_AddressDuplicate(projector_editform, caplog): + """ + Test when IP:Port address duplicate + """ + # GIVEN: Test setup + t_ip = TEST1_DATA['ip'] + t_port = TEST1_DATA['port'] + + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + (_test_module_db, logging.DEBUG, 'Filter by IP Port'), + (_test_module, logging.WARNING, f'editform(): Address already in database {t_ip}:{t_port}') + ] + projector_editform.exec() + projector_editform.name_text.setText('A Different Name Not In DB') + projector_editform.ip_text.setText(t_ip) + projector_editform.port_text.setText(str(t_port)) + + # WHEN: Called + caplog.clear() + projector_editform.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform.mock_msg_box.warning.assert_called_once_with(None, + Message.AddressDuplicate['title'], + Message.AddressDuplicate['text'] + ) + + +def test_adx_DatabaseMultiple(projector_editform, caplog): + """ + Test when database has multiple same IP:Port records + """ + # GIVEN: Test setup + t_proj = Projector(**TEST1_DATA) + t_proj.id = None + projector_editform.projectordb.save_object(t_proj) + t_id1 = TEST1_DATA['id'] + t_id2 = t_proj.id + t_name = TEST1_DATA['name'] + t_ip = TEST1_DATA['ip'] + t_port = TEST1_DATA['port'] + + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'accept_me() signal received'), + (_test_module_db, logging.DEBUG, 'Filter by Name'), + (_test_module_db, logging.DEBUG, 'Filter by IP Port'), + (_test_module, logging.WARNING, f'editform(): Multiple records found for {t_ip}:{t_port}'), + (_test_module, logging.WARNING, f'editform(): record={t_id1} name="{t_name}" adx={t_ip}:{t_port}'), + (_test_module, logging.WARNING, f'editform(): record={t_id2} name="{t_name}" adx={t_ip}:{t_port}') + ] + projector_editform.exec() + projector_editform.name_text.setText('A Different Name Not In DB') + projector_editform.ip_text.setText(t_ip) + projector_editform.port_text.setText(str(t_port)) + + # WHEN: Called + caplog.clear() + projector_editform.accept_me() + + # THEN: Appropriate calls made + assert caplog.record_tuples == logs, 'Invalid logs' + projector_editform.mock_msg_box.warning.assert_called_once_with(None, + Message.DatabaseMultiple['title'], + Message.DatabaseMultiple['text'] + ) + + +@patch.multiple(openlp.core.projectors.editform.ProjectorEditForm, updateProjectors=DEFAULT, close=DEFAULT) +@patch.object(openlp.core.projectors.db.ProjectorDB, 'add_projector') +def test_save_new(mock_add, projector_editform_mtdb, **kwargs): + """ + Test editform saving new projector instance where db fails to save + """ + # GIVEN: Test environment + mock_update = kwargs['updateProjectors'] + mock_close = kwargs['close'] + mock_add.return_value = True + + t_proj = Projector(**TEST1_DATA) + t_proj.id = None + projector_editform_mtdb.new_projector = True + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_proj.name) + projector_editform_mtdb.ip_text.setText(t_proj.ip) + projector_editform_mtdb.port_text.setText(str(t_proj.port)) + + # WHEN: Called + projector_editform_mtdb.accept_me() + + # THEN: appropriate message called + projector_editform_mtdb.mock_msg_box.warning.assert_not_called() + mock_update.emit.assert_called_once() + mock_close.assert_called_once() + + +@patch.multiple(openlp.core.projectors.editform.ProjectorEditForm, updateProjectors=DEFAULT, close=DEFAULT) +@patch.object(openlp.core.projectors.db.ProjectorDB, 'add_projector') +def test_save_new_fail(mock_add, projector_editform_mtdb, caplog, **kwargs): + """ + Test editform saving new projector instance where db fails to save + """ + # GIVEN: Test environment + mock_update = kwargs['updateProjectors'] + mock_close = kwargs['close'] + mock_add.return_value = False + + caplog.set_level(logging.DEBUG) + t_proj = Projector(**TEST1_DATA) + t_proj.id = None + projector_editform_mtdb.new_projector = True + projector_editform_mtdb.exec() + projector_editform_mtdb.name_text.setText(t_proj.name) + projector_editform_mtdb.ip_text.setText(t_proj.ip) + projector_editform_mtdb.port_text.setText(str(t_proj.port)) + + # WHEN: Called + projector_editform_mtdb.accept_me() + + # THEN: appropriate message called + mock_add.assert_called_once_with(projector_editform_mtdb.projector) + projector_editform_mtdb.mock_msg_box.warning.assert_called_once_with(None, + Message.DatabaseError['title'], + Message.DatabaseError['text'] + ) + mock_update.assert_not_called() + mock_close.assert_not_called() + + +@patch.multiple(openlp.core.projectors.editform.ProjectorEditForm, updateProjectors=DEFAULT, close=DEFAULT) +@patch.object(openlp.core.projectors.db.ProjectorDB, 'update_projector') +def test_save_update(mock_add, projector_editform, **kwargs): + """ + Test editform update projector instance in database + """ + # GIVEN: Test environment + mock_update = kwargs['updateProjectors'] + mock_close = kwargs['close'] + mock_add.return_value = True + + t_proj = Projector(**TEST1_DATA) + projector_editform.new_projector = True + projector_editform.exec(projector=t_proj) + projector_editform.name_text.setText(t_proj.name) + projector_editform.ip_text.setText(t_proj.ip) + projector_editform.port_text.setText(str(t_proj.port)) + + # WHEN: Called + projector_editform.accept_me() + + # THEN: appropriate message called + projector_editform.mock_msg_box.warning.assert_not_called() + mock_update.emit.assert_called_once() + mock_close.assert_called_once() + + +@patch.multiple(openlp.core.projectors.editform.ProjectorEditForm, updateProjectors=DEFAULT, close=DEFAULT) +@patch.object(openlp.core.projectors.db.ProjectorDB, 'update_projector') +def test_save_update_fail(mock_add, projector_editform, caplog, **kwargs): + """ + Test editform updating projector instance where db fails to save + """ + # GIVEN: Test environment + mock_update = kwargs['updateProjectors'] + mock_close = kwargs['close'] + mock_add.return_value = False + + caplog.set_level(logging.DEBUG) + t_proj = Projector(**TEST1_DATA) + projector_editform.exec(projector=t_proj) + projector_editform.name_text.setText(t_proj.name) + projector_editform.ip_text.setText(t_proj.ip) + projector_editform.port_text.setText(str(t_proj.port)) + + # WHEN: Called + projector_editform.accept_me() + + # THEN: appropriate message called + mock_add.assert_called_once_with(projector_editform.projector) + projector_editform.mock_msg_box.warning.assert_called_once_with(None, + Message.DatabaseError['title'], + Message.DatabaseError['text'] + ) + mock_update.assert_not_called() + mock_close.assert_not_called() diff --git a/tests/openlp_core/projectors/editform/test_misc_editform.py b/tests/openlp_core/projectors/editform/test_misc_editform.py new file mode 100644 index 000000000..a6b9d1cbc --- /dev/null +++ b/tests/openlp_core/projectors/editform/test_misc_editform.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# OpenLP - Open Source Lyrics Projection # +# ---------------------------------------------------------------------- # +# Copyright (c) 2008-2022 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 . # +########################################################################## +""" +Test ProjectorEditForm methods that don't have many paths/options +""" + +import logging +import openlp.core.projectors.editform +import openlp.core.projectors.db + +from unittest.mock import patch +from tests.resources.projector.data import TEST1_DATA, TEST2_DATA + +_test_module = openlp.core.projectors.editform.__name__ +_test_module_db = openlp.core.projectors.db.__name__ + +Message = openlp.core.projectors.editform.Message +Projector = openlp.core.projectors.db.Projector +ProjectorEditForm = openlp.core.projectors.editform.ProjectorEditForm + + +def test_exec_projector_bad(projector_editform, caplog): + """ + Test projector edit form with bad projector + """ + # GIVEN: Mocked setup + t_chk_item = str() + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.WARNING, 'edit_form() Projector type not valid for this form'), + (_test_module, logging.WARNING, f'editform() projector type is {type(t_chk_item)}') + ] + + # WHEN: Calling edit form with existing projector instance + projector_editform.exec(projector=t_chk_item) + + # THEN: Appropriate calls and log entries + assert caplog.record_tuples == logs, 'Invalid log entries' + assert projector_editform.new_projector is False, 'new_projector should not have changed' + projector_editform.mock_dialog_box.exec.assert_not_called() + projector_editform.mock_msg_box.warning.assert_called_with(None, + Message.ProjectorInvalid['title'], + Message.ProjectorInvalid['text'] + ) + + # TODO: Check signals for QDialogButtonBox (projector_editform.button_box_edit/button_box_view) + + +def test_exec_projector_edit(projector_editform, caplog): + """ + Test projector edit form with existing projector entry + + :return: + """ + # GIVEN: Mocked setup + caplog.set_level(logging.DEBUG) + logs = [(_test_module_db, logging.DEBUG, 'Filter by ID')] + + t_chk_db = projector_editform.projectordb.get_projector(id=TEST2_DATA['id'])[0] + projector_editform.new_projector = False + projector_editform.projector = None + + # WHEN: Calling edit form with existing projector instance + projector_editform.exec(projector=Projector(**TEST2_DATA)) + + # THEN: Should be editing an existing entry + assert caplog.record_tuples == logs, 'Invalid log entries' + assert projector_editform.new_projector is False, 'Projector edit form should be marked as existing entry' + assert projector_editform.projector == t_chk_db, 'Entries should match' + projector_editform.mock_msg_box.assert_not_called() + # TODO: Check signals for QDialogButtonBox (projector_editform.button_box_edit/button_box_view) + + +def test_exec_projector_new(projector_editform_mtdb, caplog): + """ + Test projector edit form with existing projector entry + + :return: + """ + # GIVEN: Mocked setup + caplog.set_level(logging.DEBUG) + logs = [] + projector_editform_mtdb.new_projector = False + projector_editform_mtdb.projector = Projector(**TEST1_DATA) + + # WHEN: Calling edit form with existing projector instance + projector_editform_mtdb.exec() + t_chk_item = projector_editform_mtdb.projector + + # THEN: Should be editing an existing entry + assert caplog.record_tuples == logs, 'Invalid log entries' + assert projector_editform_mtdb.new_projector is True, 'Projector edit form should be marked as a new entry' + assert isinstance(t_chk_item, Projector) + assert t_chk_item.id is None, 'ID should have indicated new entry' + assert t_chk_item.name is None, 'Name should have indicated new entry' + assert t_chk_item.ip is None, 'IP should have indicated new entry' + # TODO: Check signals for QDialogButtonBox (projector_editform.button_box_edit/button_box_view) + + +def test_cancel_me(projector_editform_mtdb, caplog): + """ + Test cancel_me logs and calls close + """ + # GIVEN: Test setup + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'cancel_me() signal received')] + + with patch.object(projector_editform_mtdb, 'close') as mock_close: + # WHEN: Called + projector_editform_mtdb.cancel_me() + + # THEN: Appropriate log entries made + assert caplog.record_tuples == logs, 'Invalid log entries' + mock_close.assert_called_once() + + +def test_help_me(projector_editform_mtdb, caplog): + """ + TODO: Expand method, then expand test + """ + # GIVEN: Test setup + caplog.set_level(logging.DEBUG) + logs = [(_test_module, logging.DEBUG, 'help_me() signal received')] + + # WHEN: Called + projector_editform_mtdb.help_me() + + # THEN: Appropriate log entries made + assert caplog.record_tuples == logs, 'Invalid log entries' diff --git a/tests/openlp_core/projectors/manager/test_boostrap.py b/tests/openlp_core/projectors/manager/test_boostrap.py index 284e686d8..b75790322 100644 --- a/tests/openlp_core/projectors/manager/test_boostrap.py +++ b/tests/openlp_core/projectors/manager/test_boostrap.py @@ -87,11 +87,9 @@ def test_bootstrap_post_set_up_autostart_false(mock_timer, mocked_edit, projecto caplog.set_level(logging.DEBUG) logs = [(test_module, logging.DEBUG, 'Loading all projectors')] - mock_newProjector = MagicMock() - mock_editProjector = MagicMock() + mock_updateProjectors = MagicMock() mock_edit = MagicMock() - mock_edit.newProjector = mock_newProjector - mock_edit.editProjector = mock_editProjector + mock_edit.updateProjectors = mock_updateProjectors mocked_edit.return_value = mock_edit settings.setValue('projector/connect on start', False) @@ -107,8 +105,7 @@ def test_bootstrap_post_set_up_autostart_false(mock_timer, mocked_edit, projecto # THEN: verify calls and logs mock_timer.assert_not_called() - mock_newProjector.connect.assert_called_once() - mock_editProjector.connect.assert_called_once() + mock_updateProjectors.connect.assert_called_once() mock_manager['_load_projectors'].assert_called_once(), mock_manager['projector_list_widget'].itemSelectionChanged.connect.assert_called_once() assert caplog.record_tuples == logs, 'Invalid log entries' @@ -124,11 +121,9 @@ def test_bootstrap_post_set_up_autostart_true(mock_timer, mocked_edit, projector caplog.set_level(logging.DEBUG) logs = [(test_module, logging.DEBUG, 'Delaying 1.5 seconds before loading all projectors')] - mock_newProjector = MagicMock() - mock_editProjector = MagicMock() + mock_updateProjectors = MagicMock() mock_edit = MagicMock() - mock_edit.newProjector = mock_newProjector - mock_edit.editProjector = mock_editProjector + mock_edit.updateProjectors = mock_updateProjectors settings.setValue('projector/connect on start', True) projector_manager.bootstrap_initialise() @@ -146,8 +141,7 @@ def test_bootstrap_post_set_up_autostart_true(mock_timer, mocked_edit, projector mock_timer.assert_called_once() mock_timer.return_value.singleShot.assert_called_once_with(1500, projector_manager._load_projectors) - mock_newProjector.connect.assert_called_once() - mock_editProjector.connect.assert_called_once() + mock_updateProjectors.connect.assert_called_once() mock_manager['_load_projectors'].assert_not_called(), mock_manager['projector_list_widget'].itemSelectionChanged.connect.assert_called_once() assert caplog.record_tuples == logs, 'Invalid log entries' diff --git a/tests/openlp_core/projectors/test_projector_editform.py b/tests/openlp_core/projectors/test_projector_editform.py deleted file mode 100644 index c27aee346..000000000 --- a/tests/openlp_core/projectors/test_projector_editform.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- - -########################################################################## -# OpenLP - Open Source Lyrics Projection # -# ---------------------------------------------------------------------- # -# Copyright (c) 2008-2022 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 . # -########################################################################## -""" -Interface tests to test the openlp.core.projectors.editform.ProjectorEditForm() -class and methods. -""" -import pytest -from unittest.mock import patch - -from openlp.core.projectors.db import Projector, ProjectorDB -from openlp.core.projectors.editform import ProjectorEditForm -from tests.resources.projector.data import TEST1_DATA, TEST_DB - - -@pytest.fixture() -def projector_form(settings): - with patch('openlp.core.projectors.db.init_url') as mocked_init_url: - mocked_init_url.return_value = 'sqlite:///' + TEST_DB - projectordb = ProjectorDB() - projector_frm = ProjectorEditForm(projectordb=projectordb) - yield projector_frm - projectordb.session.close() - del projector_frm - - -@patch('openlp.core.projectors.editform.QtWidgets.QDialog.exec') -def test_edit_form_add_projector(mocked_exec, projector_form): - """ - Test projector edit form with no parameters creates a new entry. - - :return: None - """ - # GIVEN: Mocked setup - # WHEN: Calling edit form with no parameters - projector_form.exec() - item = projector_form.projector - - # THEN: Should be creating a new instance - assert projector_form.new_projector, 'Projector edit form should be marked as a new entry' - assert (item.ip is None and item.name is None), 'Projector edit form should have a new Projector() instance to edit' - - -@patch('openlp.core.projectors.editform.QtWidgets.QDialog.exec') -def test_edit_form_edit_projector(mocked_exec, projector_form): - """ - Test projector edit form with existing projector entry - - :return: - """ - # GIVEN: Mocked setup - # WHEN: Calling edit form with existing projector instance - projector_form.exec(projector=Projector(**TEST1_DATA)) - item = projector_form.projector - - # THEN: Should be editing an existing entry - assert projector_form.new_projector is False, 'Projector edit form should be marked as existing entry' - assert item.ip is TEST1_DATA['ip'] and item.name is TEST1_DATA['name'], \ - 'Projector edit form should have TEST1_DATA() instance to edit'