"""Tests for the single-module mapper.""" from pathlib import Path import pytest from spice2wireviz.filter import FilterConfig from spice2wireviz.mapper.single_module import map_single_module from spice2wireviz.parser.netlist import parse_netlist FIXTURES = Path(__file__).parent / "fixtures" class TestSingleModuleMapping: def test_simple_board_connectors(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") connectors = result["connectors"] assert "amplifier_board" in connectors # module header assert "J1" in connectors assert "J2" in connectors assert "TP1" in connectors def test_module_header_pinlabels(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") header = result["connectors"]["amplifier_board"] assert header["pinlabels"] == ["VIN", "GND", "VOUT", "SIGNAL_IN"] assert header["type"] == "Module Interface" def test_connector_pinlabels(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") j1 = result["connectors"]["J1"] assert j1["pinlabels"] == ["VIN", "GND"] def test_test_point_style(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") tp1 = result["connectors"]["TP1"] assert tp1.get("style") == "simple" def test_cables_created(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") cables = result["cables"] assert len(cables) >= 2 # At least cables for J1 and J2 connections def test_connections_created(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") connections = result["connections"] assert len(connections) >= 2 def test_traceability_notes(self): netlist = parse_netlist(FIXTURES / "simple_board.net") result = map_single_module(netlist, "amplifier_board") header = result["connectors"]["amplifier_board"] assert "SPICE subcircuit" in header["notes"] def test_nonexistent_subcircuit_raises(self): netlist = parse_netlist(FIXTURES / "simple_board.net") with pytest.raises(ValueError, match="not found"): map_single_module(netlist, "nonexistent") def test_metadata_passthrough(self): netlist = parse_netlist(FIXTURES / "simple_board.net") meta = {"title": "Test Diagram", "author": "Test"} result = map_single_module(netlist, "amplifier_board", metadata=meta) assert result["metadata"]["title"] == "Test Diagram" class TestSingleModuleFiltering: def test_no_ground_filter(self): netlist = parse_netlist(FIXTURES / "simple_board.net") config = FilterConfig(show_ground=False) result = map_single_module(netlist, "amplifier_board", config) header = result["connectors"]["amplifier_board"] assert "GND" not in header["pinlabels"] def test_no_power_filter(self): """When power is hidden, VIN should still appear as it's a port name, not a power net.""" netlist = parse_netlist(FIXTURES / "simple_board.net") config = FilterConfig(show_power=False) result = map_single_module(netlist, "amplifier_board", config) # VIN is a port name — it's not VCC/VDD so it stays header = result["connectors"]["amplifier_board"] assert "VIN" in header["pinlabels"] def test_exclude_component_ref(self): netlist = parse_netlist(FIXTURES / "simple_board.net") config = FilterConfig(exclude_refs=["TP1"]) result = map_single_module(netlist, "amplifier_board", config) assert "TP1" not in result["connectors"]