Add shared-session MCP source debugger adapter
This commit is contained in:
@@ -4,6 +4,7 @@ import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT / 'toolchain'))
|
||||
@@ -26,6 +27,7 @@ class DummyBridge:
|
||||
self.calls.append((command, arguments))
|
||||
if command == 'snapshot': return {'state': self.state}
|
||||
if command == 'console_print': return {'printed': True}
|
||||
if command == 'memory': return {'hex': '00' * arguments['length']}
|
||||
raise AssertionError(command)
|
||||
|
||||
|
||||
@@ -44,13 +46,20 @@ class DummySession:
|
||||
return {'status': 'mapped', 'pc': 0x8100, 'link_address': 0x8100,
|
||||
'sources': [{'file': '/src/main.c', 'line': 3}]}
|
||||
|
||||
def refresh(self):
|
||||
return SimpleNamespace(generation=1, bank_pages={})
|
||||
|
||||
def break_line(self, filename, line, enabled=True):
|
||||
if line == 99:
|
||||
raise SessionError('нет адреса')
|
||||
identifier = self.next_id
|
||||
self.next_id += 1
|
||||
return {'id': identifier, 'backend_ids': [identifier],
|
||||
'conditions': [], 'locations': [{'line': line}], 'enabled': enabled}
|
||||
'conditions': [], 'locations': [{'line': line, 'link_address': 0x8100}],
|
||||
'enabled': enabled}
|
||||
|
||||
def break_function(self, name, enabled=True):
|
||||
return self.break_line('/src/main.c', 3, enabled=enabled)
|
||||
|
||||
def clear_breakpoint(self, identifier):
|
||||
self.cleared.append(identifier)
|
||||
@@ -189,6 +198,39 @@ class ServerTests(unittest.TestCase):
|
||||
server.close()
|
||||
controller.close()
|
||||
|
||||
def test_individual_breakpoints_keep_owner_and_source_step_priority(self):
|
||||
session = DummySession()
|
||||
controller = SessionController(session)
|
||||
try:
|
||||
mine = controller.call('break_line',
|
||||
{'file': '/src/main.c', 'line': 3, 'owner': 'mcp:a'})
|
||||
other = controller.call('break_function', {'name': 'main', 'owner': 'mcp:b'})
|
||||
self.assertTrue(controller._has_stop_breakpoint(session.where()))
|
||||
with self.assertRaisesRegex(SessionError, 'не принадлежит'):
|
||||
controller.call('clear_breakpoint', {'id': other['id'], 'owner': 'mcp:a'})
|
||||
self.assertEqual(controller.call('clear_owned_breakpoints', {'owner': 'mcp:a'}),
|
||||
{'cleared': [mine['id']]})
|
||||
self.assertEqual(session.cleared, [mine['id']])
|
||||
self.assertIn(other['id'], controller.breakpoint_info)
|
||||
controller.call('clear_breakpoint', {'id': other['id'], 'owner': 'mcp:b'})
|
||||
self.assertFalse(controller.breakpoint_info)
|
||||
finally:
|
||||
controller.close()
|
||||
|
||||
def test_read_memory_is_bounded_and_generation_tied(self):
|
||||
session = DummySession()
|
||||
controller = SessionController(session)
|
||||
try:
|
||||
result = controller.call('read_memory', {'address': 0xfffe, 'length': 2})
|
||||
self.assertEqual(result, {'address': 0xfffe, 'length': 2, 'hex': '0000',
|
||||
'generation': 1, 'bank_pages': {}})
|
||||
with self.assertRaisesRegex(SessionError, 'за 64 КБ'):
|
||||
controller.call('read_memory', {'address': 0xffff, 'length': 2})
|
||||
with self.assertRaisesRegex(SessionError, 'длина 1..256'):
|
||||
controller.call('read_memory', {'address': 0, 'length': 257})
|
||||
finally:
|
||||
controller.close()
|
||||
|
||||
def test_idle_snapshot_detects_invalidation(self):
|
||||
session = DummySession()
|
||||
controller = SessionController(session)
|
||||
|
||||
Reference in New Issue
Block a user