Initial project structure for spice2wireviz
SPICE netlist to WireViz YAML converter with: - Custom lightweight netlist parser (.net/.cir/.sp) - Single-module mapper (subcircuit external interface) - Inter-module mapper (multi-board wiring) - Filter engine with glob patterns - Click CLI with auto-detection, inspection commands - Optional .asc parser via spicelib - Comprehensive test suite with fixtures
This commit is contained in:
commit
e20a956f51
24 changed files with 2630 additions and 0 deletions
145
tests/test_inter_module.py
Normal file
145
tests/test_inter_module.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
"""Tests for the inter-module mapper."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from spice2wireviz.filter import FilterConfig
|
||||
from spice2wireviz.mapper.inter_module import map_inter_module
|
||||
from spice2wireviz.parser.netlist import parse_netlist
|
||||
|
||||
FIXTURES = Path(__file__).parent / "fixtures"
|
||||
|
||||
|
||||
class TestInterModuleMapping:
|
||||
def test_multi_board_connectors(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
connectors = result["connectors"]
|
||||
# Should have connectors for each X instance and top-level components
|
||||
assert "X1" in connectors
|
||||
assert "X2" in connectors
|
||||
assert "X3" in connectors
|
||||
assert "J_CHASSIS" in connectors
|
||||
assert "TP_VCC" in connectors
|
||||
|
||||
def test_instance_connector_type(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
x1 = result["connectors"]["X1"]
|
||||
assert x1["type"] == "power_supply"
|
||||
|
||||
def test_instance_pinlabels(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
x2 = result["connectors"]["X2"]
|
||||
assert "VIN" in x2["pinlabels"]
|
||||
assert "GND" in x2["pinlabels"]
|
||||
assert "VOUT" in x2["pinlabels"]
|
||||
|
||||
def test_cables_for_shared_nets(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
# Should have cables connecting modules via shared nets
|
||||
cables = result["cables"]
|
||||
assert len(cables) >= 1
|
||||
|
||||
def test_connections_exist(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
connections = result["connections"]
|
||||
assert len(connections) >= 1
|
||||
|
||||
def test_traceability_notes(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
x1 = result["connectors"]["X1"]
|
||||
assert "SPICE instance" in x1["notes"]
|
||||
|
||||
def test_top_level_test_point_style(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
tp = result["connectors"]["TP_VCC"]
|
||||
assert tp.get("style") == "simple"
|
||||
|
||||
|
||||
class TestInterModuleFiltering:
|
||||
def test_exclude_instance(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
config = FilterConfig(exclude_refs=["X1"])
|
||||
result = map_inter_module(netlist, config)
|
||||
|
||||
assert "X1" not in result["connectors"]
|
||||
assert "X2" in result["connectors"]
|
||||
|
||||
def test_exclude_subcircuit(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
config = FilterConfig(exclude_subcircuits=["power_supply"])
|
||||
result = map_inter_module(netlist, config)
|
||||
|
||||
assert "X1" not in result["connectors"]
|
||||
|
||||
def test_no_ground_filter(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
config = FilterConfig(show_ground=False)
|
||||
result = map_inter_module(netlist, config)
|
||||
|
||||
# GND should not appear in any connector's pinlabels
|
||||
for name, conn in result["connectors"].items():
|
||||
if "pinlabels" in conn:
|
||||
assert "GND" not in conn["pinlabels"], f"GND found in {name}"
|
||||
|
||||
def test_no_power_filter(self):
|
||||
netlist = parse_netlist(FIXTURES / "multi_board.net")
|
||||
config = FilterConfig(show_power=False)
|
||||
result = map_inter_module(netlist, config)
|
||||
|
||||
for name, conn in result["connectors"].items():
|
||||
if "pinlabels" in conn:
|
||||
assert "VCC" not in conn["pinlabels"], f"VCC found in {name}"
|
||||
|
||||
|
||||
class TestHierarchicalInterModule:
|
||||
def test_hierarchical_instances(self):
|
||||
netlist = parse_netlist(FIXTURES / "hierarchical.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
connectors = result["connectors"]
|
||||
assert "X_REG" in connectors
|
||||
assert "X_SENSOR" in connectors
|
||||
assert "X_MAIN" in connectors
|
||||
|
||||
def test_external_connectors(self):
|
||||
netlist = parse_netlist(FIXTURES / "hierarchical.net")
|
||||
result = map_inter_module(netlist)
|
||||
|
||||
connectors = result["connectors"]
|
||||
assert "J_PWR" in connectors
|
||||
assert "J_USB" in connectors
|
||||
assert "TP_3V3" in connectors
|
||||
|
||||
def test_grouped_parallel_wires(self):
|
||||
"""Parallel wires between same modules should be grouped."""
|
||||
netlist = parse_netlist(FIXTURES / "hierarchical.net")
|
||||
config = FilterConfig(group_parallel_wires=True)
|
||||
result = map_inter_module(netlist, config)
|
||||
|
||||
# With grouping, fewer cables than total net connections
|
||||
cables = result["cables"]
|
||||
connections = result["connections"]
|
||||
assert len(cables) == len(connections)
|
||||
|
||||
def test_ungrouped_wires(self):
|
||||
"""Without grouping, each wire gets its own cable."""
|
||||
netlist = parse_netlist(FIXTURES / "hierarchical.net")
|
||||
config = FilterConfig(group_parallel_wires=False)
|
||||
result = map_inter_module(netlist, config)
|
||||
|
||||
# Each cable should have wirecount=1
|
||||
for cable in result["cables"].values():
|
||||
assert cable.get("wirecount", 1) == 1 or len(cable.get("colors", [])) == 1
|
||||
Loading…
Add table
Add a link
Reference in a new issue