S1005403_RisCC/tests/gui/test_main_view_reset.py

137 lines
4.5 KiB
Python

import logging
from unittest.mock import Mock
import pytest
from target_simulator.gui import main_view as mv
def _make_minimal_mainview_with_comm(use_json: bool):
# Bypass __init__ to avoid Tkinter initialization in tests
inst = mv.MainView.__new__(mv.MainView)
# Provide a simple logger
inst.logger = logging.getLogger("test.main_view")
# Mock communicator
comm = Mock()
comm.is_open = True
# Emulate the internal flag used by MainView to decide JSON vs legacy
setattr(comm, "_use_json_protocol", use_json)
comm.send_commands.return_value = True
inst.target_communicator = comm
# Mock simulation hub: immediate empty state so reset returns quickly
hub = Mock()
hub.has_active_real_targets.return_value = False
inst.simulation_hub = hub
# Attach a lightweight stub SimulationController so the test calls
# delegate to a controller instance (the real app routes through
# SimulationController.reset_radar_state). This avoids complex
# initialization while reflecting current production behavior.
class _StubSimulationController:
def __init__(self, comm):
self._comm = comm
def reset_radar_state(self, main_view):
# Mirror the behavior expected by the tests: choose JSON
# or legacy reset depending on communicator flag.
target_comm = getattr(main_view, "target_communicator", None) or self._comm
if not target_comm or not getattr(target_comm, "is_open", False):
return False
use_json = getattr(target_comm, "_use_json_protocol", False)
try:
if use_json:
return bool(target_comm.send_commands(['{"CMD":"reset"}\n']))
# legacy path sends preparatory rows and atomic tgtset
target_comm.send_commands(["mex.t_rows=80\n"])
return bool(target_comm.send_commands(["tgtset /-s\n"]))
except Exception:
return False
inst.simulation_controller = _StubSimulationController(comm)
return inst, comm
def test_reset_uses_json_when_configured():
inst, comm = _make_minimal_mainview_with_comm(use_json=True)
ok = inst._reset_radar_state()
assert ok is True
# send_commands should be called once with the JSON reset payload
assert comm.send_commands.called
sent = comm.send_commands.call_args[0][0]
assert isinstance(sent, list)
assert sent == ['{"CMD":"reset"}\n']
def test_reset_uses_legacy_when_not_configured():
inst, comm = _make_minimal_mainview_with_comm(use_json=False)
ok = inst._reset_radar_state()
assert ok is True
assert comm.send_commands.called
# The implementation may send preparatory commands in a separate
# call followed by the atomic tgtset. Collect all sent command lists
# across calls and verify the expected sequence appears.
assert comm.send_commands.call_count >= 1
all_sent = []
for call in comm.send_commands.call_args_list:
args = call[0][0] if call and call[0] else []
if isinstance(args, list):
all_sent.extend(args)
assert "mex.t_rows=80\n" in all_sent
assert "tgtset /-s\n" in all_sent
import pytest
from target_simulator.gui.main_view import MainView
from target_simulator.core.models import Target
class DummyCommunicator:
def __init__(self):
self.sent_commands = []
self.is_open = True
def send_commands(self, commands):
self.sent_commands.extend(commands)
return True
def connect(self, cfg):
self.is_open = True
return True
def disconnect(self):
self.is_open = False
@pytest.fixture
def main_view(tmp_path, monkeypatch):
# Create a MainView but avoid opening the Tk mainloop
mv = MainView()
# Replace actual communicators with dummy to avoid I/O
dummy = DummyCommunicator()
mv.target_communicator = dummy
return mv
def test_reset_radar_state_sends_atomic_tgtset(main_view):
mv = main_view
# Ensure that the communicator reports open
assert mv.target_communicator.is_open
# Call the reset function
result = mv._reset_radar_state()
# Expect success
assert result is True
# Verify that two commands were sent: preparatory mex.t_rows=80 then tgtset /-s
assert len(mv.target_communicator.sent_commands) == 2
assert mv.target_communicator.sent_commands[0].strip() == "mex.t_rows=80"
assert mv.target_communicator.sent_commands[1].strip() == "tgtset /-s"