""" 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"