mirror of
https://github.com/lowobservable/oec.git
synced 2026-04-24 19:33:54 +00:00
Use new pycoax 0.10.0 API
This commit is contained in:
59
tests/mock_interface.py
Normal file
59
tests/mock_interface.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from unittest.mock import Mock
|
||||
|
||||
from coax import ProtocolError, ReceiveError, ReceiveTimeout
|
||||
from coax.interface import Interface
|
||||
|
||||
class MockInterface(Interface):
|
||||
def __init__(self, responses=[]):
|
||||
self.mock_responses = responses
|
||||
|
||||
self.legacy_firmware_detected = None
|
||||
self.legacy_firmware_version = None
|
||||
|
||||
# Wrap the reset and execute methods so calls can be asserted.
|
||||
self.reset = Mock(wraps=self.reset)
|
||||
self._execute = Mock(wraps=self._execute)
|
||||
|
||||
def _execute(self, commands, timeout):
|
||||
return [self._mock_get_response(device_address, command) for (device_address, command) in commands]
|
||||
|
||||
def reset_mock(self):
|
||||
self.reset.reset_mock()
|
||||
self._execute.reset_mock()
|
||||
|
||||
def assert_command_executed(self, device_address, command_type, predicate=None):
|
||||
if not self._mock_get_execute_commands(device_address, command_type, predicate):
|
||||
raise AssertionError('Expected command to be executed')
|
||||
|
||||
def assert_command_not_executed(self, device_address, command_type, predicate=None):
|
||||
if self._mock_get_execute_commands(device_address, command_type, predicate):
|
||||
raise AssertionError('Expected command not to be executed')
|
||||
|
||||
def _mock_get_execute_commands(self, device_address, command_type, predicate):
|
||||
calls = self._execute.call_args_list
|
||||
|
||||
commands = []
|
||||
|
||||
for call in calls:
|
||||
for command in call[0][0]:
|
||||
(call_device_address, call_command) = command
|
||||
|
||||
if call_device_address == device_address and isinstance(call_command, command_type):
|
||||
if predicate is None or predicate(call_command):
|
||||
commands.append(command)
|
||||
|
||||
return commands
|
||||
|
||||
def _mock_get_response(self, device_address, command):
|
||||
for (mock_device_address, mock_command_type, mock_predicate, mock_response) in self.mock_responses:
|
||||
if mock_device_address == device_address and isinstance(command, mock_command_type):
|
||||
if mock_predicate is None or mock_predicate(command):
|
||||
if callable(mock_response):
|
||||
try:
|
||||
return mock_response()
|
||||
except (ProtocolError, ReceiveError, ReceiveTimeout) as error:
|
||||
return error
|
||||
|
||||
return mock_response
|
||||
|
||||
return None
|
||||
@@ -1,36 +1,42 @@
|
||||
import selectors
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from coax import PollAction, PowerOnResetCompletePollResponse, KeystrokePollResponse, ReceiveTimeout
|
||||
from unittest.mock import Mock, create_autospec, patch
|
||||
|
||||
import selectors
|
||||
from selectors import BaseSelector
|
||||
from logging import Logger
|
||||
from coax import Poll, PollAction, PowerOnResetCompletePollResponse, KeystrokePollResponse, PollAck, ReceiveTimeout
|
||||
from coax.protocol import TerminalId
|
||||
|
||||
import context
|
||||
|
||||
from oec.interface import InterfaceWrapper
|
||||
from oec.controller import Controller
|
||||
from oec.session import SessionDisconnectedError
|
||||
from oec.terminal import Terminal, UnsupportedTerminalError
|
||||
from oec.display import Dimensions
|
||||
from oec.keyboard import KeyboardModifiers, Key
|
||||
from oec.keymap_3278_2 import KEYMAP as KEYMAP_3278_2
|
||||
from oec.session import Session, SessionDisconnectedError
|
||||
|
||||
from mock_interface import MockInterface
|
||||
|
||||
class RunLoopTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.session_mock = Mock()
|
||||
self.create_session_mock = Mock(return_value=self.session_mock)
|
||||
self.session = create_autospec(Session, instance=True)
|
||||
self.create_session = Mock(return_value=self.session)
|
||||
|
||||
self.controller = Controller(self.interface, lambda terminal_id, extended_id: KEYMAP_3278_2, self.create_session_mock)
|
||||
self.controller = Controller(InterfaceWrapper(self.interface), lambda terminal_id, extended_id: KEYMAP_3278_2, self.create_session)
|
||||
|
||||
self.controller.logger = Mock()
|
||||
self.controller.logger = create_autospec(Logger, instance=True)
|
||||
|
||||
self.controller.connected_poll_period = 1
|
||||
|
||||
self.controller.session_selector = Mock()
|
||||
self.controller.session_selector = create_autospec(BaseSelector, instance=True)
|
||||
|
||||
self.controller._update_session = Mock()
|
||||
|
||||
self.terminal = Terminal(self.interface, TerminalId(0b11110100), 'c1348300', Dimensions(24, 80), { }, KEYMAP_3278_2, None)
|
||||
self.terminal = Terminal(self.interface, None, TerminalId(0b11110100), 'c1348300', Dimensions(24, 80), { }, KEYMAP_3278_2)
|
||||
|
||||
self.terminal.setup = Mock()
|
||||
|
||||
@@ -40,33 +46,19 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
|
||||
self.terminal.keyboard.toggle_clicker = Mock()
|
||||
|
||||
self.poll_mock = Mock()
|
||||
|
||||
patcher = patch('oec.controller.poll', self.poll_mock)
|
||||
|
||||
patcher.start()
|
||||
|
||||
patcher = patch('oec.terminal.poll', self.poll_mock)
|
||||
|
||||
patcher.start()
|
||||
|
||||
patcher = patch('oec.controller.poll_ack')
|
||||
|
||||
self.poll_ack_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.controller.time.perf_counter')
|
||||
|
||||
self.perf_counter_mock = patcher.start()
|
||||
self.perf_counter = patcher.start()
|
||||
|
||||
patcher = patch('oec.controller.time.sleep')
|
||||
|
||||
self.sleep_mock = patcher.start()
|
||||
self.sleep = patcher.start()
|
||||
|
||||
patcher = patch('oec.controller.create_terminal')
|
||||
|
||||
self.create_terminal_mock = patcher.start()
|
||||
self.create_terminal = patcher.start()
|
||||
|
||||
self.create_terminal_mock.return_value = self.terminal
|
||||
self.create_terminal.return_value = self.terminal
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
@@ -88,7 +80,7 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
self.controller._update_session.assert_called()
|
||||
|
||||
def test_unsupported_terminal_attached(self):
|
||||
self.create_terminal_mock.side_effect = [UnsupportedTerminalError]
|
||||
self.create_terminal.side_effect = [UnsupportedTerminalError]
|
||||
|
||||
self._assert_run_loop(0, PowerOnResetCompletePollResponse(0xa), False, 0, True)
|
||||
|
||||
@@ -114,7 +106,7 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
self.assertIsNone(self.controller.terminal)
|
||||
self.assertIsNone(self.controller.session)
|
||||
|
||||
self.session_mock.terminate.assert_called()
|
||||
self.session.terminate.assert_called()
|
||||
|
||||
def test_session_disconnected(self):
|
||||
self.controller._update_session.side_effect = [None, SessionDisconnectedError, None]
|
||||
@@ -127,7 +119,7 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
self.assertIsNotNone(self.controller.terminal)
|
||||
self.assertIsNotNone(self.controller.session)
|
||||
|
||||
self.assertEqual(self.create_session_mock.call_count, 2)
|
||||
self.assertEqual(self.create_session.call_count, 2)
|
||||
|
||||
def test_toggle_cursor_blink(self):
|
||||
self._assert_run_loop(0, PowerOnResetCompletePollResponse(0xa), False, 0, True)
|
||||
@@ -178,13 +170,13 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
# Arrange
|
||||
self.controller._update_session.reset_mock()
|
||||
|
||||
self.poll_mock.side_effect = [poll_response]
|
||||
self.interface.mock_responses = [(None, Poll, None, poll_response)]
|
||||
|
||||
self.poll_ack_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
self.perf_counter_mock.side_effect = [poll_time, poll_time + expected_poll_delay]
|
||||
self.perf_counter.side_effect = [poll_time, poll_time + expected_poll_delay]
|
||||
|
||||
self.sleep_mock.reset_mock()
|
||||
self.sleep.reset_mock()
|
||||
|
||||
# Act
|
||||
self.controller._run_loop()
|
||||
@@ -192,31 +184,31 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
if expected_update_session:
|
||||
self.controller._update_session.assert_called_once_with(expected_poll_delay)
|
||||
self.sleep_mock.assert_not_called()
|
||||
self.sleep.assert_not_called()
|
||||
else:
|
||||
self.controller._update_session.assert_not_called()
|
||||
|
||||
if expected_poll_delay > 0:
|
||||
self.sleep_mock.assert_called_once_with(expected_poll_delay)
|
||||
self.sleep.assert_called_once_with(expected_poll_delay)
|
||||
else:
|
||||
self.sleep_mock.assert_not_called()
|
||||
self.sleep.assert_not_called()
|
||||
|
||||
if expected_poll_ack:
|
||||
self.poll_ack_mock.assert_called_once()
|
||||
self.interface.assert_command_executed(None, PollAck)
|
||||
else:
|
||||
self.poll_ack_mock.assert_not_called()
|
||||
self.interface.assert_command_not_executed(None, PollAck)
|
||||
|
||||
class UpdateSessionTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.controller = Controller(None, None, None)
|
||||
|
||||
self.controller.session = Mock()
|
||||
self.controller.session = create_autospec(Session, instance=True)
|
||||
|
||||
self.controller.session_selector = Mock()
|
||||
self.controller.session_selector = create_autospec(BaseSelector, instance=True)
|
||||
|
||||
patcher = patch('oec.controller.time.perf_counter')
|
||||
|
||||
self.perf_counter_mock = patcher.start()
|
||||
self.perf_counter = patcher.start()
|
||||
|
||||
def test_zero_duration(self):
|
||||
# Act
|
||||
@@ -243,7 +235,7 @@ class UpdateSessionTestCase(unittest.TestCase):
|
||||
|
||||
def test_select_available(self):
|
||||
# Arrange
|
||||
self.perf_counter_mock.side_effect = [0, 0.75, 0.75]
|
||||
self.perf_counter.side_effect = [0, 0.75, 0.75]
|
||||
|
||||
selector_key = Mock(fileobj=self.controller.session)
|
||||
|
||||
|
||||
@@ -1,47 +1,27 @@
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import Mock, create_autospec
|
||||
|
||||
from coax import ReadAddressCounterHi, ReadAddressCounterLo, LoadAddressCounterHi, LoadAddressCounterLo, Feature
|
||||
from coax.protocol import TerminalId
|
||||
|
||||
import context
|
||||
|
||||
from oec.display import Dimensions, Display, StatusLine, BufferedDisplay, encode_ascii_character, encode_ebcdic_character, encode_string
|
||||
from oec.interface import InterfaceWrapper
|
||||
from oec.terminal import Terminal
|
||||
from oec.display import Display, Dimensions, StatusLine, BufferedDisplay, encode_ascii_character, encode_ebcdic_character, encode_string
|
||||
from oec.keymap_3278_2 import KEYMAP as KEYMAP_3278_2
|
||||
|
||||
from mock_interface import MockInterface
|
||||
|
||||
class DisplayClearTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.display = Display(self.terminal, dimensions, None)
|
||||
self.display = _create_display(self.interface)
|
||||
|
||||
self.display.write = Mock(wraps=self.display.write)
|
||||
self.display._load_address_counter = Mock(wraps=self.display._load_address_counter)
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
def test_excluding_status_line_with_no_eab_feature(self):
|
||||
# Act
|
||||
self.display.clear(clear_status_line=False)
|
||||
@@ -82,24 +62,12 @@ class DisplayClearTestCase(unittest.TestCase):
|
||||
|
||||
class DisplayMoveCursorTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.display = Display(self.terminal, dimensions, None)
|
||||
self.display = _create_display(self.interface)
|
||||
|
||||
self.display._load_address_counter = Mock(wraps=self.display._load_address_counter)
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
def test_with_address(self):
|
||||
# Act
|
||||
self.display.move_cursor(address=895)
|
||||
@@ -138,40 +106,14 @@ class DisplayMoveCursorTestCase(unittest.TestCase):
|
||||
|
||||
class DisplayWriteTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.display = Display(self.terminal, dimensions, None)
|
||||
self.display = _create_display(self.interface)
|
||||
|
||||
self.display._read_address_counter = Mock(wraps=self.display._read_address_counter)
|
||||
self.display._load_address_counter = Mock(wraps=self.display._load_address_counter)
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.display._write_data = Mock(wraps=self.display._write_data)
|
||||
self.display._eab_write_alternate = Mock(wraps=self.display._eab_write_alternate)
|
||||
|
||||
def test_no_eab_feature(self):
|
||||
# Act and assert
|
||||
@@ -266,8 +208,10 @@ class DisplayWriteTestCase(unittest.TestCase):
|
||||
# Arrange
|
||||
self.assertIsNone(self.display.address_counter)
|
||||
|
||||
self.read_address_counter_hi_mock.return_value = 0
|
||||
self.read_address_counter_lo_mock.return_value = 160
|
||||
self.interface.mock_responses = [
|
||||
(None, ReadAddressCounterHi, None, 0),
|
||||
(None, ReadAddressCounterLo, None, 160)
|
||||
]
|
||||
|
||||
# Act
|
||||
self.display.write(bytes.fromhex('01 02 03'), None, restore_original_address=True)
|
||||
@@ -299,7 +243,7 @@ class DisplayWriteTestCase(unittest.TestCase):
|
||||
self.display.write(bytes.fromhex('01 02 03'), None)
|
||||
|
||||
# Assert
|
||||
self.write_data_mock.assert_called_with(self.terminal.interface, bytes.fromhex('01 02 03'), jumbo_write_strategy=None)
|
||||
self.display._write_data.assert_called_with(bytes.fromhex('01 02 03'))
|
||||
|
||||
def test_regen_only_repeat(self):
|
||||
# Arrange
|
||||
@@ -309,7 +253,7 @@ class DisplayWriteTestCase(unittest.TestCase):
|
||||
self.display.write((bytes.fromhex('01 02 03'), 2), None)
|
||||
|
||||
# Assert
|
||||
self.write_data_mock.assert_called_with(self.terminal.interface, (bytes.fromhex('01 02 03'), 2), jumbo_write_strategy=None)
|
||||
self.display._write_data.assert_called_with((bytes.fromhex('01 02 03'), 2))
|
||||
|
||||
def test_regen_eab(self):
|
||||
# Arrange
|
||||
@@ -320,7 +264,7 @@ class DisplayWriteTestCase(unittest.TestCase):
|
||||
self.display.write(bytes.fromhex('01 02 03'), bytes.fromhex('04 05 06'))
|
||||
|
||||
# Assert
|
||||
self.eab_write_alternate_mock.assert_called_with(self.terminal.interface, 7, bytes.fromhex('01 04 02 05 03 06'), jumbo_write_strategy=None)
|
||||
self.display._eab_write_alternate.assert_called_with(bytes.fromhex('01 04 02 05 03 06'))
|
||||
|
||||
def test_regen_eab_repeat(self):
|
||||
# Arrange
|
||||
@@ -331,25 +275,13 @@ class DisplayWriteTestCase(unittest.TestCase):
|
||||
self.display.write((bytes.fromhex('01 02 03'), 2), (bytes.fromhex('04 05 06'), 2))
|
||||
|
||||
# Assert
|
||||
self.eab_write_alternate_mock.assert_called_with(self.terminal.interface, 7, (bytes.fromhex('01 04 02 05 03 06'), 2), jumbo_write_strategy=None)
|
||||
self.display._eab_write_alternate.assert_called_with((bytes.fromhex('01 04 02 05 03 06'), 2))
|
||||
|
||||
class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.display = Display(self.terminal, dimensions, None)
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.display = _create_display(self.interface)
|
||||
|
||||
def test(self):
|
||||
# Act
|
||||
@@ -358,15 +290,14 @@ class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.display.address_counter, 895)
|
||||
|
||||
self.load_address_counter_hi_mock.assert_called_with(self.terminal.interface, 3)
|
||||
self.load_address_counter_lo_mock.assert_called_with(self.terminal.interface, 127)
|
||||
self.assert_load_address_counter_hi(3)
|
||||
self.assert_load_address_counter_lo(127)
|
||||
|
||||
def test_hi_change(self):
|
||||
# Arrange
|
||||
self.display._load_address_counter(895, force_load=False)
|
||||
|
||||
self.load_address_counter_hi_mock.reset_mock()
|
||||
self.load_address_counter_lo_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
# Act
|
||||
self.display._load_address_counter(1151, force_load=False)
|
||||
@@ -374,15 +305,14 @@ class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.display.address_counter, 1151)
|
||||
|
||||
self.load_address_counter_hi_mock.assert_called_with(self.terminal.interface, 4)
|
||||
self.load_address_counter_lo_mock.assert_not_called()
|
||||
self.assert_load_address_counter_hi(4)
|
||||
self.interface.assert_command_not_executed(None, LoadAddressCounterLo)
|
||||
|
||||
def test_lo_change(self):
|
||||
# Arrange
|
||||
self.display._load_address_counter(895, force_load=False)
|
||||
|
||||
self.load_address_counter_hi_mock.reset_mock()
|
||||
self.load_address_counter_lo_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
# Act
|
||||
self.display._load_address_counter(896, force_load=False)
|
||||
@@ -390,15 +320,14 @@ class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.display.address_counter, 896)
|
||||
|
||||
self.load_address_counter_hi_mock.assert_not_called()
|
||||
self.load_address_counter_lo_mock.assert_called_with(self.terminal.interface, 128)
|
||||
self.interface.assert_command_not_executed(None, LoadAddressCounterHi)
|
||||
self.assert_load_address_counter_lo(128)
|
||||
|
||||
def test_hi_lo_change(self):
|
||||
# Arrange
|
||||
self.display._load_address_counter(895, force_load=False)
|
||||
|
||||
self.load_address_counter_hi_mock.reset_mock()
|
||||
self.load_address_counter_lo_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
# Act
|
||||
self.display._load_address_counter(1152, force_load=False)
|
||||
@@ -406,15 +335,14 @@ class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.display.address_counter, 1152)
|
||||
|
||||
self.load_address_counter_hi_mock.assert_called_with(self.terminal.interface, 4)
|
||||
self.load_address_counter_lo_mock.assert_called_with(self.terminal.interface, 128)
|
||||
self.assert_load_address_counter_hi(4)
|
||||
self.assert_load_address_counter_lo(128)
|
||||
|
||||
def test_no_change(self):
|
||||
# Arrange
|
||||
self.display._load_address_counter(80, force_load=False)
|
||||
|
||||
self.load_address_counter_hi_mock.reset_mock()
|
||||
self.load_address_counter_lo_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
# Act
|
||||
self.display._load_address_counter(80, force_load=False)
|
||||
@@ -422,15 +350,14 @@ class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.display.address_counter, 80)
|
||||
|
||||
self.load_address_counter_hi_mock.assert_not_called()
|
||||
self.load_address_counter_lo_mock.assert_not_called()
|
||||
self.interface.assert_command_not_executed(None, LoadAddressCounterHi)
|
||||
self.interface.assert_command_not_executed(None, LoadAddressCounterLo)
|
||||
|
||||
def test_no_change_force(self):
|
||||
# Arrange
|
||||
self.display._load_address_counter(80, force_load=False)
|
||||
|
||||
self.load_address_counter_hi_mock.reset_mock()
|
||||
self.load_address_counter_lo_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
# Act
|
||||
self.display._load_address_counter(80, force_load=True)
|
||||
@@ -438,12 +365,18 @@ class DisplayLoadAddressCounterTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.display.address_counter, 80)
|
||||
|
||||
self.load_address_counter_hi_mock.assert_called_with(self.terminal.interface, 0)
|
||||
self.load_address_counter_lo_mock.assert_called_with(self.terminal.interface, 80)
|
||||
self.assert_load_address_counter_hi(0)
|
||||
self.assert_load_address_counter_lo(80)
|
||||
|
||||
def assert_load_address_counter_hi(self, address):
|
||||
self.interface.assert_command_executed(None, LoadAddressCounterHi, lambda command: command.address == address)
|
||||
|
||||
def assert_load_address_counter_lo(self, address):
|
||||
self.interface.assert_command_executed(None, LoadAddressCounterLo, lambda command: command.address == address)
|
||||
|
||||
class StatusLineWriteTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.display = Mock()
|
||||
self.display = create_autospec(Display, instance=True)
|
||||
|
||||
self.display.dimensions = Dimensions(24, 80)
|
||||
|
||||
@@ -462,7 +395,7 @@ class StatusLineWriteTestCase(unittest.TestCase):
|
||||
|
||||
class BufferedDisplayBufferedWriteByteTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.terminal = create_autospec(Terminal, instance=True)
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
@@ -561,40 +494,12 @@ class BufferedDisplayBufferedWriteByteTestCase(unittest.TestCase):
|
||||
|
||||
class BufferedDisplayFlushTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, None)
|
||||
self.buffered_display = _create_buffered_display(self.interface)
|
||||
|
||||
self.buffered_display.write = Mock(wraps=self.buffered_display.write)
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
def test_no_changes(self):
|
||||
# Arrange
|
||||
self.assertFalse(self.buffered_display.dirty)
|
||||
@@ -624,9 +529,7 @@ class BufferedDisplayFlushTestCase(unittest.TestCase):
|
||||
|
||||
def test_single_range_with_eab_feature(self):
|
||||
# Arrange
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, 7)
|
||||
self.buffered_display = _create_buffered_display(self.interface, has_eab=True)
|
||||
|
||||
self.buffered_display.write = Mock(wraps=self.buffered_display.write)
|
||||
|
||||
@@ -669,9 +572,7 @@ class BufferedDisplayFlushTestCase(unittest.TestCase):
|
||||
|
||||
def test_multiple_ranges_with_eab_feature(self):
|
||||
# Arrange
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, 7)
|
||||
self.buffered_display = _create_buffered_display(self.interface, has_eab=True)
|
||||
|
||||
self.buffered_display.write = Mock(wraps=self.buffered_display.write)
|
||||
|
||||
@@ -700,41 +601,13 @@ class BufferedDisplayFlushTestCase(unittest.TestCase):
|
||||
|
||||
class BufferedDisplayClearTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, None)
|
||||
self.buffered_display = _create_buffered_display(self.interface)
|
||||
|
||||
self.buffered_display.write = Mock(wraps=self.buffered_display.write)
|
||||
self.buffered_display._load_address_counter = Mock(wraps=self.buffered_display._load_address_counter)
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
def test_excluding_status_line_with_no_eab_feature(self):
|
||||
# Arrange
|
||||
self.buffered_display.buffered_write_byte(0x01, None, address=80)
|
||||
@@ -753,9 +626,7 @@ class BufferedDisplayClearTestCase(unittest.TestCase):
|
||||
|
||||
def test_excluding_status_line_with_eab_feature(self):
|
||||
# Arrange
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, 7)
|
||||
self.buffered_display = _create_buffered_display(self.interface, has_eab=True)
|
||||
|
||||
self.buffered_display.write = Mock(wraps=self.buffered_display.write)
|
||||
self.buffered_display._load_address_counter = Mock(wraps=self.buffered_display._load_address_counter)
|
||||
@@ -793,9 +664,7 @@ class BufferedDisplayClearTestCase(unittest.TestCase):
|
||||
|
||||
def test_including_status_line_with_eab_feature(self):
|
||||
# Arrange
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, 7)
|
||||
self.buffered_display = _create_buffered_display(self.interface, has_eab=True)
|
||||
|
||||
self.buffered_display.write = Mock(wraps=self.buffered_display.write)
|
||||
self.buffered_display._load_address_counter = Mock(wraps=self.buffered_display._load_address_counter)
|
||||
@@ -817,47 +686,23 @@ class BufferedDisplayClearTestCase(unittest.TestCase):
|
||||
|
||||
class BufferedDisplayWriteTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, None)
|
||||
self.buffered_display = _create_buffered_display(self.interface)
|
||||
|
||||
self.buffered_display._read_address_counter = Mock(wraps=self.buffered_display._read_address_counter)
|
||||
self.buffered_display._load_address_counter = Mock(wraps=self.buffered_display._load_address_counter)
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.buffered_display._write_data = Mock(wraps=self.buffered_display._write_data)
|
||||
self.buffered_display._eab_write_alternate = Mock(wraps=self.buffered_display._eab_write_alternate)
|
||||
|
||||
def test_if_current_address_unknown(self):
|
||||
# Arrange
|
||||
self.assertIsNone(self.buffered_display.address_counter)
|
||||
|
||||
self.read_address_counter_hi_mock.return_value = 0
|
||||
self.read_address_counter_lo_mock.return_value = 160
|
||||
self.interface.mock_responses = [
|
||||
(None, ReadAddressCounterHi, None, 0),
|
||||
(None, ReadAddressCounterLo, None, 160)
|
||||
]
|
||||
|
||||
# Act
|
||||
self.buffered_display.write(bytes.fromhex('01 02 03'), None)
|
||||
@@ -895,7 +740,7 @@ class BufferedDisplayWriteTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.buffered_display.regen_buffer[80:83], bytes.fromhex('01 02 03'))
|
||||
|
||||
self.write_data_mock.assert_called_with(self.terminal.interface, bytes.fromhex('01 02 03'), jumbo_write_strategy=None)
|
||||
self.buffered_display._write_data.assert_called_with(bytes.fromhex('01 02 03'))
|
||||
|
||||
def test_regen_only_repeat(self):
|
||||
# Arrange
|
||||
@@ -907,16 +752,16 @@ class BufferedDisplayWriteTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.assertEqual(self.buffered_display.regen_buffer[80:86], bytes.fromhex('01 02 03 01 02 03'))
|
||||
|
||||
self.write_data_mock.assert_called_with(self.terminal.interface, (bytes.fromhex('01 02 03'), 2), jumbo_write_strategy=None)
|
||||
self.buffered_display._write_data.assert_called_with((bytes.fromhex('01 02 03'), 2))
|
||||
|
||||
def test_regen_eab(self):
|
||||
# Arrange
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, 7)
|
||||
self.buffered_display = _create_buffered_display(self.interface, has_eab=True)
|
||||
|
||||
self.buffered_display._read_address_counter = Mock(wraps=self.buffered_display._read_address_counter)
|
||||
self.buffered_display._load_address_counter = Mock(wraps=self.buffered_display._load_address_counter)
|
||||
self.buffered_display._write_data = Mock(wraps=self.buffered_display._write_data)
|
||||
self.buffered_display._eab_write_alternate = Mock(wraps=self.buffered_display._eab_write_alternate)
|
||||
|
||||
self.buffered_display.address_counter = 80
|
||||
|
||||
@@ -927,16 +772,16 @@ class BufferedDisplayWriteTestCase(unittest.TestCase):
|
||||
self.assertEqual(self.buffered_display.regen_buffer[80:83], bytes.fromhex('01 02 03'))
|
||||
self.assertEqual(self.buffered_display.eab_buffer[80:83], bytes.fromhex('04 05 06'))
|
||||
|
||||
self.eab_write_alternate_mock.assert_called_with(self.terminal.interface, 7, bytes.fromhex('01 04 02 05 03 06'), jumbo_write_strategy=None)
|
||||
self.buffered_display._eab_write_alternate.assert_called_with(bytes.fromhex('01 04 02 05 03 06'))
|
||||
|
||||
def test_regen_eab_repeat(self):
|
||||
# Arrange
|
||||
dimensions = Dimensions(24, 80)
|
||||
|
||||
self.buffered_display = BufferedDisplay(self.terminal, dimensions, 7)
|
||||
self.buffered_display = _create_buffered_display(self.interface, has_eab=True)
|
||||
|
||||
self.buffered_display._read_address_counter = Mock(wraps=self.buffered_display._read_address_counter)
|
||||
self.buffered_display._load_address_counter = Mock(wraps=self.buffered_display._load_address_counter)
|
||||
self.buffered_display._write_data = Mock(wraps=self.buffered_display._write_data)
|
||||
self.buffered_display._eab_write_alternate = Mock(wraps=self.buffered_display._eab_write_alternate)
|
||||
|
||||
self.buffered_display.address_counter = 80
|
||||
|
||||
@@ -947,7 +792,7 @@ class BufferedDisplayWriteTestCase(unittest.TestCase):
|
||||
self.assertEqual(self.buffered_display.regen_buffer[80:86], bytes.fromhex('01 02 03 01 02 03'))
|
||||
self.assertEqual(self.buffered_display.eab_buffer[80:86], bytes.fromhex('04 05 06 04 05 06'))
|
||||
|
||||
self.eab_write_alternate_mock.assert_called_with(self.terminal.interface, 7, (bytes.fromhex('01 04 02 05 03 06'), 2), jumbo_write_strategy=None)
|
||||
self.buffered_display._eab_write_alternate.assert_called_with((bytes.fromhex('01 04 02 05 03 06'), 2))
|
||||
|
||||
def test_dirty_cleared(self):
|
||||
# Arrange
|
||||
@@ -993,3 +838,29 @@ class EncodeStringTestCase(unittest.TestCase):
|
||||
|
||||
def test_unmapped_characters(self):
|
||||
self.assertEqual(encode_string('Everything ✓'), bytes.fromhex('a4 95 84 91 98 93 87 88 8d 86 00 18'))
|
||||
|
||||
def _create_display(interface):
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { }
|
||||
keymap = KEYMAP_3278_2
|
||||
|
||||
terminal = Terminal(InterfaceWrapper(interface), None, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
display = Display(terminal, dimensions, features.get(Feature.EAB))
|
||||
|
||||
return display
|
||||
|
||||
def _create_buffered_display(interface, has_eab=False):
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { Feature.EAB: 7 } if has_eab else { }
|
||||
keymap = KEYMAP_3278_2
|
||||
|
||||
terminal = Terminal(InterfaceWrapper(interface), None, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
buffered_display = BufferedDisplay(terminal, dimensions, features.get(Feature.EAB))
|
||||
|
||||
return buffered_display
|
||||
|
||||
202
tests/test_interface.py
Normal file
202
tests/test_interface.py
Normal file
@@ -0,0 +1,202 @@
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from coax import ReadAddressCounterHi, ReadAddressCounterLo, ProtocolError
|
||||
|
||||
import context
|
||||
|
||||
from oec.interface import InterfaceWrapper, AggregateExecuteError, address_commands
|
||||
|
||||
from mock_interface import MockInterface
|
||||
|
||||
class InterfaceWrapperInitTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = MockInterface()
|
||||
|
||||
patcher = patch('oec.interface._get_jumbo_write_strategy')
|
||||
|
||||
self.get_jumbo_write_strategy = patcher.start()
|
||||
|
||||
patcher = patch('oec.interface._print_i1_jumbo_write_notice')
|
||||
|
||||
self.print_i1_jumbo_write_notice = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
def test_no_jumbo_write_strategy(self):
|
||||
# Arrange
|
||||
self.get_jumbo_write_strategy.return_value = None
|
||||
|
||||
# Act
|
||||
interface_wrapper = InterfaceWrapper(self.interface)
|
||||
|
||||
# Assert
|
||||
self.assertIsNone(interface_wrapper.jumbo_write_strategy)
|
||||
self.assertIsNone(interface_wrapper.jumbo_write_max_length)
|
||||
|
||||
self.print_i1_jumbo_write_notice.assert_not_called()
|
||||
|
||||
def test_split_jumbo_write_strategy(self):
|
||||
# Arrange
|
||||
self.get_jumbo_write_strategy.return_value = 'split'
|
||||
|
||||
# Act
|
||||
interface_wrapper = InterfaceWrapper(self.interface)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(interface_wrapper.jumbo_write_strategy, 'split')
|
||||
self.assertEqual(interface_wrapper.jumbo_write_max_length, 1024)
|
||||
|
||||
self.print_i1_jumbo_write_notice.assert_not_called()
|
||||
|
||||
def test_i1_no_jumbo_write_strategy(self):
|
||||
# Arrange
|
||||
self.interface.legacy_firmware_detected = True
|
||||
|
||||
self.get_jumbo_write_strategy.return_value = None
|
||||
|
||||
# Act
|
||||
interface_wrapper = InterfaceWrapper(self.interface)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(interface_wrapper.jumbo_write_strategy, 'split')
|
||||
self.assertEqual(interface_wrapper.jumbo_write_max_length, 1024)
|
||||
|
||||
self.print_i1_jumbo_write_notice.assert_called()
|
||||
|
||||
class InterfaceWrapperExecuteTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.interface_wrapper = InterfaceWrapper(self.interface)
|
||||
|
||||
def test_single_command(self):
|
||||
# Arrange
|
||||
self.interface.mock_responses = [(None, ReadAddressCounterHi, None, 0x00)]
|
||||
|
||||
# Act
|
||||
response = self.interface_wrapper.execute((None, ReadAddressCounterHi()))
|
||||
|
||||
# Assert
|
||||
self.assertEqual(response, 0x00)
|
||||
|
||||
def test_single_command_that_raises_error(self):
|
||||
# Arrange
|
||||
self.interface.mock_responses = [(None, ReadAddressCounterHi, None, Mock(side_effect=ProtocolError))]
|
||||
|
||||
# Act and assert
|
||||
with self.assertRaises(ProtocolError):
|
||||
self.interface_wrapper.execute((None, ReadAddressCounterHi()))
|
||||
|
||||
def test_multiple_commands(self):
|
||||
# Arrange
|
||||
self.interface.mock_responses = [
|
||||
(None, ReadAddressCounterHi, None, 0x00),
|
||||
(None, ReadAddressCounterLo, None, 0xff)
|
||||
]
|
||||
|
||||
# Act
|
||||
responses = self.interface_wrapper.execute([(None, ReadAddressCounterHi()), (None, ReadAddressCounterLo())])
|
||||
|
||||
# Assert
|
||||
self.assertEqual(responses, [0x00, 0xff])
|
||||
|
||||
def test_multiple_commands_that_returns_error(self):
|
||||
# Arrange
|
||||
self.interface.mock_responses = [
|
||||
(None, ReadAddressCounterHi, None, 0x00),
|
||||
(None, ReadAddressCounterLo, None, Mock(side_effect=ProtocolError))
|
||||
]
|
||||
|
||||
# Act and assert
|
||||
with self.assertRaises(AggregateExecuteError) as context:
|
||||
self.interface_wrapper.execute([(None, ReadAddressCounterHi()), (None, ReadAddressCounterLo())])
|
||||
|
||||
error = context.exception
|
||||
|
||||
self.assertEqual(len(error.errors), 1)
|
||||
self.assertIsInstance(error.errors[0], ProtocolError)
|
||||
|
||||
self.assertEqual(len(error.responses), 2)
|
||||
|
||||
class InterfaceWrapperJumboWriteSplitDataTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.interface_wrapper = InterfaceWrapper(self.interface)
|
||||
|
||||
def test_no_split_strategy(self):
|
||||
# Arrange
|
||||
self.interface_wrapper.jumbo_write_strategy = None
|
||||
self.interface_wrapper.jumbo_write_max_length = 32
|
||||
|
||||
# Act and assert
|
||||
for data in [bytes(range(0, 64)), (bytes.fromhex('00'), 64)]:
|
||||
with self.subTest(data=data):
|
||||
result = self.interface_wrapper.jumbo_write_split_data(data)
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
self.assertEqual(result[0], data)
|
||||
|
||||
def test_split_strategy_one_chunk(self):
|
||||
# Arrange
|
||||
self.interface_wrapper.jumbo_write_strategy = 'split'
|
||||
self.interface_wrapper.jumbo_write_max_length = 32
|
||||
|
||||
# Act and assert
|
||||
for data in [bytes(range(0, 16)), (bytes.fromhex('00'), 16), bytes(range(0, 31)), (bytes.fromhex('00'), 31)]:
|
||||
with self.subTest(data=data):
|
||||
result = self.interface_wrapper.jumbo_write_split_data(data)
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
self.assertEqual(result[0], data)
|
||||
|
||||
def test_split_strategy_two_chunks(self):
|
||||
# Arrange
|
||||
self.interface_wrapper.jumbo_write_strategy = 'split'
|
||||
self.interface_wrapper.jumbo_write_max_length = 32
|
||||
|
||||
# Act and assert
|
||||
for data in [bytes(range(0, 32)), (bytes.fromhex('00'), 32), bytes(range(0, 63)), (bytes.fromhex('00'), 63)]:
|
||||
with self.subTest(data=data):
|
||||
result = self.interface_wrapper.jumbo_write_split_data(data)
|
||||
|
||||
self.assertEqual(len(result), 2)
|
||||
self.assertEqual(len(result[0]), 31)
|
||||
|
||||
def test_split_strategy_three_chunks(self):
|
||||
# Arrange
|
||||
self.interface_wrapper.jumbo_write_strategy = 'split'
|
||||
self.interface_wrapper.jumbo_write_max_length = 32
|
||||
|
||||
# Act and assert
|
||||
for data in [bytes(range(0, 64)), (bytes.fromhex('00'), 64), bytes(range(0, 95)), (bytes.fromhex('00'), 95)]:
|
||||
with self.subTest(data=data):
|
||||
result = self.interface_wrapper.jumbo_write_split_data(data)
|
||||
|
||||
self.assertEqual(len(result), 3)
|
||||
self.assertEqual(len(result[0]), 31)
|
||||
self.assertEqual(len(result[1]), 32)
|
||||
|
||||
class AddressCommandsTestCase(unittest.TestCase):
|
||||
def test_single_command(self):
|
||||
# Arrange
|
||||
command = ReadAddressCounterHi()
|
||||
|
||||
# Act
|
||||
result = address_commands(0b111000, command)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(result, (0b111000, command))
|
||||
|
||||
def test_multiple_commands(self):
|
||||
# Arrange
|
||||
commands = [ReadAddressCounterHi(), ReadAddressCounterLo()]
|
||||
|
||||
# Act
|
||||
result = address_commands(0b111000, commands)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(result, [(0b111000, commands[0]), (0b111000, commands[1])])
|
||||
@@ -1,68 +1,49 @@
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from coax import Feature, PollAction
|
||||
from coax.protocol import TerminalId, TerminalType
|
||||
from unittest.mock import Mock, create_autospec
|
||||
from coax import Poll, PollAction, TerminalType, Feature, ReadTerminalId, ReadExtendedId, ReadFeatureId
|
||||
from coax.protocol import TerminalId
|
||||
|
||||
import context
|
||||
|
||||
from oec.interface import InterfaceWrapper
|
||||
from oec.terminal import create_terminal, Terminal, UnsupportedTerminalError
|
||||
from oec.display import Dimensions
|
||||
from oec.display import Display, Dimensions
|
||||
from oec.keymap_3278_2 import KEYMAP as KEYMAP_3278_2
|
||||
|
||||
from mock_interface import MockInterface
|
||||
|
||||
class TerminalSetupTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { }
|
||||
keymap = KEYMAP_3278_2
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.terminal = Terminal(self.interface, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
self.terminal.display = Mock()
|
||||
|
||||
patcher = patch('oec.terminal.load_control_register')
|
||||
|
||||
self.load_control_register_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.terminal.display = create_autospec(Display, instance=True)
|
||||
|
||||
def test(self):
|
||||
self.terminal.setup()
|
||||
|
||||
class TerminalPollTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { }
|
||||
keymap = KEYMAP_3278_2
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.terminal = Terminal(self.interface, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
patcher = patch('oec.terminal.poll')
|
||||
|
||||
self.poll_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.terminal.display = create_autospec(Display, instance=True)
|
||||
|
||||
# The terminal will be initialized in a state where the terminal keyboard clicker
|
||||
# state is unknown, and this cannot be read. Therefore the first POLL will always
|
||||
# attempt to set the keyboard clicker state...
|
||||
self.terminal.poll()
|
||||
|
||||
self.poll_mock.reset_mock()
|
||||
self.interface.reset_mock()
|
||||
|
||||
def test_with_no_queued_actions(self):
|
||||
# Act
|
||||
self.terminal.poll()
|
||||
|
||||
# Assert
|
||||
self.poll_mock.assert_called_with(self.interface, PollAction.NONE)
|
||||
self.assert_poll_with_poll_action(PollAction.NONE)
|
||||
|
||||
def test_with_sound_alarm_queued(self):
|
||||
# Arrange
|
||||
@@ -72,7 +53,7 @@ class TerminalPollTestCase(unittest.TestCase):
|
||||
self.terminal.poll()
|
||||
|
||||
# Assert
|
||||
self.poll_mock.assert_called_with(self.interface, PollAction.ALARM)
|
||||
self.assert_poll_with_poll_action(PollAction.ALARM)
|
||||
|
||||
def test_with_enable_keyboard_clicker_queued(self):
|
||||
# Arrange
|
||||
@@ -84,38 +65,29 @@ class TerminalPollTestCase(unittest.TestCase):
|
||||
self.terminal.poll()
|
||||
|
||||
# Assert
|
||||
self.poll_mock.assert_called_with(self.interface, PollAction.ENABLE_KEYBOARD_CLICKER)
|
||||
self.assert_poll_with_poll_action(PollAction.ENABLE_KEYBOARD_CLICKER)
|
||||
|
||||
def assert_poll_with_poll_action(self, action):
|
||||
self.interface.assert_command_executed(None, Poll, lambda command: command.action == action)
|
||||
|
||||
class CreateTerminalTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.interface = Mock()
|
||||
|
||||
self.interface.legacy_firmware_detected = False
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.get_keymap = lambda terminal_id, extended_id: KEYMAP_3278_2
|
||||
|
||||
patcher = patch('oec.terminal.read_terminal_id')
|
||||
|
||||
self.read_terminal_id_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.terminal.read_extended_id')
|
||||
|
||||
self.read_extended_id_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.terminal.get_features')
|
||||
|
||||
self.get_features_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
|
||||
def test_supported_terminal(self):
|
||||
# Arrange
|
||||
self.read_terminal_id_mock.return_value = TerminalId(0b11110100)
|
||||
self.read_extended_id_mock.return_value = bytes.fromhex('c1 34 83 00')
|
||||
self.get_features_mock.return_value = { Feature.EAB: 7 }
|
||||
interface = InterfaceWrapper(self.interface)
|
||||
|
||||
self.interface.mock_responses = [
|
||||
(None, ReadTerminalId, None, TerminalId(0b11110100)),
|
||||
(None, ReadExtendedId, None, bytes.fromhex('c1 34 83 00')),
|
||||
(None, ReadFeatureId, lambda command: command.feature_address == 7, Feature.EAB.value)
|
||||
]
|
||||
|
||||
# Act
|
||||
terminal = create_terminal(self.interface, None, self.get_keymap)
|
||||
terminal = create_terminal(interface, None, None, self.get_keymap)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(terminal.terminal_id.type, TerminalType.CUT)
|
||||
@@ -128,46 +100,34 @@ class CreateTerminalTestCase(unittest.TestCase):
|
||||
|
||||
def test_unsupported_terminal_type(self):
|
||||
# Arrange
|
||||
self.read_terminal_id_mock.return_value = TerminalId(0b00000001)
|
||||
interface = InterfaceWrapper(self.interface)
|
||||
|
||||
self.interface.mock_responses = [(None, ReadTerminalId, None, TerminalId(0b00000001))]
|
||||
|
||||
# Act and assert
|
||||
with self.assertRaises(UnsupportedTerminalError):
|
||||
create_terminal(self.interface, None, self.get_keymap)
|
||||
create_terminal(interface, None, None, self.get_keymap)
|
||||
|
||||
def test_unsupported_terminal_model(self):
|
||||
# Arrange
|
||||
interface = InterfaceWrapper(self.interface)
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
|
||||
terminal_id.model = 1
|
||||
|
||||
self.read_terminal_id_mock.return_value = terminal_id
|
||||
self.interface.mock_responses = [(None, ReadTerminalId, None, terminal_id)]
|
||||
|
||||
# Act and assert
|
||||
with self.assertRaises(UnsupportedTerminalError):
|
||||
create_terminal(self.interface, None, self.get_keymap)
|
||||
create_terminal(interface, None, None, self.get_keymap)
|
||||
|
||||
def test_eab_feature_removed_on_legacy_interface_without_strategy(self):
|
||||
# Arrange
|
||||
self.interface.legacy_firmware_detected = True
|
||||
def _create_terminal(interface):
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { }
|
||||
keymap = KEYMAP_3278_2
|
||||
|
||||
self.read_terminal_id_mock.return_value = TerminalId(0b11110100)
|
||||
self.read_extended_id_mock.return_value = bytes.fromhex('c1 34 83 00')
|
||||
self.get_features_mock.return_value = { Feature.EAB: 7 }
|
||||
terminal = Terminal(InterfaceWrapper(interface), None, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
patcher = patch('oec.terminal._print_no_i1_eab_notice')
|
||||
|
||||
print_no_i1_eab_notice_mock = patcher.start()
|
||||
|
||||
# Act
|
||||
terminal = create_terminal(self.interface, None, self.get_keymap)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(terminal.terminal_id.type, TerminalType.CUT)
|
||||
self.assertEqual(terminal.terminal_id.model, 2)
|
||||
self.assertEqual(terminal.terminal_id.keyboard, 15)
|
||||
self.assertEqual(terminal.extended_id, 'c1348300')
|
||||
self.assertEqual(terminal.display.dimensions, Dimensions(24, 80))
|
||||
self.assertEqual(terminal.features, { })
|
||||
self.assertEqual(terminal.keyboard.keymap.name, '3278-2')
|
||||
|
||||
print_no_i1_eab_notice_mock.assert_called_once()
|
||||
return terminal
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import Mock, create_autospec
|
||||
|
||||
import context
|
||||
|
||||
from oec.session import SessionDisconnectedError
|
||||
from oec.display import Dimensions, BufferedDisplay
|
||||
from oec.keyboard import Key, KeyboardModifiers
|
||||
from oec.tn3270 import TN3270Session
|
||||
from tn3270 import AttributeCell, CharacterCell, AID, Color, ProtectedCellOperatorError, FieldOverflowOperatorError
|
||||
from coax.protocol import TerminalId
|
||||
from tn3270 import Telnet, Emulator, AttributeCell, CharacterCell, AID, Color, ProtectedCellOperatorError, FieldOverflowOperatorError
|
||||
from tn3270.attributes import Attribute
|
||||
from tn3270.emulator import CellFormatting
|
||||
|
||||
import context
|
||||
|
||||
from oec.interface import InterfaceWrapper
|
||||
from oec.terminal import Terminal
|
||||
from oec.display import Dimensions, BufferedDisplay, StatusLine
|
||||
from oec.keyboard import Key, KeyboardModifiers
|
||||
from oec.keymap_3278_2 import KEYMAP as KEYMAP_3278_2
|
||||
from oec.session import SessionDisconnectedError
|
||||
from oec.tn3270 import TN3270Session
|
||||
|
||||
from mock_interface import MockInterface
|
||||
|
||||
class SessionHandleHostTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.session = TN3270Session(self.terminal, 'mainframe', 23)
|
||||
|
||||
self.telnet = Mock()
|
||||
self.telnet = create_autospec(Telnet, instance=True)
|
||||
|
||||
self.session.telnet = self.telnet
|
||||
self.session.emulator = Mock()
|
||||
self.session.emulator = create_autospec(Emulator, instance=True)
|
||||
|
||||
def test_no_changes(self):
|
||||
# Arrange
|
||||
@@ -58,11 +67,13 @@ class SessionHandleHostTestCase(unittest.TestCase):
|
||||
|
||||
class SessionHandleKeyTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.session = TN3270Session(self.terminal, 'mainframe', 23)
|
||||
|
||||
self.session.emulator = Mock()
|
||||
self.session.emulator = create_autospec(Emulator, instance=True)
|
||||
|
||||
self.session.emulator.cells = []
|
||||
self.session.emulator.dirty = set()
|
||||
@@ -206,9 +217,9 @@ class SessionHandleKeyTestCase(unittest.TestCase):
|
||||
|
||||
class SessionRenderTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.terminal.display = BufferedDisplay(self.terminal, Dimensions(24, 80), None)
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.terminal.display.buffered_write_byte = Mock(wraps=self.terminal.display.buffered_write_byte)
|
||||
self.terminal.display.move_cursor = Mock(wraps=self.terminal.display.move_cursor)
|
||||
@@ -217,36 +228,10 @@ class SessionRenderTestCase(unittest.TestCase):
|
||||
|
||||
self.session = TN3270Session(self.terminal, 'mainframe', 23)
|
||||
|
||||
self.telnet = Mock()
|
||||
self.session.telnet = create_autospec(Telnet, instance=True)
|
||||
self.session.emulator = create_autospec(Emulator, instance=True)
|
||||
|
||||
self.session.telnet = self.telnet
|
||||
self.session.emulator = Mock()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.session.emulator.keyboard_locked = False
|
||||
|
||||
def test_with_no_eab_feature(self):
|
||||
# Arrange
|
||||
@@ -382,6 +367,19 @@ class SessionRenderTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.terminal.display.status_line.write.assert_called_with(8, bytes.fromhex('f600db080000000000'))
|
||||
|
||||
def _create_terminal(interface):
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { }
|
||||
keymap = KEYMAP_3278_2
|
||||
|
||||
terminal = Terminal(InterfaceWrapper(interface), None, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
terminal.display.status_line = create_autospec(StatusLine, instance=True)
|
||||
|
||||
return terminal
|
||||
|
||||
def _create_screen_cells(rows, columns):
|
||||
return [CharacterCell(0x00) for address in range(rows * columns)]
|
||||
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import Mock, create_autospec
|
||||
|
||||
from logging import Logger
|
||||
from ptyprocess import PtyProcess
|
||||
from coax.protocol import TerminalId
|
||||
|
||||
import context
|
||||
|
||||
from oec.session import SessionDisconnectedError
|
||||
from oec.interface import InterfaceWrapper
|
||||
from oec.terminal import Terminal
|
||||
from oec.display import Dimensions, BufferedDisplay
|
||||
from oec.keyboard import Key, KeyboardModifiers
|
||||
from oec.keymap_3278_2 import KEYMAP as KEYMAP_3278_2
|
||||
from oec.session import SessionDisconnectedError
|
||||
from oec.vt100 import VT100Session
|
||||
|
||||
from mock_interface import MockInterface
|
||||
|
||||
class SessionHandleHostTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.terminal.display.dimensions = Dimensions(24, 80)
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.terminal.sound_alarm = Mock(wraps=self.terminal.sound_alarm)
|
||||
|
||||
self.session = VT100Session(self.terminal, None)
|
||||
|
||||
self.session.host_process = Mock()
|
||||
self.session.host_process = create_autospec(PtyProcess, instance=True)
|
||||
|
||||
def test(self):
|
||||
# Arrange
|
||||
@@ -54,13 +65,13 @@ class SessionHandleHostTestCase(unittest.TestCase):
|
||||
|
||||
class SessionHandleKeyTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.terminal.display.dimensions = Dimensions(24, 80)
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.session = VT100Session(self.terminal, None)
|
||||
|
||||
self.session.host_process = Mock()
|
||||
self.session.host_process = create_autospec(PtyProcess, instance=True)
|
||||
|
||||
def test_printable(self):
|
||||
# Act
|
||||
@@ -87,7 +98,7 @@ class SessionHandleKeyTestCase(unittest.TestCase):
|
||||
|
||||
def test_unmapped_alt_modifier(self):
|
||||
# Arrange
|
||||
self.session.logger = Mock()
|
||||
self.session.logger = create_autospec(Logger, instance=True)
|
||||
|
||||
# Act
|
||||
self.session.handle_key(Key.THREE, KeyboardModifiers.LEFT_ALT, None)
|
||||
@@ -106,9 +117,9 @@ class SessionHandleKeyTestCase(unittest.TestCase):
|
||||
|
||||
class SessionRenderTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.terminal = Mock()
|
||||
self.interface = MockInterface()
|
||||
|
||||
self.terminal.display = BufferedDisplay(self.terminal, Dimensions(24, 80), None)
|
||||
self.terminal = _create_terminal(self.interface)
|
||||
|
||||
self.terminal.display.buffered_write_byte = Mock(wraps=self.terminal.display.buffered_write_byte)
|
||||
self.terminal.display.move_cursor = Mock(wraps=self.terminal.display.move_cursor)
|
||||
@@ -116,33 +127,7 @@ class SessionRenderTestCase(unittest.TestCase):
|
||||
|
||||
self.session = VT100Session(self.terminal, None)
|
||||
|
||||
self.session.host_process = Mock()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_hi')
|
||||
|
||||
self.read_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.read_address_counter_lo')
|
||||
|
||||
self.read_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_hi')
|
||||
|
||||
self.load_address_counter_hi_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.load_address_counter_lo')
|
||||
|
||||
self.load_address_counter_lo_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.write_data')
|
||||
|
||||
self.write_data_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.display.eab_write_alternate')
|
||||
|
||||
self.eab_write_alternate_mock = patcher.start()
|
||||
|
||||
self.addCleanup(patch.stopall)
|
||||
self.session.host_process = create_autospec(PtyProcess, instance=True)
|
||||
|
||||
def test_with_no_eab_feature(self):
|
||||
# Arrange
|
||||
@@ -189,3 +174,14 @@ class SessionRenderTestCase(unittest.TestCase):
|
||||
self.terminal.display.move_cursor.assert_called_with(row=0, column=3)
|
||||
|
||||
self.assertFalse(self.session.vt100_screen.dirty)
|
||||
|
||||
def _create_terminal(interface):
|
||||
terminal_id = TerminalId(0b11110100)
|
||||
extended_id = 'c1348300'
|
||||
dimensions = Dimensions(24, 80)
|
||||
features = { }
|
||||
keymap = KEYMAP_3278_2
|
||||
|
||||
terminal = Terminal(InterfaceWrapper(interface), None, terminal_id, extended_id, dimensions, features, keymap)
|
||||
|
||||
return terminal
|
||||
|
||||
Reference in New Issue
Block a user