@@ -95,22 +95,81 @@ def readline_side_effect():
9595 controller = SignalduinoController (transport = mock_transport , parser = mock_parser )
9696 controller .connect ()
9797 try :
98- response = controller .send_command ( "V" , expect_response = True , timeout = 1 )
98+ response = controller .commands . get_version ( timeout = 1 )
9999 mock_transport .write_line .assert_called_with ("V" )
100100 assert response is not None
101101 assert "SIGNALduino" in response
102102 finally :
103103 controller .disconnect ()
104104
105105
106+ def test_send_command_with_interleaved_message (mock_transport , mock_parser ):
107+ """
108+ Test sending a command and receiving an irrelevant message before the
109+ expected command response. The irrelevant message must not be consumed
110+ as the response, and the correct response must still be received.
111+ """
112+ # Queue for all messages from the device
113+ response_q = queue .Queue ()
114+
115+ # The irrelevant message (e.g., an asynchronous received signal)
116+ interleaved_message = "MU;P0=353;P1=-184;D=0123456789;CP=1;SP=0;R=248;\n "
117+ # The expected command response
118+ command_response = "V 3.5.0-dev SIGNALduino\n "
119+
120+ def write_line_side_effect (payload ):
121+ # When the controller writes "V", simulate the device responding with
122+ # an interleaved message *then* the command response.
123+ if payload == "V" :
124+ # 1. Interleaved message
125+ response_q .put (interleaved_message )
126+ # 2. Command response
127+ response_q .put (command_response )
128+
129+ def readline_side_effect ():
130+ # Simulate blocking read that gets a value from the queue.
131+ try :
132+ return response_q .get (timeout = 0.5 )
133+ except queue .Empty :
134+ return None
135+
136+ mock_transport .write_line .side_effect = write_line_side_effect
137+ mock_transport .readline .side_effect = readline_side_effect
138+
139+ # Mock the parser to track if the interleaved message is passed to it
140+ mock_parser .parse_line = Mock (wraps = mock_parser .parse_line )
141+
142+ controller = SignalduinoController (transport = mock_transport , parser = mock_parser )
143+ controller .connect ()
144+ try :
145+ response = controller .commands .get_version (timeout = 1 )
146+ mock_transport .write_line .assert_called_with ("V" )
147+
148+ # 1. Verify that the correct command response was received by send_command
149+ assert response is not None
150+ assert "SIGNALduino" in response
151+ assert response .strip () == command_response .strip ()
152+
153+ # 2. Verify that the interleaved message was passed to the parser
154+ # The parser loop (_parser_loop) should attempt to parse the interleaved_message
155+ # because _handle_as_command_response should return False for it.
156+ mock_parser .parse_line .assert_called_with (interleaved_message .strip ())
157+
158+ # Give the parser thread a moment to process the message
159+ time .sleep (0.1 )
160+
161+ finally :
162+ controller .disconnect ()
163+
164+
106165def test_send_command_timeout (mock_transport , mock_parser ):
107166 """Test that a command times out if no response is received."""
108167 mock_transport .readline .return_value = None
109168 controller = SignalduinoController (transport = mock_transport , parser = mock_parser )
110169 controller .connect ()
111170 try :
112171 with pytest .raises (SignalduinoCommandTimeout ):
113- controller .send_command ( "V" , expect_response = True , timeout = 0.2 )
172+ controller .commands . get_version ( timeout = 0.2 )
114173 finally :
115174 controller .disconnect ()
116175
0 commit comments