"""Shared terminal macro lifecycle, without physical UART hardware.""" import os import unittest os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") from PySide6.QtWidgets import QApplication from PySide6.QtCore import QEventLoop, QTimer from pysetterminal.rawprotocol import RawProtocolWidget from pysetterminal.serialbus import SerialBus, SerialTab def process_events(milliseconds): loop = QEventLoop() QTimer.singleShot(milliseconds, loop.quit) loop.exec() class PendingProtocol: def __init__(self): self.requests = [] self.callback = None def request_async(self, address, value, device_address, callback): self.requests.append((address, value)) self.callback = callback def cancel_async(self): callback, self.callback = self.callback, None if callback: callback(False, "cancelled") class MacroTests(unittest.TestCase): def setUp(self): self.app = QApplication.instance() or QApplication([]) self.protocol = PendingProtocol() self.raw = RawProtocolWidget(self.protocol) self.tab = SerialTab(SerialBus(self.protocol), self.protocol, self.raw) self.command = {'type': 'read', 'tetrad': 3, 'register': 5} def tearDown(self): self.tab.stop_macro() self.tab.close() self.raw.close() def test_scheduled_execution_returns_and_can_be_cancelled(self): self.tab.execute_macro_commands([self.command]) self.assertEqual(self.protocol.requests, []) process_events(20) self.assertEqual(self.protocol.requests, [(0x200B, 0x35)]) self.assertTrue(self.tab.stop_macro_btn.isEnabled()) self.tab.stop_macro() process_events(20) self.assertFalse(self.tab._macro_running) self.assertTrue(self.tab.bus_read_btn.isEnabled()) self.assertEqual(len(self.protocol.requests), 1) def test_cancelled_scheduled_work_does_not_enter_new_macro(self): self.tab.execute_macro_commands([self.command]) self.tab.stop_macro() self.tab.execute_macro_commands([self.command]) process_events(20) self.assertEqual(len(self.protocol.requests), 1) self.protocol.callback(False, "CRC error") process_events(20) self.assertFalse(self.tab._macro_running) self.assertEqual(len(self.protocol.requests), 1) def test_completion_runs_next_step_and_updates_value(self): self.tab.execute_macro_commands([self.command]) process_events(20) self.protocol.callback(True, {'raw': b"ack"}) process_events(20) self.assertEqual(self.protocol.requests[-1], (0x200F, None)) self.protocol.callback(True, {'value': 0x1234, 'raw_response': {'raw': b"reply"}}) process_events(20) self.assertFalse(self.tab._macro_running) self.assertEqual(self.tab.bus_read_value_label.text(), "0x1234 (4660)")