The router began as a port of FreeRouting and has grown its own engine (negotiated congestion, tree nets, exact checks, axis escapes), and 'freeroute' was one letter from the project it no longer follows. The package, module and command are now rpmroute; the freeroute command stays as an alias, and the RPMROUTE / RPMROUTE_ORACLE_JAVA variables fall back to the old FREEROUTE names. Version 2026.10.07. Routing is unchanged: a PCBench board routes to a byte-identical session either way.
61 lines
1.6 KiB
Python
61 lines
1.6 KiB
Python
"""Tests for the S-expression tree parser."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from rpmroute.dsn.sexp import SExp, parse
|
|
from rpmroute.dsn.tokenizer import DsnSyntaxError, Token
|
|
|
|
|
|
def test_parse_simple_head_and_values():
|
|
tree = parse("(resolution um 10)")
|
|
assert tree.head == "resolution"
|
|
vals = tree.values()
|
|
assert [v.text for v in vals] == ["um", "10"]
|
|
|
|
|
|
def test_nested_children():
|
|
tree = parse("(structure (layer Top (type signal)) (layer Bot (type signal)))")
|
|
assert tree.head == "structure"
|
|
layers = tree.children("layer")
|
|
assert len(layers) == 2
|
|
assert isinstance(layers[0], SExp)
|
|
assert layers[0].values()[0].text == "Top"
|
|
type_scope = layers[0].child("type")
|
|
assert type_scope is not None
|
|
assert type_scope.values()[0].text == "signal"
|
|
|
|
|
|
def test_child_missing_returns_none():
|
|
tree = parse("(a (b 1))")
|
|
assert tree.child("nope") is None
|
|
|
|
|
|
def test_values_skips_nested_lists():
|
|
tree = parse("(net NET_A (pins U1-1 R2-2))")
|
|
assert [v.text for v in tree.values()] == ["NET_A"]
|
|
pins = tree.child("pins")
|
|
assert pins is not None
|
|
assert [v.text for v in pins.values()] == ["U1-1", "R2-2"]
|
|
|
|
|
|
def test_leaf_items_are_tokens():
|
|
tree = parse("(a 1 2)")
|
|
assert all(isinstance(it, Token) for it in tree.items)
|
|
|
|
|
|
def test_unbalanced_raises():
|
|
with pytest.raises(DsnSyntaxError):
|
|
parse("(a (b )")
|
|
|
|
|
|
def test_trailing_token_raises():
|
|
with pytest.raises(DsnSyntaxError):
|
|
parse("(a) (b)")
|
|
|
|
|
|
def test_no_toplevel_list_raises():
|
|
with pytest.raises(DsnSyntaxError):
|
|
parse("just atoms no parens")
|