New modules: - patterns/ library: decoupling bank, pull resistor, crystal oscillator placement with power symbol attachment and grid math helpers - tools/batch.py: atomic file-based batch operations with dry_run - tools/power_symbols.py: add_power_symbol with auto #PWR refs - tools/schematic_patterns.py: MCP wrappers for pattern library - tools/schematic_edit.py: modify/remove components, title blocks, annotations - resources/schematic.py: schematic data resources 43 new tests (99 total), lint clean.
131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
"""Shared test fixtures for mckicad tests."""
|
|
|
|
import json
|
|
import os
|
|
import tempfile
|
|
|
|
import pytest
|
|
|
|
# Detect whether kicad-sch-api is available for conditional tests
|
|
_HAS_SCH_API = False
|
|
try:
|
|
from kicad_sch_api import create_schematic, load_schematic # noqa: F401
|
|
|
|
_HAS_SCH_API = True
|
|
except ImportError:
|
|
pass
|
|
|
|
requires_sch_api = pytest.mark.skipif(not _HAS_SCH_API, reason="kicad-sch-api not installed")
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_project_dir(tmp_path):
|
|
"""Create a temporary directory with a minimal KiCad project structure."""
|
|
project_name = "test_project"
|
|
pro_file = tmp_path / f"{project_name}.kicad_pro"
|
|
pro_file.write_text('{"meta": {"filename": "test_project.kicad_pro"}}')
|
|
|
|
sch_file = tmp_path / f"{project_name}.kicad_sch"
|
|
sch_file.write_text("(kicad_sch (version 20230121))")
|
|
|
|
pcb_file = tmp_path / f"{project_name}.kicad_pcb"
|
|
pcb_file.write_text("(kicad_pcb (version 20230121))")
|
|
|
|
return tmp_path
|
|
|
|
|
|
@pytest.fixture
|
|
def project_path(tmp_project_dir):
|
|
"""Return path to the .kicad_pro file in the temp project."""
|
|
return str(tmp_project_dir / "test_project.kicad_pro")
|
|
|
|
|
|
@pytest.fixture
|
|
def schematic_path(tmp_project_dir):
|
|
"""Return path to the .kicad_sch file in the temp project."""
|
|
return str(tmp_project_dir / "test_project.kicad_sch")
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_output_dir():
|
|
"""Create a temporary output directory."""
|
|
with tempfile.TemporaryDirectory(prefix="mckicad_test_") as d:
|
|
yield d
|
|
|
|
|
|
@pytest.fixture
|
|
def populated_schematic(tmp_output_dir):
|
|
"""Create a schematic with components for testing edit/analysis tools.
|
|
|
|
Returns the path to the .kicad_sch file, or None if kicad-sch-api
|
|
is not installed.
|
|
"""
|
|
if not _HAS_SCH_API:
|
|
pytest.skip("kicad-sch-api not installed")
|
|
|
|
path = os.path.join(tmp_output_dir, "populated.kicad_sch")
|
|
sch = create_schematic("test_populated")
|
|
|
|
# Add several components
|
|
sch.components.add(lib_id="Device:R", reference="R1", value="10k", position=(100, 100))
|
|
sch.components.add(lib_id="Device:R", reference="R2", value="4.7k", position=(200, 100))
|
|
sch.components.add(lib_id="Device:C", reference="C1", value="100nF", position=(100, 200))
|
|
sch.components.add(lib_id="Device:LED", reference="D1", value="Red", position=(200, 200))
|
|
|
|
# Add a wire
|
|
sch.add_wire(start=(100, 100), end=(200, 100))
|
|
|
|
sch.save(path)
|
|
return path
|
|
|
|
|
|
@pytest.fixture
|
|
def populated_schematic_with_ic(tmp_output_dir):
|
|
"""Create a schematic with multi-pin components for power symbol and pattern tests.
|
|
|
|
Contains R1 (Device:R) and C1 (Device:C) at known positions. These
|
|
2-pin passives have predictable pin layouts suitable for testing
|
|
power symbol attachment and pattern placement.
|
|
"""
|
|
if not _HAS_SCH_API:
|
|
pytest.skip("kicad-sch-api not installed")
|
|
|
|
path = os.path.join(tmp_output_dir, "ic_test.kicad_sch")
|
|
sch = create_schematic("ic_test")
|
|
|
|
sch.components.add(lib_id="Device:R", reference="R1", value="10k", position=(100, 100))
|
|
sch.components.add(lib_id="Device:C", reference="C1", value="100nF", position=(200, 100))
|
|
|
|
sch.save(path)
|
|
return path
|
|
|
|
|
|
@pytest.fixture
|
|
def batch_json_file(tmp_output_dir):
|
|
"""Write a sample batch JSON file and return its path."""
|
|
data = {
|
|
"components": [
|
|
{"lib_id": "Device:R", "reference": "R10", "value": "1k", "x": 100, "y": 100},
|
|
{"lib_id": "Device:C", "reference": "C10", "value": "10nF", "x": 200, "y": 100},
|
|
],
|
|
"wires": [
|
|
{"start_x": 100, "start_y": 100, "end_x": 200, "end_y": 100},
|
|
],
|
|
"labels": [
|
|
{"text": "TEST_NET", "x": 150, "y": 80, "global": False},
|
|
],
|
|
"no_connects": [
|
|
{"x": 300, "y": 300},
|
|
],
|
|
}
|
|
path = os.path.join(tmp_output_dir, "test_batch.json")
|
|
with open(path, "w") as f:
|
|
json.dump(data, f)
|
|
return path
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _set_test_search_paths(tmp_project_dir, monkeypatch):
|
|
"""Point KICAD_SEARCH_PATHS at the temp project directory for all tests."""
|
|
monkeypatch.setenv("KICAD_SEARCH_PATHS", str(tmp_project_dir))
|