from __future__ import annotations import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parent.parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from step_editor.relation_formulas import ( # noqa: E402 RelationFormulaError, Vector3, evaluate_relation_formula, parse_relation_formula, validate_relation_formula_graph, ) def _parse_many(texts: list[str]): return [parse_relation_formula(text) for text in texts] def _assert_ok(texts: list[str]) -> None: validate_relation_formula_graph(_parse_many(texts)) def _assert_fails(texts: list[str], expected_fragment: str) -> None: try: validate_relation_formula_graph(_parse_many(texts)) except RelationFormulaError as exc: message = str(exc) if expected_fragment not in message: raise AssertionError(f"expected {expected_fragment!r} in error message, got {message!r}") from exc return raise AssertionError(f"expected relation formulas to fail: {texts!r}") def _assert_value(text: str, expected: object, values: dict[str, object] | None = None) -> None: formula = parse_relation_formula(text) values = dict(values or {}) value = evaluate_relation_formula(formula, lambda ref: values[ref.token]) if isinstance(value, Vector3): actual = tuple(value.values) expected_tuple = tuple(expected) # type: ignore[arg-type] if len(actual) != len(expected_tuple) or any(abs(float(left) - float(right)) > 1.0e-12 for left, right in zip(actual, expected_tuple)): raise AssertionError(f"expected {expected_tuple!r}, got {actual!r} for {text!r}") return if abs(float(value) - float(expected)) > 1.0e-12: raise AssertionError(f"expected {expected!r}, got {value!r} for {text!r}") def main() -> int: _assert_ok(["Face87.直径 = Face87.半径 + 0.1"]) _assert_ok(["Face87.位置 = Face85.位置 + (0, 0, -3.5)"]) _assert_ok(["Face85.直径 = Face87.半径", "Face11.直径 = Face85.半径"]) _assert_ok(["Face87.直径 = 10mm"]) _assert_ok(["Face87.直径 = 1 cm + 2mm"]) _assert_value("Face87.直径 = 1cm + 2毫米", 12.0) _assert_value("Face87.直径 = .5m / 10", 50.0) _assert_value( "Face87.位置 = Face85.位置 + (0mm, 1cm, -0.002m)", (1.0, 12.0, 1.0), {"Face85.位置": (1.0, 2.0, 3.0)}, ) _assert_fails(["Face87.直径 = Face87.直径 + 0.1"], "不能引用自身") _assert_fails(["Face85.直径 = Face87.半径", "Face85.直径 = Face11.半径"], "同一目标参数") _assert_fails(["Face85.直径 = Face87.直径", "Face87.直径 = Face85.直径"], "循环依赖") _assert_fails( [ "Face1.位置 = Face2.位置", "Face2.位置 = Face3.位置", "Face3.位置 = Face1.位置", ], "循环依赖", ) print("relation formula rules ok") return 0 if __name__ == "__main__": raise SystemExit(main())