Files
kicad-mcp-server/tests/test_symbol_library.py
mixelpixx 4a61ad233d test(symbol-library): init _cache_lock in __new__-based fixture
The background warm-cache change made list_symbols() guard cache writes with
self._cache_lock. _manager_for_fixture() builds the manager via __new__ (to skip
disk I/O to system libs), bypassing __init__ where the lock is created, so the 8
SPICE-parsing tests raised AttributeError. Set the lock in the fixture. The
string-aware parser itself is correct — all 8 pass once the lock exists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 08:51:46 -04:00

122 lines
4.8 KiB
Python

"""
Regression tests for symbol library parsing.
Covers:
- The 5000-char heuristic bug where PJFET properties bled into the OPAMP block.
- The sim_pins field exposed from Sim.Pins properties.
"""
import sys
import threading
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).parent.parent / "python"))
from commands.library_symbol import SymbolLibraryCommands, SymbolLibraryManager
FIXTURE = Path(__file__).parent / "fixtures" / "Simulation_SPICE_minimal.kicad_sym"
SPICE_LIB = Path("/usr/share/kicad/symbols/Simulation_SPICE.kicad_sym")
def _manager_for_fixture() -> SymbolLibraryManager:
manager = SymbolLibraryManager.__new__(SymbolLibraryManager)
manager.project_path = None
manager.libraries = {"Simulation_SPICE": str(FIXTURE)}
manager.symbol_cache = {}
# list_symbols() guards cache writes with this lock (added alongside the
# background warm-cache). The fixture bypasses __init__, so set it here.
manager._cache_lock = threading.Lock()
return manager
@pytest.mark.unit
class TestSymbolLibraryManagerParsing:
"""Unit tests using the minimal fixture file (no disk I/O to system libs)."""
def test_both_symbols_present(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
names = [s.name for s in symbols]
assert "OPAMP" in names
assert "PJFET" in names
assert len(symbols) == 2
def test_opamp_description_is_not_pjfet(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
opamp = next(s for s in symbols if s.name == "OPAMP")
assert "JFET" not in opamp.description
def test_opamp_description_correct(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
opamp = next(s for s in symbols if s.name == "OPAMP")
assert opamp.description == "Operational amplifier, single"
def test_opamp_value_correct(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
opamp = next(s for s in symbols if s.name == "OPAMP")
assert opamp.value == "${SIM.PARAMS}"
def test_opamp_sim_pins_exposed(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
opamp = next(s for s in symbols if s.name == "OPAMP")
assert opamp.sim_pins == "1=in+ 2=in- 3=vcc 4=vee 5=out"
def test_pjfet_description_correct(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
pjfet = next(s for s in symbols if s.name == "PJFET")
assert pjfet.description == "P-JFET transistor, for simulation only"
def test_pjfet_value_correct(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
pjfet = next(s for s in symbols if s.name == "PJFET")
assert pjfet.value == "PJFET"
def test_pjfet_sim_pins_exposed(self):
manager = _manager_for_fixture()
symbols = manager.list_symbols("Simulation_SPICE")
pjfet = next(s for s in symbols if s.name == "PJFET")
assert pjfet.sim_pins == "1=D 2=G 3=S"
@pytest.mark.integration
class TestGetSymbolInfoHandler:
"""Integration tests against the real system Simulation_SPICE library."""
def test_opamp_via_commands_handler(self):
if not SPICE_LIB.exists():
pytest.skip(f"System library not found: {SPICE_LIB}")
manager = SymbolLibraryManager.__new__(SymbolLibraryManager)
manager.project_path = None
manager.libraries = {"Simulation_SPICE": str(SPICE_LIB)}
manager.symbol_cache = {}
commands = SymbolLibraryCommands(library_manager=manager)
result = commands.get_symbol_info({"symbol": "Simulation_SPICE:OPAMP"})
assert result["success"] is True
info = result["symbol_info"]
assert info["description"] == "Operational amplifier, single"
assert "JFET" not in info["description"]
assert info["value"] == "${SIM.PARAMS}"
assert info["sim_pins"] == "1=in+ 2=in- 3=vcc 4=vee 5=out"
def test_pjfet_via_commands_handler(self):
if not SPICE_LIB.exists():
pytest.skip(f"System library not found: {SPICE_LIB}")
manager = SymbolLibraryManager.__new__(SymbolLibraryManager)
manager.project_path = None
manager.libraries = {"Simulation_SPICE": str(SPICE_LIB)}
manager.symbol_cache = {}
commands = SymbolLibraryCommands(library_manager=manager)
result = commands.get_symbol_info({"symbol": "Simulation_SPICE:PJFET"})
assert result["success"] is True
info = result["symbol_info"]
assert info["description"] == "P-JFET transistor, for simulation only"
assert info["value"] == "PJFET"