from __future__ import annotations from copy import deepcopy import tempfile, unittest from pathlib import Path from cadfs_to_cdsl.compare import compare_steps from cadfs_to_cdsl.featurescript_parser import parse_featurescript from cadfs_to_cdsl.lowering import lower_model from cadfs_to_cdsl.rebuild import rebuild_candidate class IntegrationTests(unittest.TestCase): def test_known_rp_roundtrip_00000173(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0000/00000173.txt"; gold = root / "step_abc/0000/00000173.step" if not feature.exists() or not gold.exists(): self.skipTest("CADFS sample is not installed") cdsl = lower_model(parse_featurescript(feature.read_text(), "00000173"), {}).cdsl with tempfile.TemporaryDirectory() as tmp: rebuilt = Path(tmp) / "rebuild.step" result = rebuild_candidate(cdsl, rebuilt) self.assertEqual(result["status"], "rebuilt") comparison = compare_steps(gold, rebuilt) self.assertFalse(comparison["strict"]["passed"]) self.assertTrue(comparison["rp"]["passed"]) self.assertEqual(comparison["decision"], "approximate_pass") def test_standard_tapped_through_counterbore_00002243(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0000/00002243.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00002243"), {}) first = next(item for item in result.cdsl["features"] if item["id"] == "f_F1") self.assertEqual(first["atomic_id"], "extrude_add_two_sided") self.assertEqual(first["params"]["distance_mm"], 125.0) self.assertEqual(first["params"]["reverse_distance_mm"], 125.0) cut = next(item for item in result.cdsl["features"] if item["id"] == "f_F3") self.assertEqual(cut["atomic_id"], "extrude_cut_two_sided") hole = next(item for item in result.cdsl["features"] if item["atomic_id"] == "hole_wizard") self.assertEqual(hole["params"]["hole_type"], "c_bore") self.assertEqual(hole["params"]["diameter_mm"], 15.0) self.assertEqual(hole["params"]["end_condition"]["type"], "through_all") self.assertNotIn("counterbore", hole["params"]) with tempfile.TemporaryDirectory() as tmp: rebuilt = Path(tmp) / "rebuild.step" self.assertEqual(rebuild_candidate(result.cdsl, rebuilt)["status"], "rebuilt") comparison = compare_steps(root / "step_abc/0000/00002243.step", rebuilt) self.assertTrue(comparison["strict"]["passed"]) def test_rectilinear_fillet_arcs_00129362_preserve_recovered_sketch_geometry(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0012/00129362.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00129362"), {}) profile = next(item for item in result.cdsl["geometry"]["sketches"] if item["id"] == "sketch_F0")["profile"] arcs = [segment for segment in profile["contours"][0]["segments"] if segment["type"] == "arc"] self.assertEqual(sorted(arc["center"] for arc in arcs), [[25.4, 12.7], [25.4, 63.5]]) self.assertTrue(all(abs(arc["radius_mm"] - 12.7) <= 1e-12 for arc in arcs)) triangle = next(item for item in result.cdsl["geometry"]["sketches"] if item["id"] == "sketch_F5")["profile"] self.assertEqual( sorted({coordinate for contour in triangle["contours"] for segment in contour["segments"] for point in (segment.get("start"), segment.get("end")) if point for coordinate in point}), [-12.7, -6.35, 0.0, 6.35, 12.7, 25.4, 34.925, 41.275], ) with tempfile.TemporaryDirectory() as tmp: rebuilt = Path(tmp) / "rebuild.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertEqual(outcome["status"], "rebuilt") def test_cylindrical_swept_face_selector_00111611(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0011/00111611.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00111611"), {}) fillet = next(item for item in result.cdsl["features"] if item["id"] == "f_F3") self.assertEqual(fillet["atomic_id"], "fillet") self.assertEqual(fillet["selectors"][0]["kind"], "face") self.assertEqual( fillet["selectors"][0]["geometry"], {"axis_origin_mm": [0.0, 0.0, 0.0], "axis_direction": [0.0, -1.0, 0.0], "radius_mm": 45.66}, ) chamfer = next(item for item in result.cdsl["features"] if item["id"] == "f_F5") self.assertEqual( sorted(selector["geometry"]["axis_origin_mm"] for selector in chamfer["selectors"]), sorted([[0.0, 25.4, 33.37], [33.38, 25.4, 0.0], [0.0, 25.4, -33.38], [-33.38, 25.4, 0.0]]), ) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} f4 = next(item for item in result.cdsl["features"] if item["id"] == "f_F4") self.assertEqual( sorted(segment["center"] for contour in sketches[f4["sketch_id"]]["profile"]["contours"] for segment in contour["segments"]), sorted([[0.0, 33.37], [33.38, 0.0], [-33.38, 0.0], [0.0, -33.38]]), ) f7 = next(item for item in result.cdsl["features"] if item["id"] == "f_F7") self.assertEqual( [segment["radius_mm"] for contour in sketches[f7["sketch_id"]]["profile"]["contours"] for segment in contour["segments"]], [4.48, 2.36], ) self.assertNotIn("result_mode", next(item for item in result.cdsl["features"] if item["id"] == "f_F7")["params"]) self.assertEqual(next(item for item in result.cdsl["features"] if item["id"] == "f_F9")["params"]["result_mode"], "new_body") from build123d import import_step with tempfile.TemporaryDirectory() as tmp: rebuilt = Path(tmp) / "rebuild.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertEqual(outcome["status"], "rebuilt") runtime_box = outcome["result"]["bbox_mm"] imported_box = import_step(str(rebuilt)).bounding_box() actual = [imported_box.min.X, imported_box.min.Y, imported_box.min.Z, imported_box.max.X, imported_box.max.Y, imported_box.max.Z] expected = runtime_box["min"] + runtime_box["max"] for value, target in zip(actual, expected): self.assertAlmostEqual(value, target, places=5) def test_inward_shells_00789939_lower_and_rebuild(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0078/00789939.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00789939"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F2"]["atomic_id"], "shell") self.assertEqual(features["f_F5"]["atomic_id"], "shell") self.assertEqual(features["f_F2"]["params"], {"thickness_mm": 2.5, "inward": True}) self.assertEqual(features["f_F5"]["params"], {"thickness_mm": 2.5, "inward": True}) self.assertNotIn("F2", [item.get("feature_id") for item in result.diagnostics]) self.assertNotIn("F5", [item.get("feature_id") for item in result.diagnostics]) with tempfile.TemporaryDirectory() as tmp: rebuilt = Path(tmp) / "rebuild.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertEqual(outcome["status"], "rebuilt") self.assertEqual(outcome["result"]["solid_count"], 2) def test_outward_cap_shells_lower_and_rebuild_prefixes(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = (("00090436", 2.5), ("00107631", 3.8)) for sample_id, thickness in cases: with self.subTest(sample_id=sample_id): feature = root / "featurescript_rp" / sample_id[:4] / f"{sample_id}.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), sample_id), {}) shell_index, shell = next( (index, item) for index, item in enumerate(result.cdsl["features"]) if item["id"] == "f_F2" ) self.assertEqual(shell["atomic_id"], "shell") self.assertEqual(shell["params"], {"thickness_mm": thickness, "inward": False}) self.assertNotIn("shell_outward", {item.get("capability") for item in result.diagnostics}) prefix = deepcopy(result.cdsl) prefix["features"] = prefix["features"][:shell_index + 1] with tempfile.TemporaryDirectory() as tmp: outcome = rebuild_candidate(prefix, Path(tmp) / "outward-shell.step") self.assertEqual(outcome["status"], "rebuilt") self.assertEqual(outcome["result"]["solid_count"], 1) def test_sweep_00542223_preserves_its_open_bspline_path(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0054/00542223.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00542223"), {}) sweep = next(item for item in result.cdsl["features"] if item["id"] == "f_F5") segment = sweep["params"]["path"]["segment"] self.assertEqual(result.status, "converted_complete") self.assertEqual(sweep["atomic_id"], "sweep_add") self.assertEqual(sweep["sketch_id"], "sketch_F4") self.assertEqual(segment["points"], [[-40.0, -50.0], [-20.0, -14.96], [0.0, 5.0]]) self.assertEqual(segment["start_tangent"], [27.94, 92.49]) self.assertEqual(segment["end_tangent"], [52.88, 49.52]) self.assertNotIn("F2", [item.get("feature_id") for item in result.diagnostics]) self.assertNotIn("F5", [item.get("feature_id") for item in result.diagnostics]) def test_circular_pattern_00542223_preserves_all_sweep_arms(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0054/00542223.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00542223"), {}) candidate = dict(result.cdsl) candidate["features"] = result.cdsl["features"][:4] from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as tmp: rebuilt = rebuild_cdsl(candidate, Path(tmp) / "pattern.step") self.assertEqual(rebuilt["solid_count"], 1) bbox = rebuilt["bbox_mm"] self.assertAlmostEqual(bbox["min"][0], -52.14101625137758) self.assertAlmostEqual(bbox["min"][1], -57.500000100000065) self.assertAlmostEqual(bbox["max"][0], 52.14101625137762) self.assertAlmostEqual(bbox["max"][1], 37.5000001000001) def test_fused_body_circular_copy_faces_bind_and_shell_00542223(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0054/00542223.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") candidate = lower_model(parse_featurescript(feature.read_text(), "00542223"), {}).cdsl with tempfile.TemporaryDirectory() as tmp: outcome = rebuild_candidate(candidate, Path(tmp) / "rebuild.step") self.assertEqual(outcome["status"], "rebuilt") result = outcome["result"] self.assertIn("f_F7", [item["feature_id"] for item in result["feature_results"]]) shell_selectors = [ item for item in result["selector_resolution"] if item["feature_id"] == "f_F7" ] self.assertEqual( {item["selector"]["owner_feature_id"] for item in shell_selectors}, {"f_F5", "f_F6.c1.f_F5", "f_F6.c2.f_F5", "f_F1"}, ) self.assertTrue(all(item["status"] == "resolved" for item in shell_selectors)) def test_face_chamfer_ignores_periodic_seams_00111611(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0011/00111611.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") from copy import deepcopy from engine.cdsl_engine.capabilities import CapabilityAnalyzer, sketch_ids_required_by_contract from engine.cdsl_engine.runtime import EXECUTORS, ExecutionSession, _execute_node, _selector_edges from engine.cdsl_engine.sketch_solver import CORE_SHAPE_GENERATORS, resolve_required_sketches from cadfs_to_cdsl.selector_binding import bind_candidate_selectors candidate = lower_model(parse_featurescript(feature.read_text(), "00111611"), {}).cdsl bound, _ = bind_candidate_selectors(candidate) resolved = resolve_required_sketches( deepcopy(bound), sketch_ids_required_by_contract(bound), errors={}, ) analysis = CapabilityAnalyzer( atomic_ids=EXECUTORS, profile_types=CORE_SHAPE_GENERATORS, ).analyze(resolved) session = ExecutionSession( sketches={str(item["id"]): item for item in resolved["geometry"]["sketches"]}, nodes={node.feature_id: node for node in analysis.plan}, ) for node in analysis.plan: if node.feature_id == "f_F5": edges = _selector_edges(node, session, tangent_propagation=True) break _execute_node(node, session) else: self.fail("F5 chamfer was not planned") self.assertEqual(len(edges), 8) self.assertTrue(all(str(edge.geom_type).endswith("CIRCLE") for edge in edges)) def test_circular_remove_pattern_replays_cut_sources_00159804(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0015/00159804.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00159804"), {}) source = next(item for item in result.cdsl["features"] if item["id"] == "f_F8") pattern = next(item for item in result.cdsl["features"] if item["id"] == "f_F9") self.assertEqual(source["atomic_id"], "extrude_cut_blind") self.assertNotIn("result_mode", source["params"]) self.assertEqual(pattern["params"]["operation_mode"], "remove") if __name__ == "__main__": unittest.main()