"""Tests for drc module: design rule checks on schematic objects.""" from mcltspice.drc import ( DRCResult, DRCViolation, Severity, _check_duplicate_names, _check_ground, _check_simulation_directive, ) from mcltspice.schematic import Schematic, write_schematic def _run_single_check(check_fn, schematic: Schematic) -> DRCResult: """Run a single DRC check function and return results.""" result = DRCResult() check_fn(schematic, result) return result class TestGroundCheck: def test_missing_ground_detected(self, schematic_no_ground): result = _run_single_check(_check_ground, schematic_no_ground) assert not result.passed assert any(v.rule == "NO_GROUND" for v in result.violations) def test_ground_present(self, valid_schematic): result = _run_single_check(_check_ground, valid_schematic) assert result.passed assert len(result.violations) == 0 class TestSimDirectiveCheck: def test_missing_sim_directive_detected(self, schematic_no_sim): result = _run_single_check(_check_simulation_directive, schematic_no_sim) assert not result.passed assert any(v.rule == "NO_SIM_DIRECTIVE" for v in result.violations) def test_sim_directive_present(self, valid_schematic): result = _run_single_check(_check_simulation_directive, valid_schematic) assert result.passed class TestDuplicateNameCheck: def test_duplicate_names_detected(self, schematic_duplicate_names): result = _run_single_check(_check_duplicate_names, schematic_duplicate_names) assert not result.passed assert any(v.rule == "DUPLICATE_NAME" for v in result.violations) def test_unique_names_pass(self, valid_schematic): result = _run_single_check(_check_duplicate_names, valid_schematic) assert result.passed class TestDRCResult: def test_passed_when_no_errors(self): result = DRCResult() result.violations.append( DRCViolation(rule="TEST", severity=Severity.WARNING, message="warning only") ) assert result.passed # Warnings don't cause failure def test_failed_when_errors(self): result = DRCResult() result.violations.append( DRCViolation(rule="TEST", severity=Severity.ERROR, message="error") ) assert not result.passed def test_summary_no_violations(self): result = DRCResult(checks_run=5) assert "passed" in result.summary().lower() def test_summary_with_errors(self): result = DRCResult(checks_run=5) result.violations.append( DRCViolation(rule="TEST", severity=Severity.ERROR, message="error") ) assert "FAILED" in result.summary() def test_to_dict(self): result = DRCResult(checks_run=3) result.violations.append( DRCViolation(rule="NO_GROUND", severity=Severity.ERROR, message="No ground") ) d = result.to_dict() assert d["passed"] is False assert d["error_count"] == 1 assert len(d["violations"]) == 1 def test_errors_and_warnings_properties(self): result = DRCResult() result.violations.append( DRCViolation(rule="E1", severity=Severity.ERROR, message="err") ) result.violations.append( DRCViolation(rule="W1", severity=Severity.WARNING, message="warn") ) result.violations.append( DRCViolation(rule="I1", severity=Severity.INFO, message="info") ) assert len(result.errors) == 1 assert len(result.warnings) == 1 class TestFullDRC: """Integration test: write a schematic to disk and run the full DRC pipeline.""" def test_valid_schematic_passes(self, valid_schematic, tmp_path): """A valid schematic should pass DRC with no errors.""" from mcltspice.drc import run_drc path = tmp_path / "valid.asc" write_schematic(valid_schematic, path) result = run_drc(path) # May have warnings (floating nodes etc) but no errors assert len(result.errors) == 0 def test_no_ground_fails(self, schematic_no_ground, tmp_path): from mcltspice.drc import run_drc path = tmp_path / "no_ground.asc" write_schematic(schematic_no_ground, path) result = run_drc(path) assert any(v.rule == "NO_GROUND" for v in result.errors)