"""Tests for schematic analysis tools.""" import pytest from tests.conftest import requires_sch_api @requires_sch_api @pytest.mark.unit class TestRunSchematicErc: """Tests for the run_schematic_erc tool.""" def test_erc_on_populated_schematic(self, populated_schematic): from mckicad.tools.schematic_analysis import run_schematic_erc result = run_schematic_erc(schematic_path=populated_schematic) assert result["success"] is True assert "violation_count" in result or "error" not in result def test_erc_invalid_path(self): from mckicad.tools.schematic_analysis import run_schematic_erc result = run_schematic_erc(schematic_path="/tmp/nonexistent.kicad_sch") assert result["success"] is False @requires_sch_api @pytest.mark.unit class TestAnalyzeConnectivity: """Tests for the analyze_connectivity tool.""" def test_connectivity_on_populated(self, populated_schematic): from mckicad.tools.schematic_analysis import analyze_connectivity result = analyze_connectivity(schematic_path=populated_schematic) assert result["success"] is True assert "net_count" in result or "error" not in result def test_connectivity_invalid_path(self): from mckicad.tools.schematic_analysis import analyze_connectivity result = analyze_connectivity(schematic_path="/tmp/nonexistent.kicad_sch") assert result["success"] is False @requires_sch_api @pytest.mark.unit class TestCheckPinConnection: """Tests for the check_pin_connection tool.""" def test_check_existing_pin(self, populated_schematic): from mckicad.tools.schematic_analysis import check_pin_connection result = check_pin_connection( schematic_path=populated_schematic, reference="R1", pin="1", ) # May succeed or fail depending on kicad-sch-api version assert "success" in result def test_check_nonexistent_pin(self, populated_schematic): from mckicad.tools.schematic_analysis import check_pin_connection result = check_pin_connection( schematic_path=populated_schematic, reference="Z99", pin="1", ) assert "success" in result @requires_sch_api @pytest.mark.unit class TestVerifyPinsConnected: """Tests for the verify_pins_connected tool.""" def test_verify_two_pins(self, populated_schematic): from mckicad.tools.schematic_analysis import verify_pins_connected result = verify_pins_connected( schematic_path=populated_schematic, ref1="R1", pin1="1", ref2="R2", pin2="1", ) # May succeed or fail depending on kicad-sch-api version assert "success" in result @requires_sch_api @pytest.mark.unit class TestGetComponentPins: """Tests for the get_component_pins tool.""" def test_get_pins(self, populated_schematic): from mckicad.tools.schematic_analysis import get_component_pins result = get_component_pins( schematic_path=populated_schematic, reference="R1", ) assert "success" in result def test_get_pins_nonexistent(self, populated_schematic): from mckicad.tools.schematic_analysis import get_component_pins result = get_component_pins( schematic_path=populated_schematic, reference="Z99", ) assert result["success"] is False @pytest.mark.unit class TestExportValidation: """Tests for input validation in export tools.""" def test_export_netlist_invalid_path(self): from mckicad.tools.schematic_analysis import export_netlist result = export_netlist(schematic_path="/tmp/nonexistent.kicad_sch") assert result["success"] is False def test_export_pdf_invalid_path(self): from mckicad.tools.schematic_analysis import export_schematic_pdf result = export_schematic_pdf(schematic_path="/tmp/nonexistent.kicad_sch") assert result["success"] is False def test_export_netlist_bad_format(self): from mckicad.tools.schematic_analysis import export_netlist result = export_netlist( schematic_path="/tmp/test.kicad_sch", format="invalid_format", ) assert result["success"] is False assert "Unsupported" in result.get("error", "") @requires_sch_api @pytest.mark.unit class TestAuditWiring: """Tests for the audit_wiring tool.""" def test_audit_existing_component(self, populated_schematic): from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path=populated_schematic, reference="R1", ) assert result["success"] is True assert result["reference"] == "R1" assert "net_summary" in result assert result.get("pin_count", 0) > 0 assert "net_count" in result def test_audit_nonexistent_component(self, populated_schematic): from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path=populated_schematic, reference="Z99", ) assert result["success"] is False def test_audit_invalid_path(self): from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path="/tmp/nonexistent.kicad_sch", reference="R1", ) assert result["success"] is False def test_audit_empty_reference(self): from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path="/tmp/nonexistent.kicad_sch", reference="", ) assert result["success"] is False def test_audit_net_summary_structure(self, populated_schematic): """Each net entry has pins, wire_count, connected_to — no wires by default.""" from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path=populated_schematic, reference="R1", ) if result["success"]: for _net_name, entry in result["net_summary"].items(): assert "pins" in entry assert isinstance(entry["pins"], list) assert "wire_count" in entry assert "connected_to" in entry assert isinstance(entry["connected_to"], list) # No wire coords by default assert "wires" not in entry def test_audit_include_wires(self, populated_schematic): """When include_wires=True, each net entry contains a wires list.""" from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path=populated_schematic, reference="R1", include_wires=True, ) if result["success"]: for _net_name, entry in result["net_summary"].items(): assert "wires" in entry assert isinstance(entry["wires"], list) def test_audit_pin_filter(self, populated_schematic): """Filtering by pin number limits the net_summary to matching nets.""" from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path=populated_schematic, reference="R1", pins=["1"], ) if result["success"]: # Only nets containing pin "1" should appear for entry in result["net_summary"].values(): assert "1" in entry["pins"] def test_audit_net_filter(self, populated_schematic): """Filtering by net name limits the summary to that net only.""" from mckicad.tools.schematic_analysis import audit_wiring # First get all nets to pick one full = audit_wiring( schematic_path=populated_schematic, reference="R1", ) if full["success"] and full["net_summary"]: target_net = next(iter(full["net_summary"])) filtered = audit_wiring( schematic_path=populated_schematic, reference="R1", net=target_net, ) assert filtered["success"] is True assert list(filtered["net_summary"].keys()) == [target_net] def test_audit_anomalies_structure(self, populated_schematic): """Anomalies dict always present with expected keys.""" from mckicad.tools.schematic_analysis import audit_wiring result = audit_wiring( schematic_path=populated_schematic, reference="R1", ) if result["success"]: assert "anomalies" in result anomalies = result["anomalies"] assert "unconnected_pins" in anomalies assert isinstance(anomalies["unconnected_pins"], list) assert "high_fanout_nets" in anomalies assert isinstance(anomalies["high_fanout_nets"], list) assert "auto_named_nets" in anomalies assert isinstance(anomalies["auto_named_nets"], list) @requires_sch_api @pytest.mark.unit class TestVerifyConnectivity: """Tests for the verify_connectivity tool.""" def test_verify_with_matching_net(self, populated_schematic): from mckicad.tools.schematic_analysis import ( analyze_connectivity, verify_connectivity, ) # First get actual connectivity to build a valid expected map conn = analyze_connectivity(schematic_path=populated_schematic) assert conn["success"] is True # Try to verify with an empty expected — should fail validation result = verify_connectivity( schematic_path=populated_schematic, expected={}, ) assert result["success"] is False def test_verify_missing_net(self, populated_schematic): from mckicad.tools.schematic_analysis import verify_connectivity result = verify_connectivity( schematic_path=populated_schematic, expected={"NONEXISTENT_NET": [["U99", "1"]]}, ) assert result["success"] is True assert result["failed"] >= 1 # Should report as missing_net or missing pin statuses = {r["status"] for r in result["results"]} assert statuses & {"missing_net", "mismatch"} def test_verify_invalid_path(self): from mckicad.tools.schematic_analysis import verify_connectivity result = verify_connectivity( schematic_path="/tmp/nonexistent.kicad_sch", expected={"NET": [["R1", "1"]]}, ) assert result["success"] is False def test_verify_result_structure(self, populated_schematic): from mckicad.tools.schematic_analysis import verify_connectivity result = verify_connectivity( schematic_path=populated_schematic, expected={"TEST_NET": [["R1", "1"]]}, ) assert result["success"] is True assert "verified" in result assert "failed" in result assert "total" in result assert "results" in result for r in result["results"]: assert "net" in r assert "status" in r