Add asynchronous machine over and out to shared MCP

This commit is contained in:
Александр Петров
2026-09-17 23:32:46 +03:00
parent 259c782190
commit a8d0692eb2
15 changed files with 241 additions and 19 deletions
+44 -3
View File
@@ -118,7 +118,7 @@ class StepBridge:
def request(self, command, **arguments):
self.calls.append(command)
if command in ('step', 'step_over', 'step_out'):
count = arguments.get('count', 1) if command == 'step' else 1
count = arguments.get('count', 1) if command in ('step', 'step_over') else 1
self.step_counts.append(count)
self.owner.index = min(self.owner.index + count,
len(self.owner.locations) - 1)
@@ -153,7 +153,7 @@ class StepSession:
class WaitingBridge:
"""Машинный over ожидает внешний ввод, но pause должен остаться доступен."""
"""Машинный over/out ожидает ввод, но Pause должен остаться доступен."""
def __init__(self):
self.paused = False
self.started = False
@@ -168,7 +168,7 @@ class WaitingBridge:
if command == 'pause':
self.paused = True
return {'accepted': True}
if command == 'step_over':
if command in ('step_over', 'step_out'):
self.started = True
return {'accepted': True}
raise AssertionError(command)
@@ -500,6 +500,30 @@ class ServerTests(unittest.TestCase):
finally:
controller.close()
def test_machine_over_and_out_are_separate_from_source_steps(self):
session = StepSession()
controller = SessionController(session)
try:
for bad in (0, 65, 1.5):
with self.assertRaisesRegex(SessionError, '1..64'):
controller.call('step_over_instruction',
{'count': bad, 'owner': 'mcp:test'})
over = controller.call('step_over_instruction',
{'count': 2, 'owner': 'mcp:test'})
self.assertEqual(over['accepted'], True)
self.wait_source_step(controller)
self.assertEqual(controller.events[-1]['body']['location']['sources'][0]['line'], 4)
self.assertEqual(session.bridge.step_counts, [2])
session.index = 0
out = controller.call('step_out_instruction', {'owner': 'mcp:test'})
self.assertEqual(out['accepted'], True)
self.wait_source_step(controller)
self.assertEqual(controller.events[-1]['body']['location']['sources'][0]['line'], 3)
self.assertEqual([name for name in session.bridge.calls
if name != 'snapshot'], ['step_over', 'step_out'])
finally:
controller.close()
def test_source_step_preserves_user_breakpoint_on_same_line(self):
session = StepSession()
controller = SessionController(session)
@@ -531,6 +555,23 @@ class ServerTests(unittest.TestCase):
finally:
controller.close()
def test_waiting_machine_over_out_keep_pause_available(self):
for method in ('step_over_instruction', 'step_out_instruction'):
with self.subTest(method=method):
session = StepSession()
session.bridge = WaitingBridge()
controller = SessionController(session)
try:
started = controller.call(method, {'owner': 'mcp:test'})
self.assertTrue(started['accepted'])
self.assertTrue(controller.running)
stopped = controller.call('pause', {'owner': 'mcp:test'})
self.assertEqual(stopped['sources'][0]['line'], 3)
self.assertFalse(controller.running)
self.assertIn('pause', session.bridge.calls)
finally:
controller.close()
if __name__ == '__main__':
unittest.main()