Merge lp:~alisonken1/openlp/pjlink2-i into lp:openlp

Proposed by Ken Roberts
Status: Merged
Approved by: Raoul Snyman
Approved revision: 2760
Merged at revision: 2760
Proposed branch: lp:~alisonken1/openlp/pjlink2-i
Merge into: lp:openlp
Diff against target: 1078 lines (+690/-117)
3 files modified
openlp/core/lib/projector/pjlink.py (+45/-35)
tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py (+1/-1)
tests/functional/openlp_core_lib/test_projector_pjlink_commands.py (+644/-81)
To merge this branch: bzr merge lp:~alisonken1/openlp/pjlink2-i
Reviewer Review Type Date Requested Status
Raoul Snyman Approve
Tomas Groth Approve
Tim Bentley Pending
Review via email: mp+328951@code.launchpad.net

This proposal supersedes a proposal from 2017-08-12.

Commit message

PJLink2 update I

Description of the change

More minor code cleanups

- Renamed get_shutter_status to get_av_mute_status (checks shutter and audio)
- Renamed shutter/audio mute test
- Update socket read to get 1K bytes in buffer
- Updated get_status for valid input
- Updated process_sver check valid length
- Update change_status to not use NETWORK_SENDING as a connection status check
- Added read check for packet length > allowed max
- Added test for process_inf1
- Added test for process_inf2
- Added test for process_info
- Added test for process_inst
- Added test for process_lamp with invalid data
- Update tests for process_powr
- Added test for process_powr_invalid
- Added tests for process_sver
- Added tests for change_status
- Added test for get_av_mute_status
- Added test for get_available_inputs
- Added test for get_error_status
- Added test for get_input_source
- Added test for get_lamp_status
- Added test for get_manufacturer
- Added test for get_model
- Added test for get_name
- Added test for get_other_info
- Added test for get_power_status
- Added tests for get_status
- Added test for process_inf1
- Added test for get_process_inf2
- Added test for get_process_info
- Added test for reset_information
- Fix deprecated log calls

--------------------------------
lp:~alisonken1/openlp/pjlink2-i (revision 2760)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2162/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2067/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1955/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1328/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1166/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/296/
[FAILURE] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/141/

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

See inline

review: Needs Fixing
Revision history for this message
Tomas Groth (tomasgroth) wrote :

Looks ok to me.

review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/lib/projector/pjlink.py'
2--- openlp/core/lib/projector/pjlink.py 2017-08-11 11:04:33 +0000
3+++ openlp/core/lib/projector/pjlink.py 2017-08-12 21:17:39 +0000
4@@ -57,7 +57,7 @@
5 E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, E_OK, \
6 E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, PJLINK_ERST_DATA, \
7 PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_POWR_STATUS, PJLINK_VALID_CMD, \
8- STATUS_STRING, S_CONNECTED, S_CONNECTING, S_NETWORK_RECEIVED, S_NETWORK_SENDING, \
9+ STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NETWORK_RECEIVED, S_NETWORK_SENDING, \
10 S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS
11
12 # Shortcuts
13@@ -159,7 +159,7 @@
14 # A command returned successfully, no further processing needed
15 return
16 elif _cmd not in self.pjlink_functions:
17- log.warn("({ip}) Unable to process command='{cmd}' (Future option)".format(ip=self.ip, cmd=cmd))
18+ log.warning("({ip}) Unable to process command='{cmd}' (Future option)".format(ip=self.ip, cmd=cmd))
19 return
20 elif _data in PJLINK_ERRORS:
21 # Oops - projector error
22@@ -231,7 +231,7 @@
23 # : Received: '%1CLSS=Class 1' (Optoma)
24 # : Received: '%1CLSS=Version1' (BenQ)
25 if len(data) > 1:
26- log.warn("({ip}) Non-standard CLSS reply: '{data}'".format(ip=self.ip, data=data))
27+ log.warning("({ip}) Non-standard CLSS reply: '{data}'".format(ip=self.ip, data=data))
28 # Due to stupid projectors not following standards (Optoma, BenQ comes to mind),
29 # AND the different responses that can be received, the semi-permanent way to
30 # fix the class reply is to just remove all non-digit characters.
31@@ -261,15 +261,15 @@
32 """
33 if len(data) != PJLINK_ERST_DATA['DATA_LENGTH']:
34 count = PJLINK_ERST_DATA['DATA_LENGTH']
35- log.warn("{ip}) Invalid error status response '{data}': length != {count}".format(ip=self.ip,
36- data=data,
37- count=count))
38+ log.warning("{ip}) Invalid error status response '{data}': length != {count}".format(ip=self.ip,
39+ data=data,
40+ count=count))
41 return
42 try:
43 datacheck = int(data)
44 except ValueError:
45 # Bad data - ignore
46- log.warn("({ip}) Invalid error status response '{data}'".format(ip=self.ip, data=data))
47+ log.warning("({ip}) Invalid error status response '{data}'".format(ip=self.ip, data=data))
48 return
49 if datacheck == 0:
50 self.projector_errors = None
51@@ -429,9 +429,9 @@
52 if self.model_filter is None:
53 self.model_filter = data
54 else:
55- log.warn("({ip}) Filter model already set".format(ip=self.ip))
56- log.warn("({ip}) Saved model: '{old}'".format(ip=self.ip, old=self.model_filter))
57- log.warn("({ip}) New model: '{new}'".format(ip=self.ip, new=data))
58+ log.warning("({ip}) Filter model already set".format(ip=self.ip))
59+ log.warning("({ip}) Saved model: '{old}'".format(ip=self.ip, old=self.model_filter))
60+ log.warning("({ip}) New model: '{new}'".format(ip=self.ip, new=data))
61
62 def process_rlmp(self, data):
63 """
64@@ -440,9 +440,9 @@
65 if self.model_lamp is None:
66 self.model_lamp = data
67 else:
68- log.warn("({ip}) Lamp model already set".format(ip=self.ip))
69- log.warn("({ip}) Saved lamp: '{old}'".format(ip=self.ip, old=self.model_lamp))
70- log.warn("({ip}) New lamp: '{new}'".format(ip=self.ip, new=data))
71+ log.warning("({ip}) Lamp model already set".format(ip=self.ip))
72+ log.warning("({ip}) Saved lamp: '{old}'".format(ip=self.ip, old=self.model_lamp))
73+ log.warning("({ip}) New lamp: '{new}'".format(ip=self.ip, new=data))
74
75 def process_snum(self, data):
76 """
77@@ -457,27 +457,32 @@
78 else:
79 # Compare serial numbers and see if we got the same projector
80 if self.serial_no != data:
81- log.warn("({ip}) Projector serial number does not match saved serial number".format(ip=self.ip))
82- log.warn("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.serial_no))
83- log.warn("({ip}) Received: '{new}'".format(ip=self.ip, new=data))
84- log.warn("({ip}) NOT saving serial number".format(ip=self.ip))
85+ log.warning("({ip}) Projector serial number does not match saved serial number".format(ip=self.ip))
86+ log.warning("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.serial_no))
87+ log.warning("({ip}) Received: '{new}'".format(ip=self.ip, new=data))
88+ log.warning("({ip}) NOT saving serial number".format(ip=self.ip))
89 self.serial_no_received = data
90
91 def process_sver(self, data):
92 """
93 Software version of projector
94 """
95- if self.sw_version is None:
96+ if len(data) > 32:
97+ # Defined in specs max version is 32 characters
98+ log.warning("Invalid software version - too long")
99+ return
100+ elif self.sw_version is None:
101 log.debug("({ip}) Setting projector software version to '{data}'".format(ip=self.ip, data=data))
102 self.sw_version = data
103 self.db_update = True
104 else:
105 # Compare software version and see if we got the same projector
106 if self.serial_no != data:
107- log.warn("({ip}) Projector software version does not match saved software version".format(ip=self.ip))
108- log.warn("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.sw_version))
109- log.warn("({ip}) Received: '{new}'".format(ip=self.ip, new=data))
110- log.warn("({ip}) NOT saving serial number".format(ip=self.ip))
111+ log.warning("({ip}) Projector software version does not match saved "
112+ "software version".format(ip=self.ip))
113+ log.warning("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.sw_version))
114+ log.warning("({ip}) Received: '{new}'".format(ip=self.ip, new=data))
115+ log.warning("({ip}) Saving new serial number as sw_version_received".format(ip=self.ip))
116 self.sw_version_received = data
117
118
119@@ -605,7 +610,7 @@
120 Normally called by timer().
121 """
122 if self.state() != self.ConnectedState:
123- log.warn("({ip}) poll_loop(): Not connected - returning".format(ip=self.ip))
124+ log.warning("({ip}) poll_loop(): Not connected - returning".format(ip=self.ip))
125 return
126 log.debug('({ip}) Updating projector status'.format(ip=self.ip))
127 # Reset timer in case we were called from a set command
128@@ -649,7 +654,9 @@
129 :param status: Status/Error code
130 :returns: (Status/Error code, String)
131 """
132- if status in ERROR_STRING:
133+ if not isinstance(status, int):
134+ return -1, 'Invalid status code'
135+ elif status in ERROR_STRING:
136 return ERROR_STRING[status], ERROR_MSG[status]
137 elif status in STATUS_STRING:
138 return STATUS_STRING[status], ERROR_MSG[status]
139@@ -674,7 +681,7 @@
140 elif status >= S_NOT_CONNECTED and status < S_STATUS:
141 self.status_connect = status
142 self.projector_status = S_NOT_CONNECTED
143- elif status < S_NETWORK_SENDING:
144+ elif status <= S_INFO:
145 self.status_connect = S_CONNECTED
146 self.projector_status = status
147 (status_code, status_message) = self._get_status(self.status_connect)
148@@ -803,7 +810,8 @@
149 log.debug('({ip}) get_data(): Not connected - returning'.format(ip=self.ip))
150 self.send_busy = False
151 return
152- read = self.readLine(self.max_size)
153+ # Although we have a packet length limit, go ahead and use a larger buffer
154+ read = self.readLine(1024)
155 log.debug("({ip}) get_data(): '{buff}'".format(ip=self.ip, buff=read))
156 if read == -1:
157 # No data available
158@@ -816,6 +824,8 @@
159 data = data_in.strip()
160 if (len(data) < 7) or (not data.startswith(PJLINK_PREFIX)):
161 return self._trash_buffer(msg='get_data(): Invalid packet - length or prefix')
162+ elif len(data) > self.max_size:
163+ return self._trash_buffer(msg='get_data(): Invalid packet - too long')
164 elif '=' not in data:
165 return self._trash_buffer(msg='get_data(): Invalid packet does not have equal')
166 log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))
167@@ -830,8 +840,8 @@
168 log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
169 return self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
170 if int(self.pjlink_class) < int(version):
171- log.warn('({ip}) get_data(): Projector returned class reply higher '
172- 'than projector stated class'.format(ip=self.ip))
173+ log.warning('({ip}) get_data(): Projector returned class reply higher '
174+ 'than projector stated class'.format(ip=self.ip))
175 return self.process_command(cmd, data)
176
177 @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
178@@ -993,6 +1003,13 @@
179 self.reset_information()
180 self.projectorUpdateIcons.emit()
181
182+ def get_av_mute_status(self):
183+ """
184+ Send command to retrieve shutter status.
185+ """
186+ log.debug('({ip}) Sending AVMT command'.format(ip=self.ip))
187+ return self.send_command(cmd='AVMT')
188+
189 def get_available_inputs(self):
190 """
191 Send command to retrieve available source inputs.
192@@ -1056,13 +1073,6 @@
193 log.debug('({ip}) Sending POWR command'.format(ip=self.ip))
194 return self.send_command(cmd='POWR')
195
196- def get_shutter_status(self):
197- """
198- Send command to retrieve shutter status.
199- """
200- log.debug('({ip}) Sending AVMT command'.format(ip=self.ip))
201- return self.send_command(cmd='AVMT')
202-
203 def set_input_source(self, src=None):
204 """
205 Verify input source available as listed in 'INST' command,
206
207=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py'
208--- tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py 2017-08-11 11:04:33 +0000
209+++ tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py 2017-08-12 21:17:39 +0000
210@@ -179,7 +179,7 @@
211
212 # THEN: Error should be logged and no command called
213 self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')
214- mock_log.warn.assert_called_once_with(log_text)
215+ mock_log.warning.assert_called_once_with(log_text)
216
217 @patch.object(pjlink_test, 'pjlink_functions')
218 @patch.object(openlp.core.lib.projector.pjlink, 'log')
219
220=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink_commands.py'
221--- tests/functional/openlp_core_lib/test_projector_pjlink_commands.py 2017-08-11 11:04:33 +0000
222+++ tests/functional/openlp_core_lib/test_projector_pjlink_commands.py 2017-08-12 21:17:39 +0000
223@@ -23,12 +23,14 @@
224 Package to test the openlp.core.lib.projector.pjlink commands package.
225 """
226 from unittest import TestCase
227-from unittest.mock import patch, MagicMock
228+from unittest.mock import patch
229
230 import openlp.core.lib.projector.pjlink
231 from openlp.core.lib.projector.pjlink import PJLink
232 from openlp.core.lib.projector.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \
233- PJLINK_POWR_STATUS, E_WARN, E_ERROR, S_OFF, S_STANDBY, S_ON
234+ PJLINK_POWR_STATUS, \
235+ E_ERROR, E_NOT_CONNECTED, E_SOCKET_ADDRESS_NOT_AVAILABLE, E_UNKNOWN_SOCKET_ERROR, E_WARN, \
236+ S_CONNECTED, S_OFF, S_ON, S_NOT_CONNECTED, S_CONNECTING, S_STANDBY
237
238 from tests.resources.projector.data import TEST_PIN
239
240@@ -45,48 +47,408 @@
241 """
242 Tests for the PJLink module
243 """
244- def test_projector_reset_information(self):
245- """
246- Test reset_information() resets all information and stops timers
247- """
248- # GIVEN: Test object and test data
249- pjlink = pjlink_test
250- pjlink.power = S_ON
251- pjlink.pjlink_name = 'OPENLPTEST'
252- pjlink.manufacturer = 'PJLINK'
253- pjlink.model = '1'
254- pjlink.shutter = True
255- pjlink.mute = True
256- pjlink.lamp = True
257- pjlink.fan = True
258- pjlink.source_available = True
259- pjlink.other_info = 'ANOTHER TEST'
260- pjlink.send_queue = True
261- pjlink.send_busy = True
262- pjlink.timer = MagicMock()
263- pjlink.socket_timer = MagicMock()
264-
265- # WHEN: reset_information() is called
266- with patch.object(pjlink.timer, 'stop') as mock_timer:
267- with patch.object(pjlink.socket_timer, 'stop') as mock_socket_timer:
268- pjlink.reset_information()
269-
270- # THEN: All information should be reset and timers stopped
271- self.assertEqual(pjlink.power, S_OFF, 'Projector power should be OFF')
272- self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None')
273- self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None')
274- self.assertIsNone(pjlink.model, 'Projector model should be None')
275- self.assertIsNone(pjlink.shutter, 'Projector shutter should be None')
276- self.assertIsNone(pjlink.mute, 'Projector shuttter should be None')
277- self.assertIsNone(pjlink.lamp, 'Projector lamp should be None')
278- self.assertIsNone(pjlink.fan, 'Projector fan should be None')
279- self.assertIsNone(pjlink.source_available, 'Projector source_available should be None')
280- self.assertIsNone(pjlink.source, 'Projector source should be None')
281- self.assertIsNone(pjlink.other_info, 'Projector other_info should be None')
282- self.assertEqual(pjlink.send_queue, [], 'Projector send_queue should be an empty list')
283- self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
284- self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called')
285- self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called')
286+ @patch.object(pjlink_test, 'changeStatus')
287+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
288+ def test_projector_change_status_connection_error(self, mock_log, mock_change_status):
289+ """
290+ Test change_status with connection error
291+ """
292+ # GIVEN: Test object
293+ pjlink = pjlink_test
294+ pjlink.projector_status = 0
295+ pjlink.status_connect = 0
296+ test_code = E_UNKNOWN_SOCKET_ERROR
297+ mock_change_status.reset_mock()
298+ mock_log.reset_mock()
299+
300+ # WHEN: change_status called with unknown socket error
301+ pjlink.change_status(status=test_code, msg=None)
302+
303+ # THEN: Proper settings should change and signals sent
304+ self.assertEqual(pjlink.projector_status, E_NOT_CONNECTED, 'Projector status should be NOT CONNECTED')
305+ self.assertEqual(pjlink.status_connect, E_NOT_CONNECTED, 'Status connect should be NOT CONNECTED')
306+ mock_change_status.emit.assert_called_once_with(pjlink.ip, E_UNKNOWN_SOCKET_ERROR,
307+ 'An unidentified error occurred')
308+ self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
309+
310+ @patch.object(pjlink_test, 'changeStatus')
311+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
312+ def test_projector_change_status_connection_status_connecting(self, mock_log, mock_change_status):
313+ """
314+ Test change_status with connection status
315+ """
316+ # GIVEN: Test object
317+ pjlink = pjlink_test
318+ pjlink.projector_status = 0
319+ pjlink.status_connect = 0
320+ test_code = S_CONNECTING
321+ mock_change_status.reset_mock()
322+ mock_log.reset_mock()
323+
324+ # WHEN: change_status called with unknown socket error
325+ pjlink.change_status(status=test_code, msg=None)
326+
327+ # THEN: Proper settings should change and signals sent
328+ self.assertEqual(pjlink.projector_status, S_NOT_CONNECTED, 'Projector status should be NOT CONNECTED')
329+ self.assertEqual(pjlink.status_connect, S_CONNECTING, 'Status connect should be CONNECTING')
330+ mock_change_status.emit.assert_called_once_with(pjlink.ip, S_CONNECTING, 'Connecting')
331+ self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
332+
333+ @patch.object(pjlink_test, 'changeStatus')
334+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
335+ def test_projector_change_status_connection_status_connected(self, mock_log, mock_change_status):
336+ """
337+ Test change_status with connection status
338+ """
339+ # GIVEN: Test object
340+ pjlink = pjlink_test
341+ pjlink.projector_status = 0
342+ pjlink.status_connect = 0
343+ test_code = S_ON
344+ mock_change_status.reset_mock()
345+ mock_log.reset_mock()
346+
347+ # WHEN: change_status called with unknown socket error
348+ pjlink.change_status(status=test_code, msg=None)
349+
350+ # THEN: Proper settings should change and signals sent
351+ self.assertEqual(pjlink.projector_status, S_ON, 'Projector status should be ON')
352+ self.assertEqual(pjlink.status_connect, S_CONNECTED, 'Status connect should be CONNECTED')
353+ mock_change_status.emit.assert_called_once_with(pjlink.ip, S_ON, 'Power is on')
354+ self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
355+
356+ @patch.object(pjlink_test, 'changeStatus')
357+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
358+ def test_projector_change_status_connection_status_with_message(self, mock_log, mock_change_status):
359+ """
360+ Test change_status with connection status
361+ """
362+ # GIVEN: Test object
363+ pjlink = pjlink_test
364+ pjlink.projector_status = 0
365+ pjlink.status_connect = 0
366+ test_message = 'Different Status Message than default'
367+ test_code = S_ON
368+ mock_change_status.reset_mock()
369+ mock_log.reset_mock()
370+
371+ # WHEN: change_status called with unknown socket error
372+ pjlink.change_status(status=test_code, msg=test_message)
373+
374+ # THEN: Proper settings should change and signals sent
375+ self.assertEqual(pjlink.projector_status, S_ON, 'Projector status should be ON')
376+ self.assertEqual(pjlink.status_connect, S_CONNECTED, 'Status connect should be CONNECTED')
377+ mock_change_status.emit.assert_called_once_with(pjlink.ip, S_ON, test_message)
378+ self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
379+
380+ @patch.object(pjlink_test, 'send_command')
381+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
382+ def test_projector_get_av_mute_status(self, mock_log, mock_send_command):
383+ """
384+ Test sending command to retrieve shutter/audio state
385+ """
386+ # GIVEN: Test object
387+ pjlink = pjlink_test
388+ mock_log.reset_mock()
389+ mock_send_command.reset_mock()
390+ test_data = 'AVMT'
391+ test_log = '(127.0.0.1) Sending AVMT command'
392+
393+ # WHEN: get_av_mute_status is called
394+ pjlink.get_av_mute_status()
395+
396+ # THEN: log data and send_command should have been called
397+ mock_log.debug.assert_called_once_with(test_log)
398+ mock_send_command.assert_called_once_with(cmd=test_data)
399+
400+ @patch.object(pjlink_test, 'send_command')
401+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
402+ def test_projector_get_available_inputs(self, mock_log, mock_send_command):
403+ """
404+ Test sending command to retrieve avaliable inputs
405+ """
406+ # GIVEN: Test object
407+ pjlink = pjlink_test
408+ mock_log.reset_mock()
409+ mock_send_command.reset_mock()
410+ test_data = 'INST'
411+ test_log = '(127.0.0.1) Sending INST command'
412+
413+ # WHEN: get_available_inputs is called
414+ pjlink.get_available_inputs()
415+
416+ # THEN: log data and send_command should have been called
417+ mock_log.debug.assert_called_once_with(test_log)
418+ mock_send_command.assert_called_once_with(cmd=test_data)
419+
420+ @patch.object(pjlink_test, 'send_command')
421+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
422+ def test_projector_get_error_status(self, mock_log, mock_send_command):
423+ """
424+ Test sending command to retrieve projector error status
425+ """
426+ # GIVEN: Test object
427+ pjlink = pjlink_test
428+ mock_log.reset_mock()
429+ mock_send_command.reset_mock()
430+ test_data = 'ERST'
431+ test_log = '(127.0.0.1) Sending ERST command'
432+
433+ # WHEN: get_error_status is called
434+ pjlink.get_error_status()
435+
436+ # THEN: log data and send_command should have been called
437+ mock_log.debug.assert_called_once_with(test_log)
438+ mock_send_command.assert_called_once_with(cmd=test_data)
439+
440+ @patch.object(pjlink_test, 'send_command')
441+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
442+ def test_projector_get_input_source(self, mock_log, mock_send_command):
443+ """
444+ Test sending command to retrieve current input
445+ """
446+ # GIVEN: Test object
447+ pjlink = pjlink_test
448+ mock_log.reset_mock()
449+ mock_send_command.reset_mock()
450+ test_data = 'INPT'
451+ test_log = '(127.0.0.1) Sending INPT command'
452+
453+ # WHEN: get_input_source is called
454+ pjlink.get_input_source()
455+
456+ # THEN: log data and send_command should have been called
457+ mock_log.debug.assert_called_once_with(test_log)
458+ mock_send_command.assert_called_once_with(cmd=test_data)
459+
460+ @patch.object(pjlink_test, 'send_command')
461+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
462+ def test_projector_get_lamp_status(self, mock_log, mock_send_command):
463+ """
464+ Test sending command to retrieve lamp(s) status
465+ """
466+ # GIVEN: Test object
467+ pjlink = pjlink_test
468+ mock_log.reset_mock()
469+ mock_send_command.reset_mock()
470+ test_data = 'LAMP'
471+ test_log = '(127.0.0.1) Sending LAMP command'
472+
473+ # WHEN: get_lamp_status is called
474+ pjlink.get_lamp_status()
475+
476+ # THEN: log data and send_command should have been called
477+ mock_log.debug.assert_called_once_with(test_log)
478+ mock_send_command.assert_called_once_with(cmd=test_data)
479+
480+ @patch.object(pjlink_test, 'send_command')
481+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
482+ def test_projector_get_manufacturer(self, mock_log, mock_send_command):
483+ """
484+ Test sending command to retrieve manufacturer name
485+ """
486+ # GIVEN: Test object
487+ pjlink = pjlink_test
488+ mock_log.reset_mock()
489+ mock_send_command.reset_mock()
490+ test_data = 'INF1'
491+ test_log = '(127.0.0.1) Sending INF1 command'
492+
493+ # WHEN: get_manufacturer is called
494+ pjlink.get_manufacturer()
495+
496+ # THEN: log data and send_command should have been called
497+ mock_log.debug.assert_called_once_with(test_log)
498+ mock_send_command.assert_called_once_with(cmd=test_data)
499+
500+ @patch.object(pjlink_test, 'send_command')
501+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
502+ def test_projector_get_model(self, mock_log, mock_send_command):
503+ """
504+ Test sending command to get model information
505+ """
506+ # GIVEN: Test object
507+ pjlink = pjlink_test
508+ mock_log.reset_mock()
509+ mock_send_command.reset_mock()
510+ test_data = 'INF2'
511+ test_log = '(127.0.0.1) Sending INF2 command'
512+
513+ # WHEN: get_model is called
514+ pjlink.get_model()
515+
516+ # THEN: log data and send_command should have been called
517+ mock_log.debug.assert_called_once_with(test_log)
518+ mock_send_command.assert_called_once_with(cmd=test_data)
519+
520+ @patch.object(pjlink_test, 'send_command')
521+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
522+ def test_projector_get_name(self, mock_log, mock_send_command):
523+ """
524+ Test sending command to get user-assigned name
525+ """
526+ # GIVEN: Test object
527+ pjlink = pjlink_test
528+ mock_log.reset_mock()
529+ mock_send_command.reset_mock()
530+ test_data = 'NAME'
531+ test_log = '(127.0.0.1) Sending NAME command'
532+
533+ # WHEN: get_name is called
534+ pjlink.get_name()
535+
536+ # THEN: log data and send_command should have been called
537+ mock_log.debug.assert_called_once_with(test_log)
538+ mock_send_command.assert_called_once_with(cmd=test_data)
539+
540+ @patch.object(pjlink_test, 'send_command')
541+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
542+ def test_projector_get_other_info(self, mock_log, mock_send_command):
543+ """
544+ Test sending command to retrieve other information
545+ """
546+ # GIVEN: Test object
547+ pjlink = pjlink_test
548+ mock_log.reset_mock()
549+ mock_send_command.reset_mock()
550+ test_data = 'INFO'
551+ test_log = '(127.0.0.1) Sending INFO command'
552+
553+ # WHEN: get_other_info is called
554+ pjlink.get_other_info()
555+
556+ # THEN: log data and send_command should have been called
557+ mock_log.debug.assert_called_once_with(test_log)
558+ mock_send_command.assert_called_once_with(cmd=test_data)
559+
560+ @patch.object(pjlink_test, 'send_command')
561+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
562+ def test_projector_get_power_status(self, mock_log, mock_send_command):
563+ """
564+ Test sending command to retrieve current power state
565+ """
566+ # GIVEN: Test object
567+ pjlink = pjlink_test
568+ mock_log.reset_mock()
569+ mock_send_command.reset_mock()
570+ test_data = 'POWR'
571+ test_log = '(127.0.0.1) Sending POWR command'
572+
573+ # WHEN: get_power_status called
574+ pjlink.get_power_status()
575+
576+ # THEN: log data and send_command should have been called
577+ mock_log.debug.assert_called_once_with(test_log)
578+ mock_send_command.assert_called_once_with(cmd=test_data)
579+
580+ def test_projector_get_status_error(self):
581+ """
582+ Test to check returned information for error code
583+ """
584+ # GIVEN: Test object
585+ pjlink = pjlink_test
586+ test_string = 'E_SOCKET_ADDRESS_NOT_AVAILABLE'
587+ test_message = 'The address specified to socket.bind() does not belong to the host'
588+
589+ # WHEN: get_status called
590+ string, message = pjlink._get_status(status=E_SOCKET_ADDRESS_NOT_AVAILABLE)
591+
592+ # THEN: Proper strings should have been returned
593+ self.assertEqual(string, test_string, 'Code as string should have been returned')
594+ self.assertEqual(message, test_message, 'Description of code should have been returned')
595+
596+ def test_projector_get_status_invalid(self):
597+ """
598+ Test to check returned information for error code
599+ """
600+ # GIVEN: Test object
601+ pjlink = pjlink_test
602+ test_string = 'Test string since get_status will only work with int'
603+ test_message = 'Invalid status code'
604+
605+ # WHEN: get_status called
606+ string, message = pjlink._get_status(status=test_string)
607+
608+ # THEN: Proper strings should have been returned
609+ self.assertEqual(string, -1, 'Should have returned -1 as a bad status check')
610+ self.assertEqual(message, test_message, 'Error message should have been returned')
611+
612+ def test_projector_get_status_status(self):
613+ """
614+ Test to check returned information for status codes
615+ """
616+ # GIVEN: Test object
617+ pjlink = pjlink_test
618+ test_string = 'S_NOT_CONNECTED'
619+ test_message = 'Not connected'
620+
621+ # WHEN: get_status called
622+ string, message = pjlink._get_status(status=S_NOT_CONNECTED)
623+
624+ # THEN: Proper strings should have been returned
625+ self.assertEqual(string, test_string, 'Code as string should have been returned')
626+ self.assertEqual(message, test_message, 'Description of code should have been returned')
627+
628+ def test_projector_get_status_unknown(self):
629+ """
630+ Test to check returned information for unknown code
631+ """
632+ # GIVEN: Test object
633+ pjlink = pjlink_test
634+ test_string = 999999
635+ test_message = 'Unknown status'
636+
637+ # WHEN: get_status called
638+ string, message = pjlink._get_status(status=test_string)
639+
640+ # THEN: Proper strings should have been returned
641+ self.assertEqual(string, test_string, 'Received code should have been returned')
642+ self.assertEqual(message, test_message, 'Unknown status string should have been returned')
643+
644+ def test_projector_process_inf1(self):
645+ """
646+ Test saving INF1 data (manufacturer)
647+ """
648+ # GIVEN: Test object
649+ pjlink = pjlink_test
650+ pjlink.manufacturer = None
651+ test_data = 'TEst INformation MultiCase'
652+
653+ # WHEN: process_inf called with test data
654+ pjlink.process_inf1(data=test_data)
655+
656+ # THEN: Data should be saved
657+ self.assertEqual(pjlink.manufacturer, test_data, 'Test data should have been saved')
658+
659+ def test_projector_process_inf2(self):
660+ """
661+ Test saving INF2 data (model)
662+ """
663+ # GIVEN: Test object
664+ pjlink = pjlink_test
665+ pjlink.model = None
666+ test_data = 'TEst moDEl MultiCase'
667+
668+ # WHEN: process_inf called with test data
669+ pjlink.process_inf2(data=test_data)
670+
671+ # THEN: Data should be saved
672+ self.assertEqual(pjlink.model, test_data, 'Test data should have been saved')
673+
674+ def test_projector_process_info(self):
675+ """
676+ Test saving INFO data (other information)
677+ """
678+ # GIVEN: Test object
679+ pjlink = pjlink_test
680+ pjlink.other_info = None
681+ test_data = 'TEst ExtrANEous MultiCase INformatoin that MFGR might Set'
682+
683+ # WHEN: process_inf called with test data
684+ pjlink.process_info(data=test_data)
685+
686+ # THEN: Data should be saved
687+ self.assertEqual(pjlink.other_info, test_data, 'Test data should have been saved')
688
689 @patch.object(pjlink_test, 'projectorUpdateIcons')
690 def test_projector_process_avmt_bad_data(self, mock_UpdateIcons):
691@@ -245,12 +607,12 @@
692
693 # WHEN: Process invalid reply
694 pjlink.process_clss('Z')
695- log_warn_text = "(127.0.0.1) NAN clss version reply 'Z' - defaulting to class '1'"
696+ log_text = "(127.0.0.1) NAN clss version reply 'Z' - defaulting to class '1'"
697
698 # THEN: Projector class should be set with default value
699 self.assertEqual(pjlink.pjlink_class, '1',
700 'Non-standard class reply should have set class=1')
701- mock_log.error.assert_called_once_with(log_warn_text)
702+ mock_log.error.assert_called_once_with(log_text)
703
704 @patch.object(openlp.core.lib.projector.pjlink, 'log')
705 def test_projector_process_clss_invalid_no_version(self, mock_log):
706@@ -262,12 +624,12 @@
707
708 # WHEN: Process invalid reply
709 pjlink.process_clss('Invalid')
710- log_warn_text = "(127.0.0.1) No numbers found in class version reply 'Invalid' - defaulting to class '1'"
711+ log_text = "(127.0.0.1) No numbers found in class version reply 'Invalid' - defaulting to class '1'"
712
713 # THEN: Projector class should be set with default value
714 self.assertEqual(pjlink.pjlink_class, '1',
715 'Non-standard class reply should have set class=1')
716- mock_log.error.assert_called_once_with(log_warn_text)
717+ mock_log.error.assert_called_once_with(log_text)
718
719 def test_projector_process_erst_all_ok(self):
720 """
721@@ -292,15 +654,15 @@
722 # GIVEN: Test object
723 pjlink = pjlink_test
724 pjlink.projector_errors = None
725- log_warn_text = "127.0.0.1) Invalid error status response '11111111': length != 6"
726+ log_text = "127.0.0.1) Invalid error status response '11111111': length != 6"
727
728 # WHEN: process_erst called with invalid data (too many values
729 pjlink.process_erst('11111111')
730
731 # THEN: pjlink.projector_errors should be empty and warning logged
732 self.assertIsNone(pjlink.projector_errors, 'There should be no errors')
733- self.assertTrue(mock_log.warn.called, 'Warning should have been logged')
734- mock_log.warn.assert_called_once_with(log_warn_text)
735+ self.assertTrue(mock_log.warning.called, 'Warning should have been logged')
736+ mock_log.warning.assert_called_once_with(log_text)
737
738 @patch.object(openlp.core.lib.projector.pjlink, 'log')
739 def test_projector_process_erst_data_invalid_nan(self, mock_log):
740@@ -310,15 +672,15 @@
741 # GIVEN: Test object
742 pjlink = pjlink_test
743 pjlink.projector_errors = None
744- log_warn_text = "(127.0.0.1) Invalid error status response '1111Z1'"
745+ log_text = "(127.0.0.1) Invalid error status response '1111Z1'"
746
747 # WHEN: process_erst called with invalid data (too many values
748 pjlink.process_erst('1111Z1')
749
750 # THEN: pjlink.projector_errors should be empty and warning logged
751 self.assertIsNone(pjlink.projector_errors, 'There should be no errors')
752- self.assertTrue(mock_log.warn.called, 'Warning should have been logged')
753- mock_log.warn.assert_called_once_with(log_warn_text)
754+ self.assertTrue(mock_log.warning.called, 'Warning should have been logged')
755+ mock_log.warning.assert_called_once_with(log_text)
756
757 def test_projector_process_erst_all_warn(self):
758 """
759@@ -399,33 +761,67 @@
760 # THEN: Input selected should reflect current input
761 self.assertEqual(pjlink.source, '1', 'Input source should be set to "1"')
762
763- @patch.object(pjlink_test, 'projectorReceivedData')
764- def test_projector_process_lamp_single(self, mock_projectorReceivedData):
765- """
766- Test status lamp on/off and hours
767- """
768- # GIVEN: Test object
769- pjlink = pjlink_test
770-
771- # WHEN: Call process_command with lamp data
772- pjlink.process_command('LAMP', '22222 1')
773-
774- # THEN: Lamp should have been set with status=ON and hours=22222
775+ @patch.object(pjlink_test, 'projectorUpdateIcons')
776+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
777+ def test_projector_process_inst(self, mock_log, mock_UpdateIcons):
778+ """
779+ Test saving video source available information
780+ """
781+ # GIVEN: Test object
782+ pjlink = pjlink_test
783+ pjlink.source_available = []
784+ test_data = '21 10 30 31 11 20'
785+ test_saved = ['10', '11', '20', '21', '30', '31']
786+ log_data = '(127.0.0.1) Setting projector sources_available to ' \
787+ '"[\'10\', \'11\', \'20\', \'21\', \'30\', \'31\']"'
788+ mock_UpdateIcons.reset_mock()
789+ mock_log.reset_mock()
790+
791+ # WHEN: process_inst called with test data
792+ pjlink.process_inst(data=test_data)
793+
794+ # THEN: Data should have been sorted and saved properly
795+ self.assertEqual(pjlink.source_available, test_saved, "Sources should have been sorted and saved")
796+ mock_log.debug.assert_called_once_with(log_data)
797+ self.assertTrue(mock_UpdateIcons.emit.called, 'Update Icons should have been called')
798+
799+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
800+ def test_projector_process_lamp_invalid(self, mock_log):
801+ """
802+ Test status multiple lamp on/off and hours
803+ """
804+ # GIVEN: Test object
805+ pjlink = pjlink_test
806+ pjlink.lamp = [{'Hours': 00000, 'On': True},
807+ {'Hours': 11111, 'On': False}]
808+ log_data = '(127.0.0.1) process_lamp(): Invalid data "11111 1 22222 0 333A3 1"'
809+
810+ # WHEN: Call process_command with invalid lamp data
811+ pjlink.process_lamp('11111 1 22222 0 333A3 1')
812+
813+ # THEN: lamps should not have changed
814+ self.assertEqual(len(pjlink.lamp), 2,
815+ 'Projector should have kept 2 lamps specified')
816 self.assertEqual(pjlink.lamp[0]['On'], True,
817- 'Lamp power status should have been set to TRUE')
818- self.assertEqual(pjlink.lamp[0]['Hours'], 22222,
819- 'Lamp hours should have been set to 22222')
820+ 'Lamp 1 power status should have been set to TRUE')
821+ self.assertEqual(pjlink.lamp[0]['Hours'], 00000,
822+ 'Lamp 1 hours should have been left at 00000')
823+ self.assertEqual(pjlink.lamp[1]['On'], False,
824+ 'Lamp 2 power status should have been set to FALSE')
825+ self.assertEqual(pjlink.lamp[1]['Hours'], 11111,
826+ 'Lamp 2 hours should have been left at 11111')
827+ mock_log.warning.assert_called_once_with(log_data)
828
829- @patch.object(pjlink_test, 'projectorReceivedData')
830- def test_projector_process_lamp_multiple(self, mock_projectorReceivedData):
831+ def test_projector_process_lamp_multiple(self):
832 """
833 Test status multiple lamp on/off and hours
834 """
835 # GIVEN: Test object
836 pjlink = pjlink_test
837+ pjlink.lamps = []
838
839 # WHEN: Call process_command with lamp data
840- pjlink.process_command('LAMP', '11111 1 22222 0 33333 1')
841+ pjlink.process_lamp('11111 1 22222 0 33333 1')
842
843 # THEN: Lamp should have been set with proper lamp status
844 self.assertEqual(len(pjlink.lamp), 3,
845@@ -443,53 +839,112 @@
846 self.assertEqual(pjlink.lamp[2]['Hours'], 33333,
847 'Lamp 3 hours should have been set to 33333')
848
849- @patch.object(pjlink_test, 'projectorReceivedData')
850+ def test_projector_process_lamp_single(self):
851+ """
852+ Test status lamp on/off and hours
853+ """
854+ # GIVEN: Test object
855+ pjlink = pjlink_test
856+ pjlink.lamps = []
857+
858+ # WHEN: Call process_command with lamp data
859+ pjlink.process_lamp('22222 1')
860+
861+ # THEN: Lamp should have been set with status=ON and hours=22222
862+ self.assertEqual(pjlink.lamp[0]['On'], True,
863+ 'Lamp power status should have been set to TRUE')
864+ self.assertEqual(pjlink.lamp[0]['Hours'], 22222,
865+ 'Lamp hours should have been set to 22222')
866+
867+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
868+ def test_projector_process_name(self, mock_log):
869+ """
870+ Test saving NAME data from projector
871+ """
872+ # GIVEN: Test data
873+ pjlink = pjlink_test
874+ test_data = "Some Name the End-User Set IN Projector"
875+ test_log = '(127.0.0.1) Setting projector PJLink name to "Some Name the End-User Set IN Projector"'
876+ mock_log.reset_mock()
877+
878+ # WHEN: process_name called with test data
879+ pjlink.process_name(data=test_data)
880+
881+ # THEN: name should be set and logged
882+ self.assertEqual(pjlink.pjlink_name, test_data, 'Name test data should have been saved')
883+ mock_log.debug.assert_called_once_with(test_log)
884+
885 @patch.object(pjlink_test, 'projectorUpdateIcons')
886 @patch.object(pjlink_test, 'send_command')
887 @patch.object(pjlink_test, 'change_status')
888 def test_projector_process_powr_on(self,
889 mock_change_status,
890 mock_send_command,
891- mock_UpdateIcons,
892- mock_ReceivedData):
893+ mock_UpdateIcons):
894 """
895 Test status power to ON
896 """
897 # GIVEN: Test object and preset
898 pjlink = pjlink_test
899 pjlink.power = S_STANDBY
900+ test_data = PJLINK_POWR_STATUS[S_ON]
901
902 # WHEN: Call process_command with turn power on command
903- pjlink.process_command('POWR', PJLINK_POWR_STATUS[S_ON])
904+ pjlink.process_command(cmd='POWR', data=test_data)
905
906 # THEN: Power should be set to ON
907 self.assertEqual(pjlink.power, S_ON, 'Power should have been set to ON')
908 mock_send_command.assert_called_once_with('INST')
909+ mock_change_status.assert_called_once_with(PJLINK_POWR_STATUS[test_data])
910 self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
911
912- @patch.object(pjlink_test, 'projectorReceivedData')
913+ @patch.object(pjlink_test, 'projectorUpdateIcons')
914+ @patch.object(pjlink_test, 'send_command')
915+ @patch.object(pjlink_test, 'change_status')
916+ def test_projector_process_powr_invalid(self,
917+ mock_change_status,
918+ mock_send_command,
919+ mock_UpdateIcons):
920+ """
921+ Test process_powr invalid call
922+ """
923+ # GIVEN: Test object and preset
924+ pjlink = pjlink_test
925+ pjlink.power = S_STANDBY
926+ test_data = '99'
927+
928+ # WHEN: Call process_command with turn power on command
929+ pjlink.process_command(cmd='POWR', data=test_data)
930+
931+ # THEN: Power should be set to ON
932+ self.assertEqual(pjlink.power, S_STANDBY, 'Power should not have changed')
933+ self.assertFalse(mock_change_status.called, 'Change status should not have been called')
934+ self.assertFalse(mock_send_command.called, 'send_command("INST") should not have been called')
935+ self.assertFalse(mock_UpdateIcons.emit.called, 'projectorUpdateIcons should not have been called')
936+
937 @patch.object(pjlink_test, 'projectorUpdateIcons')
938 @patch.object(pjlink_test, 'send_command')
939 @patch.object(pjlink_test, 'change_status')
940 def test_projector_process_powr_off(self,
941 mock_change_status,
942 mock_send_command,
943- mock_UpdateIcons,
944- mock_ReceivedData):
945+ mock_UpdateIcons):
946 """
947 Test status power to STANDBY
948 """
949 # GIVEN: Test object and preset
950 pjlink = pjlink_test
951 pjlink.power = S_ON
952+ test_data = PJLINK_POWR_STATUS[S_STANDBY]
953
954 # WHEN: Call process_command with turn power on command
955- pjlink.process_command('POWR', PJLINK_POWR_STATUS[S_STANDBY])
956+ pjlink.process_command(cmd='POWR', data=test_data)
957
958 # THEN: Power should be set to STANDBY
959 self.assertEqual(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')
960- self.assertEqual(mock_send_command.called, False, 'send_command should not have been called')
961 self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
962+ mock_change_status.assert_called_once_with(PJLINK_POWR_STATUS[test_data])
963+ self.assertFalse(mock_send_command.called, "send_command['INST'] should not have been called")
964
965 def test_projector_process_rfil_save(self):
966 """
967@@ -582,3 +1037,111 @@
968 # THEN: Serial number should be set
969 self.assertNotEquals(pjlink.serial_no, test_number,
970 'Projector serial number should NOT have been set')
971+
972+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
973+ def test_projector_process_sver(self, mock_log):
974+ """
975+ Test invalid software version information - too long
976+ """
977+ # GIVEN: Test object
978+ pjlink = pjlink_test
979+ pjlink.sw_version = None
980+ pjlink.sw_version_received = None
981+ test_data = 'Test 1 Subtest 1'
982+ test_log = "(127.0.0.1) Setting projector software version to 'Test 1 Subtest 1'"
983+ mock_log.reset_mock()
984+
985+ # WHEN: process_sver called with invalid data
986+ pjlink.process_sver(data=test_data)
987+
988+ # THEN: Version information should not change
989+ self.assertEqual(pjlink.sw_version, test_data, 'Software version should have been updated')
990+ self.assertIsNone(pjlink.sw_version_received, 'Received software version should not have changed')
991+ mock_log.debug.assert_called_once_with(test_log)
992+
993+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
994+ def test_projector_process_sver_changed(self, mock_log):
995+ """
996+ Test invalid software version information - Received different than saved
997+ """
998+ # GIVEN: Test object
999+ pjlink = pjlink_test
1000+ test_data_new = 'Test 1 Subtest 2'
1001+ test_data_old = 'Test 1 Subtest 1'
1002+ pjlink.sw_version = test_data_old
1003+ pjlink.sw_version_received = None
1004+ test_log = '(127.0.0.1) Saving new serial number as sw_version_received'
1005+ mock_log.reset_mock()
1006+
1007+ # WHEN: process_sver called with invalid data
1008+ pjlink.process_sver(data=test_data_new)
1009+
1010+ # THEN: Version information should not change
1011+ self.assertEqual(pjlink.sw_version, test_data_old, 'Software version should not have been updated')
1012+ self.assertEqual(pjlink.sw_version_received, test_data_new,
1013+ 'Received software version should have been changed')
1014+ self.assertEqual(mock_log.warning.call_count, 4, 'log.warn should have been called 4 times')
1015+ # There was 4 calls, but only the last one is checked with this method
1016+ mock_log.warning.assert_called_with(test_log)
1017+
1018+ @patch.object(openlp.core.lib.projector.pjlink, 'log')
1019+ def test_projector_process_sver_invalid(self, mock_log):
1020+ """
1021+ Test invalid software version information - too long
1022+ """
1023+ # GIVEN: Test object
1024+ pjlink = pjlink_test
1025+ pjlink.sw_version = None
1026+ pjlink.sw_version_received = None
1027+ test_data = 'This is a test software version line that is too long based on PJLink version 2 specs'
1028+ test_log = "Invalid software version - too long"
1029+ mock_log.reset_mock()
1030+
1031+ # WHEN: process_sver called with invalid data
1032+ pjlink.process_sver(data=test_data)
1033+
1034+ # THEN: Version information should not change
1035+ self.assertIsNone(pjlink.sw_version, 'Software version should not have changed')
1036+ self.assertIsNone(pjlink.sw_version_received, 'Received software version should not have changed')
1037+ mock_log.warning.assert_called_once_with(test_log)
1038+
1039+ def test_projector_reset_information(self):
1040+ """
1041+ Test reset_information() resets all information and stops timers
1042+ """
1043+ # GIVEN: Test object and test data
1044+ pjlink = pjlink_test
1045+ pjlink.power = S_ON
1046+ pjlink.pjlink_name = 'OPENLPTEST'
1047+ pjlink.manufacturer = 'PJLINK'
1048+ pjlink.model = '1'
1049+ pjlink.shutter = True
1050+ pjlink.mute = True
1051+ pjlink.lamp = True
1052+ pjlink.fan = True
1053+ pjlink.source_available = True
1054+ pjlink.other_info = 'ANOTHER TEST'
1055+ pjlink.send_queue = True
1056+ pjlink.send_busy = True
1057+
1058+ # WHEN: reset_information() is called
1059+ with patch.object(pjlink, 'timer') as mock_timer:
1060+ with patch.object(pjlink, 'socket_timer') as mock_socket_timer:
1061+ pjlink.reset_information()
1062+
1063+ # THEN: All information should be reset and timers stopped
1064+ self.assertEqual(pjlink.power, S_OFF, 'Projector power should be OFF')
1065+ self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None')
1066+ self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None')
1067+ self.assertIsNone(pjlink.model, 'Projector model should be None')
1068+ self.assertIsNone(pjlink.shutter, 'Projector shutter should be None')
1069+ self.assertIsNone(pjlink.mute, 'Projector shuttter should be None')
1070+ self.assertIsNone(pjlink.lamp, 'Projector lamp should be None')
1071+ self.assertIsNone(pjlink.fan, 'Projector fan should be None')
1072+ self.assertIsNone(pjlink.source_available, 'Projector source_available should be None')
1073+ self.assertIsNone(pjlink.source, 'Projector source should be None')
1074+ self.assertIsNone(pjlink.other_info, 'Projector other_info should be None')
1075+ self.assertEqual(pjlink.send_queue, [], 'Projector send_queue should be an empty list')
1076+ self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
1077+ self.assertTrue(mock_timer.stop.called, 'Projector timer.stop() should have been called')
1078+ self.assertTrue(mock_socket_timer.stop.called, 'Projector socket_timer.stop() should have been called')