Files
Sprinter-SDCC/tests/sdbg/test_mcp_adapter.py
T
2026-09-17 23:32:46 +03:00

128 lines
5.6 KiB
Python

"""MCP передаёт команды одной сессии и не удаляет чужие точки."""
from pathlib import Path
import sys
import unittest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / 'toolchain'))
from sdbg.mcp_adapter import McpSession
from sdbg.session import SessionError
class McpAdapterTests(unittest.TestCase):
def setUp(self):
self.calls = []
def rpc(path, method, arguments, timeout=10, **identity):
self.calls.append((path, method, arguments, timeout, identity))
if method == 'status':
return {'session_id': 'test-session', 'build_id': 'test-build',
'generation': 7}
return {'method': method, 'arguments': arguments}
self.client = McpSession('/tmp/sprinter-test.sock', rpc=rpc)
def test_personal_breakpoints_are_tagged_and_cleared_by_owner(self):
self.client.break_line('/src/main.c', 12)
self.client.break_function('main')
self.client.clear_breakpoint(7)
self.client.clear_owned_breakpoints()
self.assertTrue(self.client.owner.startswith('mcp:'))
for _, method, arguments, _, identity in self.calls:
if method == 'status':
continue
self.assertEqual(arguments['owner'], self.client.owner)
self.assertEqual(identity['session_id'], 'test-session')
self.assertEqual(identity['build_id'], 'test-build')
self.assertEqual([item[1] for item in self.calls if item[1] != 'status'],
['break_line', 'break_function', 'clear_breakpoint',
'clear_owned_breakpoints'])
def test_memory_and_events_validate_before_rpc(self):
self.client.read_memory('0xc000', 16)
self.assertEqual(self.calls[-1][2], {'address': 0xc000, 'length': 16})
self.client.events(after=4, timeout=12)
self.assertEqual(self.calls[-1][1:4],
('events', {'after': 4, 'timeout': 12,
'owner': self.client.owner}, 14))
before = len(self.calls)
with self.assertRaisesRegex(SessionError, 'Адрес памяти'):
self.client.read_memory('not-an-address')
with self.assertRaisesRegex(SessionError, 'timeout'):
self.client.events(timeout=31)
with self.assertRaisesRegex(SessionError, 'kind'):
self.client.step_source('back')
self.assertEqual(len(self.calls), before)
def test_machine_step_count_is_validated_before_rpc(self):
before = len(self.calls)
for count in (0, 65, True):
with self.assertRaisesRegex(SessionError, '1..64'):
self.client.step_instruction(count)
self.assertEqual(len(self.calls), before)
self.client.step_instruction(3)
self.assertEqual(self.calls[-1][1], 'step')
self.assertEqual(self.calls[-1][2]['count'], 3)
self.client.step_over_instruction(2)
self.assertEqual(self.calls[-1][1], 'step_over_instruction')
self.assertEqual(self.calls[-1][2]['count'], 2)
self.client.step_out_instruction()
self.assertEqual(self.calls[-1][1], 'step_out_instruction')
before = len(self.calls)
with self.assertRaisesRegex(SessionError, '1..64'):
self.client.step_over_instruction(0)
self.assertEqual(len(self.calls), before)
def test_press_key_releases_shift_after_snapshot_error(self):
calls = []
def rpc(path, method, arguments, timeout=10, **identity):
calls.append((method, arguments))
if method == 'status':
return {'session_id': 'test-session', 'build_id': 'test-build',
'generation': 7, 'running': True}
if method == 'snapshot':
raise SessionError('Потеряна связь с MAME')
return {}
client = McpSession('/tmp/sprinter-test.sock', rpc=rpc)
with self.assertRaisesRegex(SessionError, 'Потеряна связь'):
client.press_key('X')
keys = [args for method, args in calls if method == 'input_key']
self.assertEqual([item['down'] for item in keys],
[True, True, False, False])
self.assertEqual(keys[0]['tag'], keys[-1]['tag'])
self.assertEqual(keys[1]['tag'], keys[-2]['tag'])
self.assertTrue(all(item['owner'] == client.owner for item in keys))
def test_type_string_checks_layout_before_input_and_releases_each_key(self):
calls = []
frame = 0
def rpc(path, method, arguments, timeout=10, **identity):
nonlocal frame
calls.append((method, arguments))
if method == 'status':
return {'session_id': 'test-session', 'build_id': 'test-build',
'generation': 7, 'running': True}
if method == 'snapshot':
frame += 1
return {'state': 'running', 'frame': frame}
return {}
client = McpSession('/tmp/sprinter-test.sock', rpc=rpc)
with self.assertRaisesRegex(SessionError, 'нет раскладки'):
client.type_string('a€')
self.assertEqual(calls, [])
result = client.type_string('ab')
self.assertEqual(result, {'requested': 2, 'typed': 2,
'complete': True, 'stopped': False})
keys = [args for method, args in calls if method == 'input_key']
self.assertEqual([item['down'] for item in keys],
[True, False, True, False])
if __name__ == '__main__':
unittest.main()