FreeRouting ships no unit tests for its geometry/router, so there is no value-level oracle to port against. This adds a dev/test-only harness that runs the reference JAR to route a DSN, letting freeroute's output be diffed against the reference implementation — the router phase will assert connectivity parity (same nets routed) via routed_net_set(). - tests/oracle.py: locate Java 21+ and a freerouting JAR (env overrides: FREEROUTE_ORACLE_JAVA, FREEROUTING_JAR), route a DSN, and extract routed connectivity from the SES. requires_oracle skips when no JVM/JAR is present, so the suite stays Java-free. - tests/test_oracle.py: routes a routable board end-to-end and checks the connectivity extraction. - tests/dsn/fixtures/kicad_routable.dsn: a real KiCad pcbnew-exported DSN (Arduino_Mega template, path sanitized) that actually routes — the smd_demo fixture leaves its nets unrouted. - pyproject: pythonpath=["tests"] so the harness imports as `oracle`.
42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
"""Tests for the FreeRouting oracle harness (tests/oracle.py).
|
|
|
|
The routing test is gated on a live JVM + JAR and skips otherwise, so the suite
|
|
stays green without Java. When the maze router lands, its output SES will be
|
|
diffed against ``routed_net_set`` of the oracle SES here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from oracle import HAS_ORACLE, requires_oracle, route_dsn, routed_net_set, routed_nets
|
|
|
|
FIXTURES = Path(__file__).parent / "dsn" / "fixtures"
|
|
ROUTABLE = FIXTURES / "kicad_routable.dsn"
|
|
|
|
|
|
def test_oracle_harness_imports():
|
|
# The harness must import and report availability even with no Java/JAR,
|
|
# so gated tests can skip cleanly instead of erroring at collection.
|
|
assert isinstance(HAS_ORACLE, bool)
|
|
|
|
|
|
@requires_oracle
|
|
def test_oracle_routes_and_reports_connectivity():
|
|
"""Reference FreeRouting routes a routable KiCad board and we can read it back.
|
|
|
|
Exercises the whole oracle path — JAR execution, SES production, and the
|
|
``routed_nets`` extraction that the router phase will diff against.
|
|
"""
|
|
ses = route_dsn(ROUTABLE, max_passes=5)
|
|
|
|
nets = routed_nets(ses)
|
|
assert nets, "SES network_out had no nets"
|
|
for counts in nets.values():
|
|
assert set(counts) == {"wires", "vias"}
|
|
|
|
routed = routed_net_set(ses)
|
|
assert routed, "oracle produced no routed nets on a routable board"
|
|
# Every routed net is a subset of all nets in the SES.
|
|
assert routed <= set(nets)
|