87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
from __future__ import annotations
|
||
|
||
import math
|
||
import sys
|
||
import tempfile
|
||
import unittest
|
||
from copy import deepcopy
|
||
from pathlib import Path
|
||
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(ROOT / "backend"))
|
||
sys.path.insert(0, str(ROOT / "backend" / "engine"))
|
||
|
||
from cdsl_engine.sketch_solver import list_registered_shapes # noqa: E402
|
||
|
||
|
||
def _workplane() -> dict:
|
||
return {"origin_mm": [0, 0, 0], "x_dir": [1, 0, 0], "normal": [0, 0, 1]}
|
||
|
||
|
||
def _document(profile: dict) -> dict:
|
||
return {
|
||
"schema": "cad.cdsl.llm.v1", "schema_version": "1.1.0", "kind": "part", "part_id": "profile-chain",
|
||
"meta": {"unit": "mm"},
|
||
"geometry": {"sketches": [{
|
||
"id": "base", "workplane": _workplane(), "profile": profile,
|
||
}]},
|
||
"features": [{
|
||
"id": "base_add", "atomic_id": "extrude_add_blind", "depends_on": [],
|
||
"params": {"distance_mm": 10}, "sketch_id": "base",
|
||
}],
|
||
}
|
||
|
||
|
||
class EngineProfileContractTests(unittest.TestCase):
|
||
"""#10 Profile 链:annulus / circles 进入 CDSL-only 运行时与公开 schema。"""
|
||
|
||
def test_annulus_and_circles_are_registered_runtime_profiles(self) -> None:
|
||
registered = list_registered_shapes()
|
||
self.assertIn("annulus", registered)
|
||
self.assertIn("circles", registered)
|
||
|
||
def test_annulus_profile_rebuilds_as_ring_extrusion(self) -> None:
|
||
from cdsl_engine.runtime import rebuild_cdsl
|
||
|
||
cdsl = _document({
|
||
"type": "annulus", "center": [0, 0], "inner_radius_mm": 2, "outer_radius_mm": 5,
|
||
})
|
||
with tempfile.TemporaryDirectory() as directory:
|
||
result = rebuild_cdsl(cdsl, Path(directory) / "ring.step")
|
||
# 环面面积 π(5²-2²)=21π,拉伸 10 → 210π ≈ 659.734
|
||
self.assertAlmostEqual(result["volume_mm3"], 210 * math.pi, places=4)
|
||
self.assertEqual(result["solid_count"], 1)
|
||
|
||
def test_circles_profile_rebuilds_as_independent_solids(self) -> None:
|
||
from cdsl_engine.runtime import rebuild_cdsl
|
||
|
||
cdsl = _document({
|
||
"type": "circles",
|
||
"items": [
|
||
{"center": [-4, 0], "radius_mm": 2},
|
||
{"center": [4, 0], "radius_mm": 2},
|
||
],
|
||
})
|
||
with tempfile.TemporaryDirectory() as directory:
|
||
result = rebuild_cdsl(cdsl, Path(directory) / "two.step")
|
||
# 两个独立圆柱:2 × π×2²×10 = 80π ≈ 251.327
|
||
self.assertAlmostEqual(result["volume_mm3"], 2 * math.pi * 4 * 10, places=4)
|
||
self.assertEqual(result["solid_count"], 2)
|
||
|
||
def test_annulus_validation_rejects_inverted_radii(self) -> None:
|
||
from cdsl_engine.runtime import rebuild_cdsl
|
||
|
||
cdsl = _document({
|
||
"type": "annulus", "center": [0, 0], "inner_radius_mm": 5, "outer_radius_mm": 2,
|
||
})
|
||
with tempfile.TemporaryDirectory() as directory:
|
||
# 能力检查阶段以 profile_resolution_failed blocker 拒绝该文档
|
||
# (reason 为 "annulus: inner_radius must be < outer_radius")。
|
||
with self.assertRaises(ValueError):
|
||
rebuild_cdsl(cdsl, Path(directory) / "bad.step")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|