Standalone PyPI package providing structured access to the full OpenOCD command surface via the TCL RPC protocol (port 6666). Async-first API with sync wrappers for every method. Subsystems: target control, memory read/write, CPU registers, flash programming, JTAG chain/scan/boundary, breakpoints/watchpoints, SVD peripheral decoding, RTT channels, transport/adapter config. 79 tests passing against a mock TCL RPC server.
99 lines
3.1 KiB
Python
99 lines
3.1 KiB
Python
"""Tests for the Session class."""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from openocd.breakpoints import BreakpointManager
|
|
from openocd.flash import Flash
|
|
from openocd.jtag import JTAGController
|
|
from openocd.memory import Memory
|
|
from openocd.registers import Registers
|
|
from openocd.rtt import RTTManager
|
|
from openocd.session import Session
|
|
from openocd.svd import SVDManager
|
|
from openocd.target import Target
|
|
from openocd.transport import Transport
|
|
|
|
|
|
async def test_connect_to_mock(mock_ocd):
|
|
"""Session.connect() should successfully connect to the mock server."""
|
|
host, port, _server = mock_ocd
|
|
sess = await Session.connect(host, port, timeout=5.0)
|
|
assert sess is not None
|
|
await sess.close()
|
|
|
|
|
|
async def test_raw_command(session):
|
|
"""session.command() should pass through to the underlying connection."""
|
|
resp = await session.command("targets")
|
|
assert "stm32f1x.cpu" in resp
|
|
|
|
|
|
async def test_context_manager(mock_ocd):
|
|
"""Session should work as an async context manager."""
|
|
host, port, _server = mock_ocd
|
|
async with await Session.connect(host, port, timeout=5.0) as sess:
|
|
resp = await sess.command("halt")
|
|
assert resp == ""
|
|
# After exiting the context, the connection is closed.
|
|
# Attempting to send should raise.
|
|
from openocd.errors import ConnectionError
|
|
with pytest.raises(ConnectionError):
|
|
await sess.command("targets")
|
|
|
|
|
|
async def test_subsystem_target_type(session):
|
|
"""session.target should return a Target instance."""
|
|
assert isinstance(session.target, Target)
|
|
|
|
|
|
async def test_subsystem_memory_type(session):
|
|
"""session.memory should return a Memory instance."""
|
|
assert isinstance(session.memory, Memory)
|
|
|
|
|
|
async def test_subsystem_registers_type(session):
|
|
"""session.registers should return a Registers instance."""
|
|
assert isinstance(session.registers, Registers)
|
|
|
|
|
|
async def test_subsystem_flash_type(session):
|
|
"""session.flash should return a Flash instance."""
|
|
assert isinstance(session.flash, Flash)
|
|
|
|
|
|
async def test_subsystem_jtag_type(session):
|
|
"""session.jtag should return a JTAGController instance."""
|
|
assert isinstance(session.jtag, JTAGController)
|
|
|
|
|
|
async def test_subsystem_breakpoints_type(session):
|
|
"""session.breakpoints should return a BreakpointManager instance."""
|
|
assert isinstance(session.breakpoints, BreakpointManager)
|
|
|
|
|
|
async def test_subsystem_rtt_type(session):
|
|
"""session.rtt should return an RTTManager instance."""
|
|
assert isinstance(session.rtt, RTTManager)
|
|
|
|
|
|
async def test_subsystem_svd_type(session):
|
|
"""session.svd should return an SVDManager instance."""
|
|
assert isinstance(session.svd, SVDManager)
|
|
|
|
|
|
async def test_subsystem_transport_type(session):
|
|
"""session.transport should return a Transport instance."""
|
|
assert isinstance(session.transport, Transport)
|
|
|
|
|
|
async def test_subsystem_lazy_initialization(session):
|
|
"""Accessing the same property twice should return the same object."""
|
|
t1 = session.target
|
|
t2 = session.target
|
|
assert t1 is t2
|
|
|
|
m1 = session.memory
|
|
m2 = session.memory
|
|
assert m1 is m2
|