diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index bbf2ccc64..ce06b3625 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -58,7 +58,7 @@ SocketSTate = QAbstractSocket.SocketState PJLINK_PREFIX = '%' PJLINK_CLASS = '1' -PJLINK_HEADER = '%s%s' % (PJLINK_PREFIX, PJLINK_CLASS) +PJLINK_HEADER = '{prefix}{linkclass}'.format(prefix=PJLINK_PREFIX, linkclass=PJLINK_CLASS) PJLINK_SUFFIX = CR @@ -160,8 +160,10 @@ class PJLink1(QTcpSocket): self.source = None self.other_info = None if hasattr(self, 'timer'): + log.debug('({ip}): Calling timer.stop()'.format(ip=self.ip)) self.timer.stop() if hasattr(self, 'socket_timer'): + log.debug('({ip}): Calling socket_timer.stop()'.format(ip=self.ip)) self.socket_timer.stop() self.send_queue = [] self.send_busy = False diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 8edf9775f..541c139c7 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -81,9 +81,10 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP ) return check_directory_exists(path) - file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % \ - (self.from_date_calendar.selectedDate().toString('ddMMyyyy'), - self.to_date_calendar.selectedDate().toString('ddMMyyyy')) + file_name = translate('SongUsagePlugin.SongUsageDetailForm', + 'usage_detail_{old}_{new}.txt' + ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'), + new=self.to_date_calendar.selectedDate().toString('ddMMyyyy')) Settings().setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate()) Settings().setValue(self.plugin.settings_section + '/to date', self.to_date_calendar.selectedDate()) usage = self.plugin.manager.get_all_objects( @@ -95,21 +96,23 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP try: file_handle = open(report_file_name, 'wb') for instance in usage: - record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \ - '\"%s\",\"%s\"\n' % \ - (instance.usagedate, instance.usagetime, instance.title, instance.copyright, - instance.ccl_number, instance.authors, instance.plugin_name, instance.source) + record = ('\"{date}\",\"{time}\",\"{title}\",\"{copyright}\",\"{ccli}\",\"{authors}\",' + '\"{name}\",\"{source}\"\n').format(date=instance.usagedate, time=instance.usagetime, + title=instance.title, copyright=instance.copyright, + ccli=instance.ccl_number, authors=instance.authors, + name=instance.plugin_name, source=instance.source) file_handle.write(record.encode('utf-8')) self.main_window.information_message( translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'), translate('SongUsagePlugin.SongUsageDetailForm', - 'Report \n%s \nhas been successfully created. ') % report_file_name + 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name) ) except OSError as ose: log.exception('Failed to write out song usage records') critical_error_message_box(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation Failed'), translate('SongUsagePlugin.SongUsageDetailForm', - 'An error occurred while creating the report: %s') % ose.strerror) + 'An error occurred while creating the report: {error}' + ).format(error=ose.strerror)) finally: if file_handle: file_handle.close() diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index ac1059656..45dbde093 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -34,6 +34,18 @@ from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUT pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True) +class DummyTimer(object): + ''' + Dummy class to fake timers + ''' + def __init__(self, *args, **kwargs): + pass + + def start(self, *args, **kwargs): + pass + + def stop(self, *args, **kwargs): + pass class TestPJLink(TestCase): """ @@ -43,13 +55,10 @@ class TestPJLink(TestCase): @patch.object(pjlink_test, 'send_command') @patch.object(pjlink_test, 'waitForReadyRead') @patch('openlp.core.common.qmd5_hash') - def authenticated_connection_call_test(self, - mock_qmd5_hash, - mock_waitForReadyRead, - mock_send_command, + def authenticated_connection_call_test(self, mock_qmd5_hash, mock_waitForReadyRead, mock_send_command, mock_readyRead): """ - Fix for projector connect with PJLink authentication exception. Ticket 92187. + Ticket 92187: Fix for projector connect with PJLink authentication exception. """ # GIVEN: Test object pjlink = pjlink_test @@ -63,9 +72,23 @@ class TestPJLink(TestCase): self.assertTrue(mock_qmd5_hash.called_with(TEST_PIN, "Connection request should have been called with TEST_PIN")) + def projector_class_test(self): + """ + Test class version from projector + """ + # GIVEN: Test object + pjlink = pjlink_test + + # WHEN: Process class response + pjlink.process_clss('1') + + # THEN: Projector class should be set to 1 + self.assertEquals(pjlink.pjlink_class, '1', + 'Projector should have returned class=1') + def non_standard_class_reply_test(self): """ - bugfix 1550891 - CLSS request returns non-standard 'Class N' reply + Bugfix 1550891: CLSS request returns non-standard 'Class N' reply """ # GIVEN: Test object pjlink = pjlink_test @@ -264,3 +287,46 @@ class TestPJLink(TestCase): # THEN: Input selected should reflect current input self.assertEquals(pjlink.source, '1', 'Input source should be set to "1"') + + def projector_reset_information_test(self): + """ + Test reset_information() resets all information and stops timers + """ + # GIVEN: Test object and test data + pjlink = pjlink_test + pjlink.power = S_ON + pjlink.pjlink_name = 'OPENLPTEST' + pjlink.manufacturer = 'PJLINK' + pjlink.model = '1' + pjlink.shutter = True + pjlink.mute = True + pjlink.lamp = True + pjlink.fan = True + pjlink.source_available = True + pjlink.other_info = 'ANOTHER TEST' + pjlink.send_queue = True + pjlink.send_busy = True + pjlink.timer = DummyTimer() + pjlink.socket_timer = DummyTimer() + + # WHEN: reset_information() is called + with patch.object(pjlink.timer, 'stop') as mock_timer: + with patch.object(pjlink.socket_timer, 'stop') as mock_socket_timer: + pjlink.reset_information() + + # THEN: All information should be reset and timers stopped + self.assertEquals(pjlink.power, S_OFF, 'Projector power should be OFF') + self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None') + self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None') + self.assertIsNone(pjlink.model, 'Projector model should be None') + self.assertIsNone(pjlink.shutter, 'Projector shutter should be None') + self.assertIsNone(pjlink.mute, 'Projector shuttter should be None') + self.assertIsNone(pjlink.lamp, 'Projector lamp should be None') + self.assertIsNone(pjlink.fan, 'Projector fan should be None') + self.assertIsNone(pjlink.source_available, 'Projector source_available should be None') + self.assertIsNone(pjlink.source, 'Projector source should be None') + self.assertIsNone(pjlink.other_info, 'Projector other_info should be None') + self.assertEquals(pjlink.send_queue, [], 'Projector send_queue should be an empty list') + self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False') + self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called') + self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called')