from __future__ import annotations import json, math, tempfile, unittest from copy import deepcopy 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.ir import Call from cadfs_to_cdsl.lowering import ( UnsupportedCapability, _arc, _contours, _curve_endpoint_tangent, _direct_hole_location, _direct_line_angle_axis, _direct_sketch_wire_path, _direct_boolean_intersection_selector, _direct_primary_cut_intersection_selector, _global, _number, _record_single_body_successor, lower_model, ) from cadfs_to_cdsl.pipeline import compare_one, convert_one, rebuild_one from cadfs_to_cdsl.rebuild import rebuild_candidate from cadfs_to_cdsl.dataset import Sample from cadfs_to_cdsl.dataset import scan_dataset from cadfs_to_cdsl.tests.test_parser import SOURCE, TRANSFORM_SOURCE LINE_ANGLE_TWO_ENTITY_SOURCE = '''FeatureScript 1511; import(path : "onshape/std/geometry.fs", version : "1511.0"); const mm = millimeter; const VERTEX = EntityType.VERTEX; const EDGE = EntityType.EDGE; const FACE = EntityType.FACE; function v(x, y){return vector(x, y);} annotation { "Feature Type Name" : "Feature" } export const myFeature = defineFeature(function(context is Context, id is Id, definition is map) precondition{} { { var Q0; Q0=qCreatedBy(makeId("Top.planeOp"),FACE); var sketch=newSketch(context,id+"F0",{"sketchPlane":qUnion([Q0])}); skLineSegment(sketch,"E0",{"start":v(0,0)*mm,"end":v(10,0)*mm}); skLineSegment(sketch,"E1",{"start":v(0,0)*mm,"end":v(0,10)*mm}); skLineSegment(sketch,"E2",{"start":v(0,5)*mm,"end":v(10,5)*mm}); skPoint(sketch,"P0",{"position":v(0,10)*mm}); skPoint(sketch,"P1",{"position":v(10,0)*mm}); skSolve(sketch); } { var Q0; Q0=sQuery(id+"F0.wireOp",EDGE,"E0"); var Q1; Q1=sQuery(id+"F0.wireOp",EDGE,"E1"); cPlane(context,id+"F1",{"entities":qUnion([Q0,Q1]),"cplaneType":CPlaneType.LINE_ANGLE,"angle":0*degree}); } { var Q0; Q0=sQuery(id+"F0.wireOp",EDGE,"E0"); var Q1; Q1=sQuery(id+"F0.wireOp",EDGE,"E2"); cPlane(context,id+"F2",{"entities":qUnion([Q0,Q1]),"cplaneType":CPlaneType.LINE_ANGLE,"angle":0*degree}); } { var Q0; Q0=sQuery(id+"F0.wireOp",EDGE,"E0"); var Q1; Q1=sQuery(id+"F0.wireOp",VERTEX,"P0"); cPlane(context,id+"F3",{"entities":qUnion([Q0,Q1]),"cplaneType":CPlaneType.LINE_ANGLE,"angle":0*degree}); } { var Q0; Q0=sQuery(id+"F0.wireOp",VERTEX,"P0"); var Q1; Q1=sQuery(id+"F0.wireOp",EDGE,"E0"); cPlane(context,id+"F4",{"entities":qUnion([Q0,Q1]),"cplaneType":CPlaneType.LINE_ANGLE,"angle":90*degree,"oppositeDirection":true}); } { var Q0; Q0=sQuery(id+"F0.wireOp",EDGE,"E0"); var Q1; Q1=sQuery(id+"F0.wireOp",VERTEX,"P1"); cPlane(context,id+"F5",{"entities":qUnion([Q0,Q1]),"cplaneType":CPlaneType.LINE_ANGLE,"angle":0*degree}); } { var Q0; Q0=sQuery(id+"F0.wireOp",EDGE,"E0"); var Q1; Q1=qCreatedBy(id+"F1.planeOp",FACE); cPlane(context,id+"F6",{"entities":qUnion([Q0,Q1]),"cplaneType":CPlaneType.LINE_ANGLE,"angle":0*degree}); } }''' class LoweringTests(unittest.TestCase): def test_direct_sketch_wire_path_accepts_only_one_nonconstruction_line_or_bspline(self): plane = {"origin_mm": [0.0, 0.0, 0.0], "x_dir": [1.0, 0.0, 0.0], "normal": [0.0, 0.0, 1.0]} line = {"type": "line", "start": [0.0, 0.0], "end": [10.0, 0.0], "source_entity_id": "E0"} query = Call("qUnion", [[ Call("qConstructionFilter", [ Call("qBodyType", [ Call("qCreatedBy", [Call("__binary__", ["id", "+", "F0"]), "EDGE"]), "BodyType.WIRE", ]), "ConstructionObject.NO", ]), ]]) sketches = {"F0": {"workplane": plane}} entities = {"F0": {"E0": line, "axis": {"type": "line", "start": [0.0, 0.0], "end": [0.0, 5.0], "construction": True}}} self.assertEqual( _direct_sketch_wire_path( query, sketches, entities, featurescript_version="1511", standard_library="onshape/std/geometry.fs", standard_library_version="1511.0", ), ("F0", "E0", line, sketches["F0"]), ) self.assertIsNone(_direct_sketch_wire_path( query, sketches, entities, featurescript_version="1512", standard_library="onshape/std/geometry.fs", standard_library_version="1511.0", )) self.assertIsNone(_direct_sketch_wire_path( query, sketches, entities, featurescript_version="1511", standard_library="onshape/std/geometry.fs", standard_library_version="1512.0", )) self.assertIsNone(_direct_sketch_wire_path( query, sketches, {"F0": {"E0": line, "E1": {**line, "source_entity_id": "E1"}}}, featurescript_version="1511", standard_library="onshape/std/geometry.fs", standard_library_version="1511.0", )) self.assertIsNone(_direct_sketch_wire_path( Call("qBodyType", [Call("qCreatedBy", ["F0", "EDGE"]), "BodyType.WIRE"]), sketches, entities, featurescript_version="1511", standard_library="onshape/std/geometry.fs", standard_library_version="1511.0", )) self.assertIsNone(_direct_sketch_wire_path( query.args[0][0], sketches, entities, featurescript_version="1511", standard_library="onshape/std/geometry.fs", standard_library_version="1511.0", )) def test_direct_hole_location_accepts_only_original_sketch_vertices(self): plane = {"origin_mm": [0.0, 0.0, 0.0], "x_dir": [1.0, 0.0, 0.0], "normal": [0.0, 0.0, 1.0]} sketches = {"F2": {"workplane": plane}} entities = {"F2": { "P0": {"type": "point", "point": [1.0, 2.0]}, "C0": {"type": "circle", "center": [3.0, 4.0], "radius_mm": 1.0}, "L0": {"type": "line", "start": [5.0, 6.0], "end": [7.0, 8.0]}, "A0": {"type": "arc", "start": [9.0, 10.0], "end": [11.0, 12.0]}, }} def vertex(token: str) -> Call: return Call("sQuery", ["F2.wireOp", "VERTEX", token]) self.assertEqual(_direct_hole_location(vertex("P0"), sketches, entities), ([1.0, 2.0, 0.0], plane)) self.assertEqual(_direct_hole_location(vertex("C0.center"), sketches, entities), ([3.0, 4.0, 0.0], plane)) self.assertEqual(_direct_hole_location(vertex("L0.end"), sketches, entities), ([7.0, 8.0, 0.0], plane)) self.assertEqual(_direct_hole_location(vertex("A0.start"), sketches, entities), ([9.0, 10.0, 0.0], plane)) self.assertIsNone(_direct_hole_location(Call("qAdjacent", [vertex("C0.center")]), sketches, entities)) self.assertIsNone(_direct_hole_location(vertex("C0.center.copy"), sketches, entities)) def test_strict_comparison_status_is_not_labeled_approximate(self): with tempfile.TemporaryDirectory() as tmp: output = Path(tmp); directory = output / "samples" / "strict-status"; directory.mkdir(parents=True) sample = Sample("strict-status", {"step": str(directory / "gold.step")}, {}, {}, []) (directory / "rebuild.step").touch(); (directory / "gold.step").touch() (directory / "status.json").write_text(json.dumps({ "sample_id": sample.sample_id, "rebuild_status": "rebuilt", "comparison_error": {"type": "TimeoutError", "message": "stale"}, }), encoding="utf-8") (directory / "comparison.json").write_text(json.dumps({"decision": "strict_pass", "strict": {"passed": True}, "rp": {"passed": True}}), encoding="utf-8") status = compare_one(sample, output, compare_mode="strict") self.assertEqual(status["status"], "rebuilt_strict") self.assertNotIn("comparison_error", status) def test_missing_dataset_fails_explicitly(self): with tempfile.TemporaryDirectory() as tmp: with self.assertRaises(FileNotFoundError): scan_dataset(Path(tmp) / "missing") def test_circle_extrude_is_valid_cdsl_11(self): result = lower_model(parse_featurescript(SOURCE, "00000173"), {}) self.assertEqual(result.status, "converted_complete") self.assertEqual(result.cdsl["schema_version"], "1.1.0") self.assertEqual(result.cdsl["geometry"]["sketches"][0]["profile"]["radius_mm"], 9.53) from engine.cdsl_engine.semantic_validation import validate_semantic_cdsl self.assertTrue(validate_semantic_cdsl(result.cdsl)["future_rebuild_ready"]) def test_rectilinear_fillet_arc_recovers_its_exact_endpoint_radius(self): arc = _arc([38.1, 63.5], [34.38, 72.48], [25.4, 76.2]) self.assertEqual(arc["center"], [25.4, 63.5]) self.assertAlmostEqual(arc["radius_mm"], 12.7) self.assertFalse(arc["clockwise"]) def test_general_three_point_arc_remains_circumcircle_defined(self): arc = _arc([0, 0], [2, 3], [5, 0]) self.assertAlmostEqual(arc["center"][0], 2.5) self.assertAlmostEqual(arc["center"][1], 0.5) self.assertAlmostEqual(arc["radius_mm"], math.hypot(2.5, 0.5)) def test_direct_extrude_lineage_succeeds_and_unregistered_loft_query_preserves_prefix(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = { "00000715": ("f_F2", 2, True), "00005267": ("f_F4", 4, False), } for sample_id, (fillet_id, selector_count, line_type) in cases.items(): with self.subTest(sample_id=sample_id): feature = root / "featurescript_rp" / sample_id[:4] / f"{sample_id}.txt" result = lower_model(parse_featurescript(feature.read_text(), sample_id), {}) self.assertEqual(result.status, "converted_complete") fillet = next(item for item in result.cdsl["features"] if item["id"] == fillet_id) self.assertEqual(len(fillet["selectors"]), selector_count) self.assertTrue(all(item["owner_feature_id"] == fillet["depends_on"][0] for item in fillet["selectors"])) if sample_id == "00000715": self.assertTrue(all("geometry" not in item for item in fillet["selectors"])) self.assertTrue(all( item["selector_intent"]["query_family"] == "SWEPT_EDGE" and item["selector_intent"]["derivation_policy"] == {"allowed": ["boundary"], "multiplicity": "one"} and len(item["selector_intent"]["source_entities"]) == 2 for item in fillet["selectors"] )) else: self.assertTrue(all("bbox_mm" in item["geometry"] for item in fillet["selectors"])) self.assertEqual(["curve_type" in item["geometry"] for item in fillet["selectors"]], [line_type] * selector_count) self.assertTrue(all( item["selector_intent"]["query_family"] == "SWEPT_EDGE" and item["selector_intent"]["evidence"] == "feature_script_query" and item["selector_intent"]["derivation_policy"] == {"allowed": ["continuation"], "multiplicity": "none"} and item["selector_intent"]["source_query"]["featurescript_version"] == "1793" for item in fillet["selectors"] )) with tempfile.TemporaryDirectory() as directory: rebuilt = Path(directory) / "rebuild.step" outcome = rebuild_candidate(result.cdsl, rebuilt) if sample_id == "00005267": self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], "f_F4: selector_query_unsupported during incremental replay") self.assertTrue(rebuilt.exists()) self.assertEqual(outcome["last_executable_prefix"]["failed_feature_id"], "f_F4") self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F3") else: self.assertEqual(outcome["status"], "rebuilt") comparison = compare_steps(root / "step_abc" / sample_id[:4] / f"{sample_id}.step", rebuilt) self.assertTrue(comparison["strict"]["passed"]) def test_swept_edge_requires_one_direct_shared_source_endpoint(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0000/00000715.txt" source = feature.read_text(encoding="utf-8").replace( 'sQuery(id+"F0.wireOp",EDGE,"E8")', 'sQuery(id+"F0.wireOp",EDGE,"E1")', 1, ) result = lower_model(parse_featurescript(source, "swept-edge-ambiguous"), {}) self.assertEqual(result.status, "converted_partial") self.assertEqual(result.diagnostics, [{ "code": "feature_deferred", "feature_id": "F2", "operation": "fillet", "message": "swept edge source endpoint provenance is unsupported", }]) def test_full_revolve_swept_circle_edges_remain_deferred_with_prefixes(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" for sample_id, dressup_id, selector_count in ( ("00048326", "f_F3", 2), ("00025622", "f_F2", 1), ): with self.subTest(sample_id=sample_id): feature = root / "featurescript_rp" / sample_id[:4] / f"{sample_id}.txt" result = lower_model(parse_featurescript(feature.read_text(), sample_id), {}) self.assertEqual(result.status, "converted_complete") dressup = next(item for item in result.cdsl["features"] if item["id"] == dressup_id) self.assertEqual(len(dressup["selectors"]), selector_count) self.assertTrue(all( selector["geometry"].get("curve_type") == "circle" and len(selector["geometry"].get("circle_center_mm") or []) == 3 and selector["geometry"].get("radius_mm", 0) > 0 and selector["selector_intent"]["query_family"] == "SWEPT_EDGE" and selector["selector_intent"]["evidence"] == "feature_script_query" and selector["selector_intent"]["derivation_policy"]["multiplicity"] == "none" for selector in dressup["selectors"] )) with tempfile.TemporaryDirectory() as directory: rebuilt = Path(directory) / "rebuild.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], f"{dressup_id}: selector_query_unsupported during incremental replay") self.assertEqual(outcome["last_executable_prefix"]["failed_feature_id"], dressup_id) def test_full_revolve_swept_circle_requires_one_direct_shared_source_endpoint(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0000/00001352.txt" source = feature.read_text(encoding="utf-8").replace( 'sQuery(id+"F0.wireOp",EDGE,"E2")', 'sQuery(id+"F0.wireOp",EDGE,"E1")', 1, ) result = lower_model(parse_featurescript(source, "revolve-swept-edge-ambiguous"), {}) self.assertEqual(result.status, "converted_partial") self.assertIn({ "code": "feature_deferred", "feature_id": "F2", "operation": "fillet", "message": "swept edge source endpoint provenance is unsupported", }, result.diagnostics) def test_equivalent_imprint_profile_preserves_but_does_not_bind_full_revolve_queries(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" source = root / "featurescript_rp/0011/00112257.txt" result = lower_model(parse_featurescript(source.read_text(), "00112257"), {}) self.assertEqual(result.status, "converted_complete") fillet = next(item for item in result.cdsl["features"] if item["id"] == "f_F2") self.assertEqual(len(fillet["selectors"]), 5) self.assertTrue(all( selector["geometry"].get("curve_type") == "circle" and selector["selector_intent"]["query_family"] == "SWEPT_EDGE" and selector["selector_intent"]["derivation_policy"]["multiplicity"] == "none" for selector in fillet["selectors"] )) from cadfs_to_cdsl.selector_binding import bind_candidate_selectors prefix = dict(result.cdsl) prefix["features"] = result.cdsl["features"][:2] with self.assertRaisesRegex(ValueError, "f_F2: selector_query_unsupported after prefix rebuild"): bind_candidate_selectors(prefix) def test_changed_imprint_profile_does_not_inherit_full_revolve_source_edges(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" source = root / "featurescript_rp/0059/00590828.txt" result = lower_model(parse_featurescript(source.read_text(), "00590828"), {}) self.assertEqual(result.status, "converted_partial") self.assertIn({ "code": "feature_deferred", "feature_id": "F2", "operation": "fillet", "message": "swept edge source endpoint provenance is unsupported", }, result.diagnostics) def test_unsupported_operation_is_audited_not_invented(self): source = SOURCE.replace('extrude(context, id + "F1",', 'draft(context, id + "F1",') result = lower_model(parse_featurescript(source, "00000173"), {}) self.assertEqual(result.status, "deferred_no_executable_feature") self.assertIsNone(result.cdsl) self.assertEqual(result.diagnostics[0]["code"], "unsupported_operation") def test_direct_translation_transform_is_baked_into_the_source_feature(self): result = lower_model(parse_featurescript(TRANSFORM_SOURCE, "transform"), {}) self.assertEqual(result.status, "converted_complete") self.assertEqual([item["id"] for item in result.cdsl["features"]], ["f_F1"]) self.assertEqual(result.history[-1]["feature_id"], "F2") self.assertFalse(result.diagnostics) self.assertEqual(result.cdsl["geometry"]["sketches"][0]["workplane"]["origin_mm"], [10.0, 0.0, 0.0]) def test_copy_transform_lowers_to_an_explicit_body_operation(self): source = TRANSFORM_SOURCE.replace('"makeCopy":false', '"makeCopy":true') result = lower_model(parse_featurescript(source, "transform-copy"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) transform = result.cdsl["features"][-1] self.assertEqual(transform["atomic_id"], "transform_bodies") self.assertEqual(transform["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [10.0, 0.0, 0.0]}, "make_copy": True, }) def test_identity_copy_transform_creates_a_distinct_body_member(self): source = TRANSFORM_SOURCE.replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.COPY', ) result = lower_model(parse_featurescript(source, "identity-copy"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) self.assertEqual(result.cdsl["features"][-1]["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [0.0, 0.0, 0.0]}, "make_copy": True, }) from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(result.cdsl, Path(directory) / "identity-copy.step") self.assertEqual([item["feature_id"] for item in rebuilt["feature_results"]], ["f_F1", "f_F2"]) self.assertEqual(rebuilt["solid_count"], 2) self.assertTrue(any(item["operation"] == "translation" for item in rebuilt["topology_deltas"])) def test_identity_copy_transform_preserves_direct_source_provenance(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = { "00548763": {"f_F2": "f_F1"}, "00853763": {"f_F6": "f_F5"}, # F3 is the exact single-body successor of F1 after a regular # additive fusion. COPY must reference that live member rather # than resurrecting F1's consumed runtime body key. "00981258": {"f_F4": "f_F3", "f_F11": "f_F10"}, } for sample_id, expected_sources in cases.items(): 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), {}) transforms = {item["id"]: item for item in result.cdsl["features"] if item["atomic_id"] == "transform_bodies"} self.assertFalse(any( item.get("feature_id") in {feature_id[2:] for feature_id in expected_sources} and str(item.get("capability") or "").startswith("transform") for item in result.diagnostics )) for feature_id, source_feature_id in expected_sources.items(): self.assertEqual(transforms[feature_id]["params"], { "source_feature_ids": [source_feature_id], "transform": {"type": "translation", "translation_mm": [0.0, 0.0, 0.0]}, "make_copy": True, }) def test_transform_lowers_one_proven_mirror_copy_member(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = { "00120430": {"f_F5": {"pattern_feature_id": "f_F4", "source_feature_id": "f_F1", "instance_index": 1}}, "00749755": {"f_F4": {"pattern_feature_id": "f_F3", "source_feature_id": "f_F1", "instance_index": 1}}, } for sample_id, expected in cases.items(): 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), {}) transforms = {item["id"]: item for item in result.cdsl["features"] if item["atomic_id"] == "transform_bodies"} for feature_id, reference in expected.items(): self.assertEqual(transforms[feature_id]["params"]["pattern_instance_refs"], [reference]) self.assertFalse(any( item.get("feature_id") in {feature_id[2:] for feature_id in expected} and item.get("capability") == "transform_pattern_copy" for item in result.diagnostics )) def test_transform_lowers_source_qualified_multi_source_copy_members(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0069/00699847.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00699847"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) transforms = {item["id"]: item for item in result.cdsl["features"] if item["atomic_id"] == "transform_bodies"} self.assertEqual(transforms["f_F3"]["params"]["source_feature_ids"], ["f_F1", "f_F2"]) self.assertEqual(transforms["f_F4"]["params"]["transform_copy_refs"], [ {"transform_feature_id": "f_F3", "source_feature_id": "f_F1"}, {"transform_feature_id": "f_F3", "source_feature_id": "f_F2"}, ]) self.assertEqual(transforms["f_F4"]["depends_on"], ["f_F1", "f_F2", "f_F3"]) def test_uniform_scale_lowers_to_a_non_rigid_body_transform(self): source = TRANSFORM_SOURCE.replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.SCALE_UNIFORMLY, "scale":0.5, ' '"scalePoint":qCreatedBy(makeId("Origin.pointOp"), VERTEX), "makeCopy":false', ) result = lower_model(parse_featurescript(source, "uniform-scale"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) transform = result.cdsl["features"][-1] self.assertEqual(transform["atomic_id"], "transform_bodies") self.assertEqual(transform["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "uniform_scale", "center_mm": [0.0, 0.0, 0.0], "scale_factor": 0.5}, "make_copy": False, }) from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(result.cdsl, Path(directory) / "uniform-scale.step") self.assertEqual(rebuilt["solid_count"], 1) self.assertAlmostEqual(rebuilt["volume_mm3"], math.pi * 9.53 ** 2 * 120 / 8) self.assertEqual(rebuilt["bbox_mm"], {"min": [-4.765, -4.765, 0.0], "max": [4.765, 4.765, 60.0]}) self.assertTrue(any(item["operation"] == "uniform_scale" for item in rebuilt["topology_deltas"])) def test_uniform_scale_resolves_direct_circle_center_and_rejects_invalid_centers(self): source = TRANSFORM_SOURCE.replace( '"center":v(0, 0) * mm, "radius":9.53 * mm', '"center":v(10, 0) * mm, "radius":9.53 * mm', ).replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.SCALE_UNIFORMLY, "scale":0.5, ' '"scalePoint":sQuery(id + "F0.wireOp", VERTEX, "E0.center"), "makeCopy":false', ) result = lower_model(parse_featurescript(source, "uniform-scale-circle-center"), {}) self.assertEqual(result.status, "converted_complete") self.assertEqual(result.cdsl["features"][-1]["params"]["transform"], { "type": "uniform_scale", "center_mm": [10.0, 0.0, 0.0], "scale_factor": 0.5, }) zero_factor = lower_model(parse_featurescript(source.replace('"scale":0.5', '"scale":0'), "uniform-scale-zero"), {}) self.assertEqual(zero_factor.status, "converted_partial") self.assertEqual(zero_factor.diagnostics[-1]["capability"], "transform_uniform_scale") unresolved_center = lower_model(parse_featurescript(source.replace( 'sQuery(id + "F0.wireOp", VERTEX, "E0.center")', 'qCreatedBy(id + "F1", VERTEX)', ), "uniform-scale-unresolved-center"), {}) self.assertEqual(unresolved_center.status, "converted_partial") self.assertEqual(unresolved_center.diagnostics[-1]["capability"], "transform_uniform_scale_center") def test_non_copy_uniform_scale_preserves_a_later_source_owner_alias(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0041/00417936.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00417936"), {}) self.assertEqual(result.status, "converted_complete") transforms = [item for item in result.cdsl["features"] if item["atomic_id"] == "transform_bodies"] self.assertEqual([item["params"]["source_feature_ids"] for item in transforms], [["f_F1"], ["f_F2"]]) self.assertEqual([item["params"]["transform"]["scale_factor"] for item in transforms], [10.0, 1.5]) from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(result.cdsl, Path(directory) / "sequential-uniform-scale.step") self.assertEqual(rebuilt["solid_count"], 1) self.assertEqual([item["feature_id"] for item in rebuilt["feature_results"]], ["f_F1", "f_F2", "f_F3"]) self.assertEqual( [item["operation"] for item in rebuilt["topology_deltas"]], ["extrude", "uniform_scale", "uniform_scale"], ) def test_single_body_successor_aliases_clear_at_body_graph_boundaries(self): for boundary in ( {"id": "f_copy", "atomic_id": "transform_bodies", "params": {"make_copy": True}}, {"id": "f_boolean", "atomic_id": "boolean_bodies", "params": {}}, {"id": "f_pattern", "atomic_id": "pattern_circular", "params": {}}, {"id": "f_delete", "atomic_id": "delete_bodies", "params": {}}, ): with self.subTest(boundary=boundary["atomic_id"]): aliases = {} state = {"owner": None, "sources": set()} _record_single_body_successor(aliases, state, { "id": "f_base", "atomic_id": "extrude_add_blind", "params": {"result_mode": "new_body"}, }) _record_single_body_successor(aliases, state, { "id": "f_add", "atomic_id": "extrude_add_blind", "params": {}, }) self.assertEqual(aliases, {"f_base": "f_add"}) _record_single_body_successor(aliases, state, boundary) self.assertEqual(aliases, {}) self.assertIsNone(state["owner"]) self.assertEqual(state["sources"], set()) def test_shell_parts_lowers_to_a_live_member_or_proven_sole_body_alias(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" successor = root / "featurescript_rp/0010/00107631.txt" result = lower_model(parse_featurescript(successor.read_text(), "00107631"), {}) shell = next(feature for feature in result.cdsl["features"] if feature["id"] == "f_F3") self.assertEqual(shell["params"]["target_feature_id"], "f_F2") self.assertFalse(any( diagnostic.get("capability") == "shell_parts_body_source" for diagnostic in result.diagnostics )) patterned = root / "featurescript_rp/0054/00542223.txt" result = lower_model(parse_featurescript(patterned.read_text(), "00542223"), {}) shell = next(feature for feature in result.cdsl["features"] if feature["id"] == "f_F7") self.assertEqual(shell["params"]["target_feature_id"], "f_F5") self.assertFalse(any( diagnostic.get("capability") == "shell_parts_body_source" for diagnostic in result.diagnostics )) def test_translation_distance_lowers_from_a_linear_sketch_direction(self): source = TRANSFORM_SOURCE.replace( 'skCircle(sketch, "E0", {"center":v(0, 0) * mm, "radius":9.53 * mm}); skSolve(sketch);', 'skCircle(sketch, "E0", {"center":v(0, 0) * mm, "radius":9.53 * mm}); ' 'skLineSegment(sketch, "E1", {"start":v(0, 0) * mm, "end":v(1, 0) * mm, "construction":true}); skSolve(sketch);', ).replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.TRANSLATION_DISTANCE, "transformDirection":sQuery(id + "F0.wireOp", EDGE, "E1"), ' '"distance":10 * mm, "oppositeDirection":true, "makeCopy":false', ) moved = lower_model(parse_featurescript(source, "distance-move"), {}) self.assertEqual(moved.status, "converted_complete") self.assertFalse(moved.diagnostics) self.assertEqual(moved.cdsl["geometry"]["sketches"][0]["workplane"]["origin_mm"], [-10.0, 0.0, 0.0]) datum_plane = TRANSFORM_SOURCE.replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.TRANSLATION_DISTANCE, ' '"transformDirection":qCreatedBy(makeId("Front.planeOp"), FACE), ' '"distance":10 * mm, "makeCopy":true', ) datum_result = lower_model(parse_featurescript(datum_plane, "distance-datum-plane"), {}) self.assertEqual(datum_result.status, "converted_complete") self.assertEqual(datum_result.cdsl["features"][-1]["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [0.0, -10.0, 0.0]}, "make_copy": True, }) square = ( 'skLineSegment(sketch, "E0", {"start":v(0, 0) * mm, "end":v(10, 0) * mm}); ' 'skLineSegment(sketch, "E1", {"start":v(10, 0) * mm, "end":v(10, 10) * mm}); ' 'skLineSegment(sketch, "E2", {"start":v(10, 10) * mm, "end":v(0, 10) * mm}); ' 'skLineSegment(sketch, "E3", {"start":v(0, 10) * mm, "end":v(0, 0) * mm}); skSolve(sketch);' ) swept_face = TRANSFORM_SOURCE.replace( 'skCircle(sketch, "E0", {"center":v(0, 0) * mm, "radius":9.53 * mm}); skSolve(sketch);', square, ).replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.TRANSLATION_DISTANCE, ' '"transformDirection":makeQuery(id + "F1.opExtrude", "SWEPT_FACE", FACE, ' '{"derivedFrom":sQuery(id + "F0.wireOp", EDGE, "E0")}), ' '"distance":10 * mm, "makeCopy":true', ) swept_result = lower_model(parse_featurescript(swept_face, "distance-swept-face"), {}) self.assertEqual(swept_result.status, "converted_complete") self.assertEqual(swept_result.cdsl["features"][-1]["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [0.0, -10.0, 0.0]}, "make_copy": True, }) copied = lower_model(parse_featurescript(source.replace('"makeCopy":false', '"makeCopy":true'), "distance-copy"), {}) self.assertEqual(copied.status, "converted_complete") self.assertFalse(copied.diagnostics) self.assertEqual(copied.cdsl["features"][-1]["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [-10.0, 0.0, 0.0]}, "make_copy": True, }) from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(copied.cdsl, Path(directory) / "distance-copy.step") self.assertEqual(rebuilt["solid_count"], 2) self.assertEqual(rebuilt["bbox_mm"]["min"], [-19.53, -9.53, 0.0]) self.assertEqual(rebuilt["bbox_mm"]["max"], [9.53, 9.53, 120.0]) def test_translation_distance_cap_edge_uses_its_physical_frame(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0066/00665176.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00665176"), {}) transforms = {item["id"]: item for item in result.cdsl["features"] if item["atomic_id"] == "transform_bodies"} self.assertEqual(transforms["f_F2"]["params"]["transform"], {"type": "translation", "translation_mm": [0.0, 0.0, 381.0]}) self.assertEqual(transforms["f_F3"]["params"]["transform"], {"type": "translation", "translation_mm": [127.0, 0.0, 0.0]}) self.assertEqual(transforms["f_F4"]["params"]["transform"], {"type": "translation", "translation_mm": [-127.0, 0.0, 0.0]}) self.assertNotIn("F2", [item.get("feature_id") for item in result.diagnostics]) self.assertNotIn("F3", [item.get("feature_id") for item in result.diagnostics]) self.assertNotIn("F4", [item.get("feature_id") for item in result.diagnostics]) def test_translation_distance_cap_face_uses_its_physical_normal(self): source = TRANSFORM_SOURCE.replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.TRANSLATION_DISTANCE, ' '"transformDirection":makeQuery(id + "F1.opExtrude", "CAP_FACE", FACE, ' '{"derivedFrom":sQuery(id + "F0.wireOp", EDGE, "E0"), "isStart":false}), ' '"distance":10 * mm, "makeCopy":true', ) result = lower_model(parse_featurescript(source, "distance-cap-face"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) self.assertEqual(result.cdsl["features"][-1]["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [0.0, 0.0, 10.0]}, "make_copy": True, }) root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0007/00078650.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") real = lower_model(parse_featurescript(feature.read_text(), "00078650"), {}) self.assertEqual(real.status, "converted_complete") transform = next(item for item in real.cdsl["features"] if item["id"] == "f_F4") self.assertEqual(transform["params"], { "source_feature_ids": ["f_F1", "f_F2", "f_F3"], "transform": {"type": "translation", "translation_mm": [0.0, -431.8, 0.0]}, "make_copy": True, }) def test_translation_distance_rejects_a_curved_direction(self): source = TRANSFORM_SOURCE.replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.TRANSLATION_DISTANCE, "transformDirection":sQuery(id + "F0.wireOp", EDGE, "E0"), ' '"distance":10 * mm, "makeCopy":false', ) result = lower_model(parse_featurescript(source, "distance-curve"), {}) self.assertEqual(result.status, "converted_partial") self.assertEqual(result.diagnostics[-1]["capability"], "transform_translation_direction") cap_circle = lower_model(parse_featurescript(source.replace( 'sQuery(id + "F0.wireOp", EDGE, "E0")', 'makeQuery(id + "F1.opExtrude", "CAP_EDGE", EDGE, {"derivedFrom":sQuery(id + "F0.wireOp", EDGE, "E0"), "isStart":false})', ), "distance-cap-circle"), {}) self.assertEqual(cap_circle.status, "converted_partial") self.assertEqual(cap_circle.diagnostics[-1]["capability"], "transform_translation_direction") def test_translation_entity_lowers_direct_line_and_vertex_vectors(self): sketch = ( 'skCircle(sketch, "E0", {"center":v(0, 0) * mm, "radius":9.53 * mm}); ' 'skLineSegment(sketch, "E1", {"start":v(0, 0) * mm, "end":v(2, 0) * mm, "construction":true}); ' 'skPoint(sketch, "E2", {"position":v(0, 0) * mm}); ' 'skPoint(sketch, "E3", {"position":v(0, 5) * mm}); skSolve(sketch);' ) line_source = TRANSFORM_SOURCE.replace( 'skCircle(sketch, "E0", {"center":v(0, 0) * mm, "radius":9.53 * mm}); skSolve(sketch);', sketch, ).replace( '"transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false', '"transformType":TransformType.TRANSLATION_ENTITY, "transformLine":sQuery(id + "F0.wireOp", EDGE, "E1"), ' '"oppositeDirectionEntity":false, "makeCopy":true', ) copied = lower_model(parse_featurescript(line_source, "entity-line-copy"), {}) self.assertEqual(copied.status, "converted_complete") self.assertEqual(copied.cdsl["features"][-1]["params"], { "source_feature_ids": ["f_F1"], "transform": {"type": "translation", "translation_mm": [2.0, 0.0, 0.0]}, "make_copy": True, }) vertex_source = line_source.replace( '"transformLine":sQuery(id + "F0.wireOp", EDGE, "E1"), "oppositeDirectionEntity":false, "makeCopy":true', '"transformLine":qUnion([sQuery(id + "F0.wireOp", VERTEX, "E2"), sQuery(id + "F0.wireOp", VERTEX, "E3")]), ' '"oppositeDirectionEntity":false, "makeCopy":false', ) moved = lower_model(parse_featurescript(vertex_source, "entity-vertices-move"), {}) self.assertEqual(moved.status, "converted_complete") self.assertEqual(moved.cdsl["geometry"]["sketches"][0]["workplane"]["origin_mm"], [0.0, 5.0, 0.0]) curved = lower_model(parse_featurescript(line_source.replace('EDGE, "E1"', 'EDGE, "E0"'), "entity-curve"), {}) self.assertEqual(curved.status, "converted_partial") self.assertEqual(curved.diagnostics[-1]["capability"], "transform_translation_entity") cap_circle = lower_model(parse_featurescript(line_source.replace( 'sQuery(id + "F0.wireOp", EDGE, "E1")', 'makeQuery(id + "F1.opExtrude", "CAP_EDGE", EDGE, {"derivedFrom":sQuery(id + "F0.wireOp", EDGE, "E0"), "isStart":false})', ), "entity-cap-circle"), {}) self.assertEqual(cap_circle.status, "converted_partial") self.assertEqual(cap_circle.diagnostics[-1]["capability"], "transform_translation_entity") def test_translation_entity_real_line_cap_and_body_lifecycle_boundaries(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" direct = root / "featurescript_rp/0012/00122249.txt" cap_edge = root / "featurescript_rp/0018/00184423.txt" absorbed = root / "featurescript_rp/0022/00226751.txt" if not all(path.exists() for path in (direct, cap_edge, absorbed)): self.skipTest("CADFS samples are not installed") direct_result = lower_model(parse_featurescript(direct.read_text(), "00122249"), {}) self.assertEqual(direct_result.status, "converted_complete") moved_sketch = next(item for item in direct_result.cdsl["geometry"]["sketches"] if item["id"] == "sketch_F1__f_F2") self.assertEqual(moved_sketch["workplane"]["origin_mm"], [-7.0, 0.0, 0.0]) cap_result = lower_model(parse_featurescript(cap_edge.read_text(), "00184423"), {}) transform = next(item for item in cap_result.cdsl["features"] if item["id"] == "f_F2") self.assertEqual(transform["params"]["transform"], {"type": "translation", "translation_mm": [12.7, 0.0, 0.0]}) self.assertEqual(cap_result.status, "converted_complete") self.assertFalse(cap_result.diagnostics) transforms = {item["id"]: item for item in cap_result.cdsl["features"] if item["atomic_id"] == "transform_bodies"} self.assertEqual( {feature_id: item["params"]["source_feature_ids"] for feature_id, item in transforms.items()}, {"f_F2": ["f_F1"], "f_F3": ["f_F2"], "f_F4": ["f_F3"], "f_F5": ["f_F4"], "f_F6": ["f_F4"]}, ) self.assertEqual(transforms["f_F5"]["params"]["transform"]["type"], "translation") for actual, expected in zip(transforms["f_F5"]["params"]["transform"]["translation_mm"], [0.0, -12.7, 0.0]): self.assertAlmostEqual(actual, expected) from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(cap_result.cdsl, Path(directory) / "transform-copy-chain.step") self.assertEqual(rebuilt["solid_count"], 6) self.assertEqual([item["feature_id"] for item in rebuilt["feature_results"]], [ "f_F1", "f_F2", "f_F3", "f_F4", "f_F5", "f_F6", ]) self.assertFalse(rebuilt["runtime_diagnostics"]) absorbed_result = lower_model(parse_featurescript(absorbed.read_text(), "00226751"), {}) self.assertEqual(absorbed_result.diagnostics[-1]["capability"], "transform_body_lifecycle") def test_direct_swept_body_delete_lowers_to_a_body_graph_operation(self): source = SOURCE.replace( '\n});\n', ''' { var Q0; Q0=makeQuery(id + "F1.opExtrude", "SWEPT_BODY", BODY, {}); deleteBodies(context, id + "F2", {"entities":qUnion([Q0])}); } }); ''', ) result = lower_model(parse_featurescript(source, "delete-body"), {}) self.assertEqual(result.status, "converted_complete") delete = result.cdsl["features"][-1] self.assertEqual(delete["atomic_id"], "delete_bodies") self.assertEqual(delete["params"], {"target_feature_ids": ["f_F1"]}) def test_symmetric_cut_lowers_to_two_sided_cut(self): source = SOURCE.replace('"depth":120 * mm', '"operationType":NewBodyOperationType.REMOVE, "depth":120 * mm, "symmetric":true') result = lower_model(parse_featurescript(source, "symmetric-cut"), {}) self.assertEqual(result.status, "converted_complete") feature = result.cdsl["features"][0] self.assertEqual(feature["atomic_id"], "extrude_cut_two_sided") self.assertEqual(feature["params"]["distance_mm"], 60.0) self.assertEqual(feature["params"]["reverse_distance_mm"], 60.0) def test_through_all_extrudes_reuse_the_engine_extent_contract(self): for operation_type, expected_atomic in [ ("NewBodyOperationType.NEW", "extrude_add_blind"), ("NewBodyOperationType.REMOVE", "extrude_cut_blind"), ]: with self.subTest(operation_type=operation_type): source = SOURCE.replace( '"depth":120 * mm', f'"operationType":{operation_type}, "depth":120 * mm, "endBound":BoundingType.THROUGH_ALL', ) result = lower_model(parse_featurescript(source, f"through-all-{operation_type}"), {}) self.assertEqual(result.status, "converted_complete") feature = result.cdsl["features"][0] self.assertEqual(feature["atomic_id"], expected_atomic) self.assertEqual(feature["params"]["end_condition"]["type"], "through_all") def test_up_to_next_extrudes_reuse_the_engine_extent_contract(self): for operation_type, expected_atomic in [ ("NewBodyOperationType.NEW", "extrude_add_blind"), ("NewBodyOperationType.REMOVE", "extrude_cut_blind"), ]: with self.subTest(operation_type=operation_type): source = SOURCE.replace( '"depth":120 * mm', f'"operationType":{operation_type}, "depth":120 * mm, "endBound":BoundingType.UP_TO_NEXT', ) result = lower_model(parse_featurescript(source, f"up-to-next-{operation_type}"), {}) self.assertEqual(result.status, "converted_complete") feature = result.cdsl["features"][0] self.assertEqual(feature["atomic_id"], expected_atomic) self.assertEqual(feature["params"]["end_condition"]["type"], "through_next") def test_implicit_extrude_after_a_body_uses_default_new_body_semantics(self): source = SOURCE.replace( '\n});\n', ''' { var Q0; Q0=qSketchRegion(id + "F0", true); extrude(context, id + "F2", {"entities":qUnion([Q0]), "depth":20 * mm}); } }); ''', ) result = lower_model(parse_featurescript(source, "implicit-add"), {}) first, second = result.cdsl["features"] self.assertEqual(first["params"]["result_mode"], "new_body") self.assertEqual(second["params"]["result_mode"], "new_body") def test_up_to_body_extrude_captures_target_and_offset(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0069/00694309.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00694309"), {}) self.assertEqual(result.status, "converted_complete") extrude = next(item for item in result.cdsl["features"] if item["id"] == "f_F3") end = extrude["params"]["end_condition"] self.assertEqual(end["type"], "up_to_body") self.assertEqual(end["offset_mm"], 3.0) self.assertEqual(end["reference"]["kind"], "body") self.assertEqual(end["reference"]["owner_feature_id"], "f_F1") self.assertEqual(end["reference"]["source"], "runtime_snapshot") self.assertNotIn("stable_id", end["reference"]) self.assertEqual(end["reference"]["selector_intent"]["query_family"], "SWEPT_BODY") self.assertEqual(end["reference"]["selector_intent"]["evidence"], "active_body_member") self.assertEqual( end["reference"]["selector_intent"]["derivation_policy"], {"allowed": ["boundary"], "multiplicity": "one"}, ) fillet = next(item for item in result.cdsl["features"] if item["id"] == "f_F4") self.assertEqual(len(fillet["selectors"]), 1) self.assertEqual(fillet["selectors"][0]["selector_intent"]["query_family"], "CAP_EDGE") self.assertEqual( fillet["selectors"][0]["selector_intent"]["derivation_policy"], {"allowed": ["boundary", "continuation"], "multiplicity": "one"}, ) from engine.cdsl_engine.semantic_validation import validate_semantic_cdsl mixed_evidence = deepcopy(result.cdsl) mixed_reference = next( item for item in mixed_evidence["features"] if item["id"] == "f_F3" )["params"]["end_condition"]["reference"] mixed_reference["stable_id"] = "body:f_F1" with self.assertRaisesRegex(ValueError, "invalid SWEPT_BODY member contract"): validate_semantic_cdsl(mixed_evidence) def test_up_to_surface_extrude_captures_the_cap_face(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0092/00925274.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00925274"), {}) extrude = next(item for item in result.cdsl["features"] if item["id"] == "f_F3") end = extrude["params"]["end_condition"] self.assertEqual(end["type"], "up_to_surface") self.assertEqual(end["reference"]["kind"], "face") self.assertEqual(end["reference"]["owner_feature_id"], "f_F1") self.assertEqual(end["reference"]["output_role"], "extrude.start") self.assertEqual(end["reference"]["source"], "runtime_snapshot") self.assertNotIn("geometry", end["reference"]) self.assertEqual(end["reference"]["selector_intent"]["query_family"], "CAP_FACE") self.assertEqual(end["reference"]["selector_intent"]["evidence"], "operation_role") swept = next(item for item in result.cdsl["features"] if item["id"] == "f_F6") swept_reference = swept["params"]["end_condition"]["reference"] self.assertEqual(swept_reference["selector_intent"]["query_family"], "SWEPT_FACE") self.assertEqual( swept_reference["selector_intent"]["derivation_policy"], {"allowed": ["boundary", "continuation"], "multiplicity": "one"}, ) self.assertEqual(swept_reference["selector_intent"]["evidence"], "kernel_history") self.assertEqual(swept_reference["selector_intent"]["source_entity"], {"sketch_id": "F0", "entity_id": "E0"}) self.assertEqual(swept_reference["source"], "runtime_snapshot") self.assertNotIn("stable_id", swept_reference) self.assertNotIn("binding_feature_id", swept_reference) self.assertNotIn("geometry", swept_reference) mirror = next(item for item in result.cdsl["features"] if item["id"] == "f_F18") self.assertTrue(mirror["params"]["mirror_current_body"]) def test_mirrored_copy_cap_face_uses_the_mirrored_loft_frame(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0061/00612529.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00612529"), {}) sketch = next(item for item in result.cdsl["geometry"]["sketches"] if item["id"] == "sketch_F6") plane = sketch["workplane"] self.assertEqual(plane["origin_mm"], [0.0, 50.0, 0.0]) self.assertEqual(plane["normal"], [0.0, 1.0, 0.0]) self.assertEqual(plane["x_dir"], [-1.0, 0.0, 0.0]) spline = sketch["profile"]["contours"][0]["segments"][0] first = spline["points"][0] self.assertEqual([ plane["origin_mm"][index] + plane["x_dir"][index] * first[0] + (plane["normal"][(index + 1) % 3] * plane["x_dir"][(index + 2) % 3] - plane["normal"][(index + 2) % 3] * plane["x_dir"][(index + 1) % 3]) * first[1] for index in range(3) ], [-60.68, 50.0, 66.22]) def test_line_angle_opposite_direction_preserves_the_sketch_side(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0092/00925274.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00925274"), {}) sketch = next(item for item in result.cdsl["geometry"]["sketches"] if item["id"] == "sketch_F8") plane = sketch["workplane"] y_dir = [ plane["normal"][1] * plane["x_dir"][2] - plane["normal"][2] * plane["x_dir"][1], plane["normal"][2] * plane["x_dir"][0] - plane["normal"][0] * plane["x_dir"][2], plane["normal"][0] * plane["x_dir"][1] - plane["normal"][1] * plane["x_dir"][0], ] center = sketch["profile"]["center"] self.assertAlmostEqual(plane["origin_mm"][2] + y_dir[2] * center[1], 25.0) def test_line_angle_cylinder_reference_uses_the_surface_generatrix(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0092/00925274.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00925274"), {}) sketch = next(item for item in result.cdsl["geometry"]["sketches"] if item["id"] == "sketch_F5") plane = sketch["workplane"] self.assertAlmostEqual(plane["normal"][0], -0.5) self.assertAlmostEqual(plane["normal"][1], -math.sqrt(3) / 2) self.assertAlmostEqual(plane["origin_mm"][0], -12.15) self.assertAlmostEqual(plane["origin_mm"][1], -24.3 * math.sqrt(3) / 2) def test_line_angle_direct_circle_uses_the_featurescript_circle_axis(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0003/00030209.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00030209"), {}) self.assertEqual(result.status, "converted_partial") planes = { item["id"]: item["params"]["plane"] for item in result.cdsl["features"] if item["atomic_id"] == "reference_plane" } expected_centers = { "f_F1": [45.78, 0.0, 26.2], "f_F2": [13.9, 0.0, 26.5], "f_F4": [-17.08, 0.0, 23.46], "f_F5": [-44.4, 0.0, 19.8], } self.assertEqual(set(planes), set(expected_centers)) for feature_id, center in expected_centers.items(): with self.subTest(feature_id=feature_id): plane = planes[feature_id] self.assertEqual(plane["origin_mm"], center) self.assertEqual(plane["x_dir"], [0.0, -1.0, 0.0]) self.assertAlmostEqual(plane["normal"][0], 1.0) self.assertAlmostEqual(plane["normal"][1], 0.0) self.assertAlmostEqual(plane["normal"][2], 0.0) self.assertFalse(any( diagnostic.get("operation") == "cPlane" for diagnostic in result.diagnostics )) opposite_source = feature.read_text().replace( '"angle" : 90 * degree, "width"', '"angle" : 90 * degree, "oppositeDirection" : true, "width"', 1, ) opposite = lower_model(parse_featurescript(opposite_source, "line-angle-circle-opposite"), {}) opposite_plane = next( item for item in opposite.cdsl["features"] if item["id"] == "f_F1" )["params"]["plane"] self.assertAlmostEqual(opposite_plane["normal"][0], -1.0) self.assertAlmostEqual(opposite_plane["normal"][1], 0.0) self.assertAlmostEqual(opposite_plane["normal"][2], 0.0) def test_line_angle_two_entities_follow_axis_plane_order_and_swap_rules(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = { # F8 selects Right plane first, then the direct F7 line. The # standard library must swap them before calculating the frame. "00298026": ("f_F8", [0.0, -1.0, 0.0], [0.43837114678907757, 0.0, -0.898794046299167]), # F1 supplies the direct line first and the default plane second. "00586156": ("f_F1", [0.0, 0.0, 1.0], [-math.sqrt(0.5), -math.sqrt(0.5), 0.0]), } for sample_id, (feature_id, expected_x, expected_normal) in cases.items(): with self.subTest(sample_id=sample_id): source = root / "featurescript_rp" / sample_id[:4] / f"{sample_id}.txt" result = lower_model(parse_featurescript(source.read_text(), sample_id), {}) plane = next(item for item in result.cdsl["features"] if item["id"] == feature_id)["params"]["plane"] self.assertEqual(plane["x_dir"], expected_x) for actual, expected in zip(plane["normal"], expected_normal): self.assertAlmostEqual(actual, expected) self.assertFalse(any( diagnostic.get("operation") == "cPlane" and diagnostic.get("feature_id") == feature_id.removeprefix("f_") for diagnostic in result.diagnostics )) def test_line_angle_two_direct_entities_cover_axis_point_and_degenerate_contracts(self): result = lower_model(parse_featurescript(LINE_ANGLE_TWO_ENTITY_SOURCE, "line-angle-two-entities"), {}) self.assertEqual(result.status, "converted_partial") planes = { item["id"]: item["params"]["plane"] for item in result.cdsl["features"] if item["atomic_id"] == "reference_plane" } # Nonparallel axes, parallel offset axes, and an axis plus a direct # point each use the exact source direction, rather than a sketch # workplane frame. for feature_id in ("f_F1", "f_F2", "f_F3"): self.assertEqual(planes[feature_id]["x_dir"], [1.0, 0.0, 0.0]) self.assertEqual(planes[feature_id]["normal"], [0.0, 0.0, 1.0]) # A point selected before its axis triggers FeatureScript's swap. The # signed angle also follows oppositeDirection. self.assertEqual(planes["f_F4"]["x_dir"], [1.0, 0.0, 0.0]) self.assertAlmostEqual(planes["f_F4"]["normal"][0], 0.0) self.assertAlmostEqual(planes["f_F4"]["normal"][1], 1.0) self.assertAlmostEqual(planes["f_F4"]["normal"][2], 0.0) # A cPlane output is represented as qCreatedBy(...planeOp, FACE), # not a sketch source. It is accepted only because F1 is an existing # reference-plane frame, and it supplies the true zero-angle side. self.assertEqual(planes["f_F6"]["x_dir"], [1.0, 0.0, 0.0]) self.assertEqual(planes["f_F6"]["normal"], [0.0, 0.0, -1.0]) self.assertIn({ "code": "feature_deferred", "feature_id": "F5", "operation": "cPlane", "message": "line-angle reference selection is degenerate", }, result.diagnostics) def test_line_angle_direct_axis_refuses_a_topology_derived_query(self): direct = Call("sQuery", ["F0.wireOp", "EDGE", "E0"], 1) derived = Call("makeQuery", [ "F1.opExtrude", "CAP_EDGE", "EDGE", {"derivedFrom": direct, "isStart": False}, ], 2) sketch_by_source = {"F0": {"workplane": { "origin_mm": [0.0, 0.0, 0.0], "x_dir": [1.0, 0.0, 0.0], "normal": [0.0, 0.0, 1.0], }}} entity_by_sketch = {"F0": {"E0": { "type": "line", "start": [0.0, 0.0], "end": [10.0, 0.0], "source_entity_id": "E0", }}} self.assertIsNotNone(_direct_line_angle_axis(direct, sketch_by_source, entity_by_sketch)) self.assertIsNone(_direct_line_angle_axis(derived, sketch_by_source, entity_by_sketch)) def test_line_angle_direct_axis_refuses_a_query_wrapper_and_keeps_the_prefix(self): direct = Call("sQuery", ["F0.wireOp", "EDGE", "E0"], 1) wrapped = Call("qAdjacent", [direct, "VERTEX", "EDGE"], 2) sketch_by_source = {"F0": {"workplane": { "origin_mm": [0.0, 0.0, 0.0], "x_dir": [1.0, 0.0, 0.0], "normal": [0.0, 0.0, 1.0], }}} entity_by_sketch = {"F0": {"E0": { "type": "line", "start": [0.0, 0.0], "end": [10.0, 0.0], "source_entity_id": "E0", }}} self.assertIsNone(_direct_line_angle_axis(wrapped, sketch_by_source, entity_by_sketch)) model = parse_featurescript(LINE_ANGLE_TWO_ENTITY_SOURCE, "line-angle-wrapped-axis") plane = next(item for item in model.features if item.feature_id == "F1") plane.params["entities"].args[0][0] = wrapped result = lower_model(model, {}) self.assertIn({ "code": "feature_deferred", "feature_id": "F1", "operation": "cPlane", "message": "line-angle reference selection is unsupported", }, result.diagnostics) self.assertIn("f_F2", {item["id"] for item in result.cdsl["features"]}) def test_line_angle_rejects_a_circle_center_vertex_as_an_axis(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0003/00030209.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") source = feature.read_text().replace( 'Q0=sQuery(id+"F0.wireOp",EDGE,"E0");', 'Q0=sQuery(id+"F0.wireOp",VERTEX,"E0.center");', 1, ) result = lower_model(parse_featurescript(source, "line-angle-circle-center"), {}) self.assertIn({ "code": "feature_deferred", "feature_id": "F1", "operation": "cPlane", "message": "line-angle reference selection is unsupported", }, result.diagnostics) def test_open_nonconstruction_geometry_is_preserved_as_reference(self): source = SOURCE.replace('skSolve(sketch);', 'skLineSegment(sketch, "open", {"start":v(0, 0) * mm, "end":v(20, 0) * mm}); skSolve(sketch);', 1) result = lower_model(parse_featurescript(source, "open-profile"), {}) self.assertEqual(result.status, "converted_complete") profile = result.cdsl["geometry"]["sketches"][0]["profile"] self.assertEqual(profile["type"], "analytic_contours") self.assertEqual(profile["construction"][0]["type"], "line") def test_open_imprint_profiles_and_mixed_sketch_context_lower_for_00789939(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"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertEqual(features["f_F8"]["sketch_id"], "sketch_F7__f_F8") self.assertEqual(features["f_F10"]["sketch_id"], "sketch_F9__f_F10") self.assertEqual(features["f_F12"]["sketch_id"], "sketch_F11") self.assertFalse(sketches["sketch_F7__f_F8"]["profile"]["contours"][0]["closed"]) self.assertEqual(sketches["sketch_F7__f_F8"]["workplane"]["origin_mm"], [45.7, 0.0, 0.0]) self.assertEqual(sketches["sketch_F9__f_F10"]["workplane"]["origin_mm"], [-44.3, -0.0, -0.0]) self.assertEqual(sketches["sketch_F7__f_F8"]["workplane"]["normal"], [1.0, -0.0, -0.0]) self.assertEqual(sketches["sketch_F9__f_F10"]["workplane"]["normal"], [-1.0, -0.0, -0.0]) self.assertEqual(sketches["sketch_F9__f_F10"]["workplane"]["x_dir"], [-0.0, -1.0, -0.0]) def test_offset_face_profile_is_the_proven_linear_extrusion_wall(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"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertEqual(features["f_F15"]["sketch_id"], "sketch_F5__f_F15") sketch = sketches["sketch_F5__f_F15"] self.assertEqual(sketch["workplane"]["origin_mm"], [-0.0, 52.19, -0.0]) self.assertEqual(sketch["workplane"]["normal"], [0.0, -1.0, 0.0]) points = { tuple(round(component, 6) for component in endpoint) for segment in sketch["profile"]["contours"][0]["segments"] for endpoint in (segment["start"], segment["end"]) } self.assertEqual(points, {(-45.0, 2.5), (45.0, 2.5), (45.0, 6.0), (-45.0, 6.0)}) def test_offset_face_profile_defers_when_query_has_multiple_source_edges(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") source = feature.read_text(encoding="utf-8").replace( 'Q0=makeQuery(id+"F5.opShell","OFFSET_FACE",FACE,{"disambiguationData":[OSD([sQuery(id+"F3.wireOp",EDGE,"E1.bottom")])]});', 'Q0=makeQuery(id+"F5.opShell","OFFSET_FACE",FACE,{"disambiguationData":[OSD([sQuery(id+"F3.wireOp",EDGE,"E1.bottom"),sQuery(id+"F3.wireOp",EDGE,"E1.top")])]});', 1, ) result = lower_model(parse_featurescript(source, "00789939-offset-face-multi-source"), {}) self.assertNotIn("f_F15", {item["id"] for item in result.cdsl["features"]}) diagnostic = next(item for item in result.diagnostics if item.get("feature_id") == "F15") self.assertEqual(diagnostic["capability"], "extrude_profile_topology:offset_face") def test_offset_face_profile_defers_for_non_direct_shell_provenance(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0058/00588094.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00588094"), {}) self.assertNotIn("f_F14", {item["id"] for item in result.cdsl["features"]}) diagnostic = next(item for item in result.diagnostics if item.get("feature_id") == "F14") self.assertEqual(diagnostic["capability"], "extrude_profile_topology:offset_face") def test_circular_pattern_uses_the_proven_fused_body_successor(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"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F6"]["params"]["source_feature_ids"], ["f_F5"]) def test_circular_copy_boolean_uses_the_proven_fused_body_successor(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0025/00253824.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00253824"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(result.status, "converted_complete") self.assertEqual(features["f_F5"]["params"]["source_feature_ids"], ["f_F4"]) self.assertEqual(features["f_F6"]["params"], { "operation": "union", "keep_tools": False, "target_feature_ids": ["f_F4"], "tool_pattern_instance_refs": [ {"pattern_feature_id": "f_F5", "source_feature_id": "f_F4", "instance_index": 2}, {"pattern_feature_id": "f_F5", "source_feature_id": "f_F4", "instance_index": 1}, ], }) def test_shared_sketch_edge_produces_each_bounded_region(self): segments = [ {"type": "line", "start": [0, 0], "end": [1, 0]}, {"type": "line", "start": [1, 0], "end": [2, 0]}, {"type": "line", "start": [2, 0], "end": [2, 1]}, {"type": "line", "start": [2, 1], "end": [1, 1]}, {"type": "line", "start": [1, 1], "end": [0, 1]}, {"type": "line", "start": [0, 1], "end": [0, 0]}, {"type": "line", "start": [1, 0], "end": [1, 1]}, ] contours, construction = _contours(segments) self.assertEqual(len(contours), 2) self.assertFalse(construction) self.assertEqual(sorted(len(item["segments"]) for item in contours), [4, 4]) def test_vertex_on_long_line_is_split_before_region_extraction(self): segments = [ {"type": "line", "start": [0, 0], "end": [2, 0]}, {"type": "line", "start": [2, 0], "end": [2, 2]}, {"type": "line", "start": [2, 2], "end": [0, 2]}, {"type": "line", "start": [0, 2], "end": [0, 0]}, {"type": "line", "start": [2, 0.5], "end": [3, 0.5]}, {"type": "line", "start": [3, 0.5], "end": [3, 1.5]}, {"type": "line", "start": [3, 1.5], "end": [2, 1.5]}, ] contours, construction = _contours(segments) self.assertEqual(len(contours), 2) self.assertFalse(construction) def test_surface_operation_on_a_closed_region_lowers_to_a_solid_revolve(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0095/00957738.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00957738"), {}) self.assertEqual(result.status, "converted_complete") feature = next(item for item in result.cdsl["features"] if item["id"] == "f_F2") self.assertEqual(feature["atomic_id"], "revolve_add") self.assertNotIn("result_mode", feature["params"]) def test_explicit_surface_body_lowers_to_the_surface_revolve_contract(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0078/00784880.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00784880"), {}) self.assertEqual(result.status, "converted_complete") feature = next(item for item in result.cdsl["features"] if item["id"] == "f_F3") self.assertEqual(feature["atomic_id"], "revolve_surface") self.assertNotIn("result_mode", feature["params"]) def test_mixed_extrude_lowers_selected_circular_surface_wires(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0071/00710855.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00710855"), {}) self.assertEqual(result.status, "converted_complete") features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F1_surface"]["atomic_id"], "extrude_surface") self.assertEqual(features["f_F1_surface"]["params"], { "distance_mm": 63.5, "reverse": False, "reverse_distance_mm": 63.5, }) self.assertEqual(features["f_F5_surface"]["atomic_id"], "extrude_surface") sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} radii = [ contour["segments"][0]["radius_mm"] for contour in sketches["sketch_F0__f_F1_surface"]["profile"]["contours"] ] self.assertEqual(radii, [19.0, 16.0]) profile = sketches[features["f_F5"]["sketch_id"]]["profile"] self.assertEqual(profile["type"], "analytic_contours") self.assertEqual( [(item["role"], item["segments"][0]["radius_mm"]) for item in profile["contours"]], [("outer", 25.5), ("inner", 19.0)], ) def test_mixed_extrude_preserves_prefix_when_cap_edge_chamfer_query_is_deferred(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0071/00710855.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00710855"), {}) with tempfile.TemporaryDirectory() as tmp: from cadfs_to_cdsl.rebuild import rebuild_candidate rebuilt = rebuild_candidate(result.cdsl, Path(tmp) / "rebuilt.step") self.assertEqual(rebuilt["status"], "rebuild_failed") self.assertEqual(rebuilt["error"]["message"], "f_F10: selector_query_unsupported during incremental replay") self.assertEqual(rebuilt["last_executable_prefix"]["failed_feature_id"], "f_F10") self.assertEqual(rebuilt["last_executable_prefix"]["last_feature_id"], "f_F9") def test_fit_spline_loft_lowers_to_executable_loft_add(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0061/00612529.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00612529"), {}) self.assertIsNotNone(result.cdsl) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F3"]["atomic_id"], "loft_add") self.assertEqual(features["f_F3"]["params"]["profile_sketch_ids"], ["sketch_F2", "sketch_F0"]) self.assertEqual(features["f_F4"]["atomic_id"], "pattern_mirror") self.assertEqual(features["f_F4"]["params"]["source_feature_ids"], ["f_F3"]) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertEqual(sketches["sketch_F0"]["profile"]["contours"][0]["segments"][0]["type"], "bspline") self.assertNotIn("loft", {item.get("operation") for item in result.diagnostics}) def test_fit_spline_loft_candidate_rebuilds(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0061/00612529.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00612529"), {}) with tempfile.TemporaryDirectory() as tmp: from cadfs_to_cdsl.rebuild import rebuild_candidate rebuilt = rebuild_candidate(result.cdsl, Path(tmp) / "rebuilt.step") self.assertEqual(rebuilt["status"], "rebuilt") self.assertGreater(rebuilt["result"]["volume_mm3"], 0) def test_closed_fit_splines_lower_to_periodic_contours_and_join_split_imprints(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0061/00612529.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00612529"), {}) self.assertEqual(result.status, "converted_complete") self.assertNotIn("F8", {item.get("feature_id") for item in result.diagnostics}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} for sketch_id in ("sketch_F0", "sketch_F2", "sketch_F5", "sketch_F6"): segment = sketches[sketch_id]["profile"]["contours"][0]["segments"][0] self.assertTrue(segment["periodic"]) self.assertEqual(segment["parameterization"], "centripetal") features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F8"]["sketch_id"], "sketch_F6") def test_open_fit_spline_reversal_preserves_parameter_and_tangent_semantics(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0028/00287955.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00287955"), {}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} spline = sketches["sketch_F13__f_F14"]["profile"]["contours"][0]["segments"][1] source_points = [[33.77, 39.06], [38.2, 35.02], [36.58, 30.72], [33.77, 28.66]] source_parameters = [0.0] for start, end in zip(source_points, source_points[1:]): source_parameters.append(source_parameters[-1] + math.sqrt(math.dist(start, end))) source_parameters = [value / source_parameters[-1] for value in source_parameters] self.assertEqual(spline["points"], list(reversed(source_points))) self.assertEqual(spline["start_tangent"], [11.58, -1.2]) self.assertEqual(spline["end_tangent"], [-14.95, 1.46]) self.assertEqual( spline["parameters"], [source_parameters[-1] - value for value in reversed(source_parameters)], ) def test_draft_and_boolean_bodies_preserve_explicit_source_body_selection(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0083/00835610.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00835610"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F1"]["params"]["draft"], {"angle_deg": 49.0, "pull_direction": True}) self.assertEqual(features["f_F3"]["sketch_id"], "sketch_F0__f_F3") self.assertEqual(features["f_F3"]["params"]["draft"], {"angle_deg": 49.0, "pull_direction": True}) self.assertEqual(features["f_F4"]["atomic_id"], "boolean_bodies") self.assertEqual(features["f_F4"]["params"], { "operation": "subtract", "target_feature_ids": ["f_F3"], "tool_feature_ids": ["f_F2"], "keep_tools": False, }) self.assertEqual(features["f_F8"]["atomic_id"], "revolve_add") self.assertNotIn("result_mode", features["f_F8"]["params"]) def test_drafted_cap_face_profile_executes_from_a_builder_proven_boolean_successor(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0083/00835610.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00835610"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(result.status, "converted_complete") cap_extrude = features["f_F5"] self.assertEqual(cap_extrude["atomic_id"], "extrude_from_face") self.assertNotIn("sketch_id", cap_extrude) selector = cap_extrude["selectors"][0] self.assertEqual({key: selector[key] for key in ( "kind", "owner_feature_id", "output_role", "source", "confidence", )}, { "kind": "face", "owner_feature_id": "f_F3", "output_role": "extrude.start", "source": "runtime_snapshot", "confidence": 1.0, }) self.assertNotIn("selector_intent_version", selector) self.assertEqual(selector["selector_intent"]["query_family"], "CAP_FACE") from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(result.cdsl, Path(directory) / "drafted-cap-face.step") resolution = next(item for item in rebuilt["selector_resolution"] if item["feature_id"] == "f_F5") self.assertEqual(resolution["status"], "resolved") self.assertEqual(resolution["selected"]["owner_feature_ids"], ["f_F3"]) self.assertEqual(resolution["selected"]["output_roles"], ["extrude.start"]) self.assertIn("f_F5", [item["feature_id"] for item in rebuilt["feature_results"]]) def test_drafted_cap_face_with_an_inner_loop_remains_an_explicit_capability_gap(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0026/00268467.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00268467"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertNotIn("f_F2", features) diagnostics = [item for item in result.diagnostics if item.get("feature_id") == "F2"] self.assertEqual(len(diagnostics), 1) self.assertEqual(diagnostics[0]["capability"], "extrude_profile_topology:cap_face") def test_nested_cap_edge_union_preserves_outer_profile_and_runtime_prefix(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0095/00950564.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00950564"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F3"]["sketch_id"], "sketch_F2") self.assertEqual(features["f_F5"]["sketch_id"], "sketch_F4") # F12's direct SWEPT_BODY(F1) names the one physical body after its # additive and dress-up successors. The lowering must retain that # proven successor, never substitute an implicit active aggregate. self.assertEqual(features["f_F12"]["params"]["source_feature_ids"], ["f_F11"]) self.assertIn("f_F11", features["f_F12"]["depends_on"]) from engine.cdsl_engine.runtime import analyze_cdsl f12_analysis = next(item for item in analyze_cdsl(result.cdsl).as_dict()["feature_results"] if item["feature_id"] == "f_F12") self.assertEqual(f12_analysis["resolved_status"], "executable") self.assertFalse(any(item["code"] == "body_source_unavailable" for item in f12_analysis["blockers"])) # Later chamfers have a separate selector gap. The retained prefix # proves the two CAP_EDGE profile unions themselves execute through # their dependent extrusions. prefix = deepcopy(result.cdsl) prefix["features"] = [item for item in prefix["features"] if item["id"] not in {"f_F10", "f_F11", "f_F12"}] from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(prefix, Path(directory) / "cap-edge-union-prefix.step") self.assertFalse(rebuilt["runtime_diagnostics"]) self.assertEqual( [item["feature_id"] for item in rebuilt["feature_results"]], ["f_F1", "f_F3", "f_F5", "f_F7", "f_F9"], ) def test_two_sided_blind_extrude_records_physical_cap_workplanes(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0024/00247322.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00247322"), {}) # The CAP_FACE(F4, isStart:true) workplane is the blind cap opposite # F4's primary direction, not the source sketch plane. F5 preserves # that cap's exact F4 ownership, so its CAP_EDGE can form F7's hole. self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertEqual(sketches["sketch_F3"]["workplane"]["origin_mm"], [0.0, 0.0, 40.0]) self.assertEqual(sketches["sketch_F6"]["workplane"]["origin_mm"], [0.0, 0.0, 40.3]) self.assertEqual(sketches["sketch_F6"]["workplane"]["normal"], [0.0, 0.0, 1.0]) self.assertEqual(sketches["sketch_F8"]["workplane"]["origin_mm"], [0.0, 0.0, 41.8]) self.assertEqual(sketches["sketch_F10"]["workplane"]["origin_mm"], [0.0, 0.0, 41.8]) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F7"]["selectors"][0]["geometry"], { "normal": [0.0, 0.0, 1.0], "plane_offset_mm": 40.3, }) # F9 rotates F4 only after F5/F7 have consumed it. It cannot be baked # into the earlier F4 sketch. The CAP_EDGE geometry is preserved for # diagnostics, but no source-qualified cap-edge lineage exists for # this two-sided profile contract. prefix = deepcopy(result.cdsl) prefix["features"] = [ item for item in prefix["features"] if item["id"] in {"f_F1", "f_F2", "f_F4", "f_F5", "f_F7"} ] with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_candidate(prefix, Path(directory) / "two-sided-cap-prefix.step") self.assertEqual(rebuilt["status"], "rebuild_failed") self.assertEqual(rebuilt["error"]["message"], "f_F7: selector_query_unsupported during incremental replay") self.assertEqual(rebuilt["last_executable_prefix"]["last_feature_id"], "f_F5") from engine.cdsl_engine.runtime import analyze_cdsl f9 = next(item for item in analyze_cdsl(result.cdsl).as_dict()["feature_results"] if item["feature_id"] == "f_F9") self.assertIn("body_source_unavailable", [item["code"] for item in f9["blockers"]]) def test_cap_face_profile_executes_from_a_builder_proven_dressup_successor(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0001/00016195.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00016195"), {}) self.assertEqual(result.status, "converted_complete") feature = next(item for item in result.cdsl["features"] if item["id"] == "f_F3") self.assertEqual(feature["atomic_id"], "extrude_from_face") self.assertNotIn("sketch_id", feature) from engine.cdsl_engine.runtime import rebuild_cdsl with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_cdsl(result.cdsl, Path(directory) / "cap-face.step") resolution = next(item for item in rebuilt["selector_resolution"] if item["feature_id"] == "f_F3") self.assertEqual(resolution["status"], "resolved") self.assertEqual(resolution["selected"]["owner_feature_ids"], ["f_F1"]) self.assertEqual(resolution["selected"]["output_roles"], ["extrude.end"]) def test_transformed_cap_face_uses_its_attachment_plane_origin(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0083/00835610.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00835610"), {}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} plane = sketches["sketch_F14"]["workplane"] self.assertAlmostEqual(plane["origin_mm"][0], 0.0) self.assertAlmostEqual(plane["origin_mm"][1], 0.0) self.assertAlmostEqual(plane["origin_mm"][2], -24.08) self.assertAlmostEqual(plane["normal"][0], 0.0) self.assertAlmostEqual(plane["normal"][1], 0.0) self.assertAlmostEqual(plane["normal"][2], 1.0) def test_chamfer_tangent_propagation_lowers_to_engine_param(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"), {}) chamfer = next(item for item in result.cdsl["features"] if item["id"] == "f_F4") self.assertTrue(chamfer["params"]["tangent_propagation"]) def test_imprint_profile_query_selects_one_shared_edge_region(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0003/00035682.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00035682"), {}) revolve = next(item for item in result.cdsl["features"] if item["id"] == "f_F1") self.assertEqual(revolve["sketch_id"], "sketch_F0__f_F1") selected = next(item for item in result.cdsl["geometry"]["sketches"] if item["id"] == revolve["sketch_id"]) self.assertEqual(len(selected["profile"]["contours"]), 1) x_coordinates = {point[0] for segment in selected["profile"]["contours"][0]["segments"] for point in (segment["start"], segment["end"])} self.assertEqual(x_coordinates, {11.68, 12.05}) def test_line_point_plane_uses_the_reference_line_as_its_normal(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0003/00035682.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00035682"), {}) self.assertEqual(result.status, "converted_complete") features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F5"]["atomic_id"], "reference_plane") self.assertEqual(features["f_F8"]["atomic_id"], "reference_plane") self.assertEqual(features["f_F7"]["atomic_id"], "extrude_cut_blind") self.assertEqual(features["f_F10"]["atomic_id"], "extrude_cut_blind") sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} length = math.hypot(10.44, 6.03) for actual, expected in zip(sketches["sketch_F6"]["workplane"]["normal"], [-10.44 / length, 6.03 / length, 0.0]): self.assertAlmostEqual(actual, expected) for actual, expected in zip(sketches["sketch_F6"]["workplane"]["x_dir"], [-6.03 / length, -10.44 / length, 0.0]): self.assertAlmostEqual(actual, expected) for actual, expected in zip(sketches["sketch_F9"]["workplane"]["normal"], [10.44 / length, 6.03 / length, 0.0]): self.assertAlmostEqual(actual, expected) for actual, expected in zip(sketches["sketch_F9"]["workplane"]["x_dir"], [-6.03 / length, 10.44 / length, 0.0]): self.assertAlmostEqual(actual, expected) def test_revolved_swept_face_lowers_to_an_annular_profile(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0005/00054089.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00054089"), {}) self.assertEqual(result.status, "converted_complete") features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F5"]["atomic_id"], "extrude_add_blind") sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} profile = sketches["sketch_F4"]["profile"] self.assertEqual(profile["type"], "analytic_contours") radii = {contour["role"]: contour["segments"][0]["radius_mm"] for contour in profile["contours"]} self.assertEqual(radii, {"outer": 18.0, "inner": 14.0}) def test_full_revolve_planar_swept_face_lowers_as_a_mirror_plane(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0000/00000385.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") source = feature.read_text(encoding="utf-8") result = lower_model(parse_featurescript(source, "00000385"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F5"]["atomic_id"], "pattern_mirror") mirror_plane = features["f_F5_plane"]["params"]["plane"] self.assertEqual(mirror_plane["origin_mm"], [0.0, 0.0, 0.0]) self.assertEqual(mirror_plane["x_dir"], [1.0, 0.0, 0.0]) self.assertEqual(mirror_plane["normal"], [0.0, 0.0, 1.0]) self.assertFalse([item for item in result.diagnostics if item.get("feature_id") == "F5"]) boolean = features["f_F6"] self.assertEqual(boolean["atomic_id"], "boolean_bodies") self.assertEqual(boolean["params"], { "operation": "union", "target_feature_ids": ["f_F1"], "keep_tools": False, "tool_pattern_instance_refs": [{ "pattern_feature_id": "f_F5", "source_feature_id": "f_F1", "instance_index": 1, }], }) self.assertFalse([item for item in result.diagnostics if item.get("feature_id") == "F6"]) with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_candidate(result.cdsl, Path(directory) / "rebuild.step") self.assertEqual(rebuilt["status"], "rebuilt") mirror = next(item for item in rebuilt["result"]["feature_results"] if item["feature_id"] == "f_F5") self.assertEqual(mirror["status"], "executed") boolean_result = next(item for item in rebuilt["result"]["feature_results"] if item["feature_id"] == "f_F6") self.assertEqual(boolean_result["status"], "executed") partial = source.replace("RevolveType.FULL", "RevolveType.PARTIAL", 1) rejected = lower_model(parse_featurescript(partial, "partial-revolve-mirror-plane"), {}) self.assertNotIn("f_F5", {item["id"] for item in rejected.cdsl["features"]}) self.assertEqual( [item for item in rejected.diagnostics if item.get("feature_id") == "F5"], [{ "code": "feature_deferred", "feature_id": "F5", "operation": "mirror", "message": "mirror plane is not a default or reference plane", }], ) def test_targetless_union_partitions_direct_body_queries_in_source_order(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0029/00293508.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(encoding="utf-8"), "00293508"), {}) self.assertEqual(result.status, "converted_complete") boolean = next(item for item in result.cdsl["features"] if item["id"] == "f_F4") self.assertEqual(boolean["atomic_id"], "boolean_bodies") self.assertEqual(boolean["params"], { "operation": "union", "target_feature_ids": ["f_F1"], "tool_feature_ids": ["f_F3"], "keep_tools": False, }) with tempfile.TemporaryDirectory() as directory: rebuilt = rebuild_candidate(result.cdsl, Path(directory) / "rebuild.step") self.assertEqual(rebuilt["status"], "rebuilt") execution = next(item for item in rebuilt["result"]["feature_results"] if item["feature_id"] == "f_F4") self.assertEqual(execution["status"], "executed") def test_intersect_partition_profile_retains_exact_planar_imprint_evidence(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0083/00835610.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00835610"), {}) self.assertEqual(result.status, "converted_complete") self.assertFalse([item for item in result.diagnostics if item.get("feature_id") == "F5"]) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F5"]["atomic_id"], "extrude_from_face") sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} first = sketches[features["f_F15"]["sketch_id"]]["profile"] second = sketches[features["f_F16"]["sketch_id"]]["profile"] self.assertEqual(first["type"], "planar_imprint") self.assertEqual(second["type"], "planar_imprint") self.assertEqual( first["selections"], [ {"source_entity_id": "E11", "face_side": 1.0, "fragment": {"anchor_entity_id": "E15", "side": -1.0, "intersection_index": 0}}, {"source_entity_id": "E11", "face_side": -1.0, "fragment": {"anchor_entity_id": "E15", "side": -1.0, "intersection_index": 0}}, ], ) self.assertEqual({item["id"] for item in first["source_entities"]}, {"E11", "E13", "E14", "E15"}) self.assertEqual( [selection["fragment"]["anchor_entity_id"] for selection in second["selections"]], ["E14", "E14"], ) def test_direct_imprint_profile_preserves_selector_intent_and_f1_checkpoint(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0035/00354246.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00354246"), {}) self.assertEqual(result.status, "converted_complete") features = {item["id"]: item for item in result.cdsl["features"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} profile = sketches[features["f_F1"]["sketch_id"]]["profile"] self.assertEqual(profile["type"], "planar_imprint") self.assertEqual(profile["selections"], [ {"source_entity_id": "E6.MirrorCS", "face_side": -1.0}, {"source_entity_id": "E0.MirrorCS", "face_side": 1.0}, ]) selectors = features["f_F2"]["selectors"] self.assertEqual(len(selectors), 7) self.assertTrue(all( selector["selector_intent"]["query_family"] == "SWEPT_FACE" and selector["selector_intent"]["derivation_policy"] == { "allowed": ["continuation"], "multiplicity": "none", } for selector in selectors )) self.assertTrue(any("geometry" not in selector for selector in selectors)) with tempfile.TemporaryDirectory() as directory: rebuilt = Path(directory) / "rebuild.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], "f_F2: selector_query_unsupported during incremental replay") self.assertTrue(rebuilt.exists()) self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F1") def test_direct_translation_transform_updates_the_source_revolve(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"), {}) self.assertNotIn("F10", {item.get("feature_id") for item in result.diagnostics}) features = {item["id"]: item for item in result.cdsl["features"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertEqual(features["f_F9"]["params"]["result_mode"], "new_body") self.assertEqual(sketches[features["f_F9"]["sketch_id"]]["workplane"]["origin_mm"], [77.16, -11.67, -63.0]) for actual, expected in zip(features["f_F9"]["params"]["axis"]["origin_mm"], [0.13, -11.67, 56.11]): self.assertAlmostEqual(actual, expected) def test_cap_face_workplane_uses_the_physical_cap_normal(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"), {}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertEqual(sketches["sketch_F2"]["workplane"]["origin_mm"], [0.0, 25.4, 0.0]) self.assertEqual(sketches["sketch_F2"]["workplane"]["normal"], [0.0, 1.0, 0.0]) self.assertEqual(sketches["sketch_F6"]["workplane"]["origin_mm"], [0.0, 0.0, 0.0]) self.assertEqual(sketches["sketch_F6"]["workplane"]["normal"], [0.0, -1.0, 0.0]) def test_nested_circle_imprint_selects_its_bounded_annulus(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"), {}) features = {item["id"]: item for item in result.cdsl["features"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} profile = sketches[features["f_F7"]["sketch_id"]]["profile"] self.assertEqual(profile["type"], "analytic_contours") self.assertEqual( [(item["role"], item["segments"][0]["radius_mm"]) for item in profile["contours"]], [("outer", 4.48), ("inner", 2.36)], ) def test_ellipse_profiles_unblock_the_00287955_feature_chain(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0028/00287955.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00287955"), {}) features = {item["id"] for item in result.cdsl["features"]} feature_by_id = {item["id"]: item for item in result.cdsl["features"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertTrue({"f_F3", "f_F5", "f_F6", "f_F11"}.issubset(features)) self.assertEqual(feature_by_id["f_F9"]["atomic_id"], "extrude_add_blind") self.assertNotIn("selectors", feature_by_id["f_F9"]) mid_plane = feature_by_id["f_F12"]["params"]["plane"] self.assertAlmostEqual(mid_plane["origin_mm"][0], -18.67, places=5) self.assertAlmostEqual(mid_plane["normal"][0], 1.0, places=5) self.assertAlmostEqual(mid_plane["normal"][1], 0.0, places=3) axis = feature_by_id["f_F14"]["params"]["axis"] self.assertAlmostEqual(axis["origin_mm"][0], -18.67, delta=0.01) self.assertAlmostEqual(axis["origin_mm"][1], 33.77, delta=0.01) for sketch_id in ("sketch_F2", "sketch_F4", "sketch_F7", "sketch_F8"): segment = sketches[sketch_id]["profile"]["contours"][0]["segments"][0] self.assertEqual(segment["type"], "ellipse") self.assertNotIn("sketch_deferred", {item["code"] for item in result.diagnostics}) def test_circular_pattern_lowers_to_existing_engine_contract(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0042/00423838.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00423838"), {}) self.assertIsNotNone(result.cdsl) features = {item["id"]: item for item in result.cdsl["features"]} pattern = features["f_F4"] self.assertEqual(pattern["atomic_id"], "pattern_circular") self.assertEqual(pattern["params"]["source_feature_ids"], ["f_F1"]) self.assertEqual(pattern["params"]["pattern_count"], 6) self.assertEqual(pattern["params"]["sweep_angle_deg"], 360.0) self.assertEqual(pattern["params"]["axis"]["direction"], [0.0, 0.0, -1.0]) self.assertNotIn("F2", {item.get("feature_id") for item in result.diagnostics}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} self.assertNotEqual(sketches[features["f_F1"]["sketch_id"]]["workplane"]["normal"], [0.0, 0.0, 1.0]) self.assertNotIn("circularPattern", {item.get("operation") for item in result.diagnostics}) def test_static_integral_round_pattern_count_is_lowered_without_guessing_rounding_mode(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" for sample_id, feature_id, count in ( ("00003011", "f_F5", 8), ("00039410", "f_F6", 9), ): with self.subTest(sample_id=sample_id): feature = root / "featurescript_rp" / sample_id[:4] / f"{sample_id}.txt" result = lower_model(parse_featurescript(feature.read_text(), sample_id), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features[feature_id]["atomic_id"], "pattern_circular") self.assertEqual(features[feature_id]["params"]["pattern_count"], count) self.assertNotIn(feature_id.removeprefix("f_"), { item.get("feature_id") for item in result.diagnostics }) integral_round = Call("round", [8.0]) fractional_round = Call("round", [8.5]) self.assertEqual(_number(integral_round), 8.0) with self.assertRaisesRegex(ValueError, "not a constant number"): _number(fractional_round) def test_two_point_fit_spline_requires_endpoint_derivatives_and_lowers_as_bspline(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" source_path = root / "featurescript_rp/0003/00039410.txt" source = source_path.read_text(encoding="utf-8") result = lower_model(parse_featurescript(source, "00039410"), {}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} profile = sketches["sketch_F4"]["profile"] splines = [ segment for contour in profile["contours"] for segment in contour["segments"] if segment["type"] == "bspline" ] self.assertEqual(len(splines), 2) self.assertTrue(all(len(segment["points"]) == 2 for segment in splines)) self.assertTrue(all("start_tangent" in segment and "end_tangent" in segment for segment in splines)) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F6"]["params"]["pattern_count"], 9) self.assertNotIn("F4", {item.get("feature_id") for item in result.diagnostics}) self.assertNotIn("F6", {item.get("feature_id") for item in result.diagnostics}) missing_tangent = source.replace(', "endDerivative": vector(4.02, 9.38) * mm', "", 1) rejected = lower_model(parse_featurescript(missing_tangent, "two-point-spline-without-tangent"), {}) self.assertIn({ "code": "sketch_deferred", "feature_id": "F4", "message": "two-point fit spline requires both endpoint derivatives", }, rejected.diagnostics) coincident = source.replace('v(0, 30) * mm', 'v(-1, 19.97) * mm', 1) rejected = lower_model(parse_featurescript(coincident, "two-point-spline-with-coincident-endpoints"), {}) self.assertIn({ "code": "sketch_deferred", "feature_id": "F4", "message": "two-point fit spline endpoints must be distinct", }, rejected.diagnostics) def test_opposed_circle_regions_lower_to_their_union_disk(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0042/00423838.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00423838"), {}) features = {item["id"]: item for item in result.cdsl["features"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} profile = sketches[features["f_F6"]["sketch_id"]]["profile"] self.assertEqual(profile["type"], "circle") self.assertEqual(profile["radius_mm"], 30.0) def test_reference_plane_variants_lower_to_explicit_frames(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = { "00159804": {"F3", "F5"}, "00192744": {"F3"}, "00212904": {"F3"}, "00542223": {"F3"}, } for sample_id, expected in cases.items(): 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), {}) features = {item["name"]: item for item in result.cdsl["features"]} for feature_id in expected: plane = features[feature_id] self.assertEqual(plane["atomic_id"], "reference_plane") self.assertEqual(set(plane["params"]["plane"]), {"origin_mm", "x_dir", "normal"}) diagnostics = [item for item in result.diagnostics if item.get("operation") == "cPlane"] self.assertFalse(diagnostics) def test_curve_point_plane_uses_an_explicit_bspline_endpoint_tangent(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0082/00827798.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00827798"), {}) plane = next(item for item in result.cdsl["features"] if item["id"] == "f_F1") self.assertEqual(plane["atomic_id"], "reference_plane") self.assertFalse(any( item.get("operation") == "cPlane" and item.get("feature_id") == "F1" for item in result.diagnostics )) expected = [107.86, 0.0, -176.04] magnitude = math.sqrt(sum(value * value for value in expected)) for actual, value in zip(plane["params"]["plane"]["normal"], expected): self.assertAlmostEqual(actual, value / magnitude) second_feature = root / "featurescript_rp/0084/00845891.txt" if second_feature.exists(): second = lower_model(parse_featurescript(second_feature.read_text(), "00845891"), {}) self.assertEqual( next(item for item in second.cdsl["features"] if item["id"] == "f_F3")["atomic_id"], "reference_plane", ) self.assertFalse(any( item.get("operation") == "cPlane" and item.get("feature_id") == "F3" for item in second.diagnostics )) without_end_derivative = feature.read_text().replace( ', "endDerivative": vector(107.86, -176.04) * mm', "", 1, ) rejected = lower_model(parse_featurescript(without_end_derivative, "00827798-no-end-derivative"), {}) self.assertIn({ "code": "unsupported_engine_capability", "capability": "reference_plane:curve_point", "feature_id": "F1", "operation": "cPlane", "message": "CURVE_POINT B-spline endpoint has no exported tangent", }, rejected.diagnostics) def test_curve_endpoint_tangent_uses_arc_orientation_without_a_chord_fallback(self): arc = { "type": "arc", "start": [1.0, 0.0], "end": [0.0, 1.0], "center": [0.0, 0.0], "clockwise": False, } self.assertEqual(_curve_endpoint_tangent(arc, "start"), [0.0, 1.0]) self.assertEqual(_curve_endpoint_tangent(arc, "end"), [-1.0, 0.0]) with self.assertRaisesRegex(UnsupportedCapability, "direct source-curve endpoint"): _curve_endpoint_tangent(arc, "internal") def test_curve_point_plane_uses_exact_bspline_interpolation_vertex_tangents(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = { "00456498": ("f_F1", "F1", [141.23, 0.0, -13.99]), "00812557": ("f_F2", "F2", [0.0, 191.15, -139.74]), } for sample_id, (cdsl_feature_id, source_feature_id, expected) in cases.items(): with self.subTest(sample_id=sample_id): source = root / "featurescript_rp" / sample_id[:4] / f"{sample_id}.txt" if not source.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(source.read_text(), sample_id), {}) plane = next(item for item in result.cdsl["features"] if item["id"] == cdsl_feature_id) self.assertEqual(plane["atomic_id"], "reference_plane") magnitude = math.sqrt(sum(value * value for value in expected)) for actual, value in zip(plane["params"]["plane"]["normal"], expected): self.assertAlmostEqual(actual, value / magnitude, places=8) self.assertFalse(any( item.get("operation") == "cPlane" and item.get("feature_id") == source_feature_id for item in result.diagnostics )) no_derivatives = (root / "featurescript_rp/0045/00456498.txt").read_text().replace( ', "startDerivative": vector(0, 64.52) * mm, "endDerivative": vector(141.23, -13.99) * mm', "", 1, ) rejected = lower_model(parse_featurescript(no_derivatives, "00456498-no-derivatives"), {}) self.assertIn({ "code": "unsupported_engine_capability", "capability": "reference_plane:curve_point", "feature_id": "F1", "operation": "cPlane", "message": "CURVE_POINT B-spline interpolation point has no complete source interpolation data", }, rejected.diagnostics) derived = (root / "featurescript_rp/0045/00456498.txt").read_text().replace( '"E0.2.internal"', '"E0.2.endSnap0"', 1, ) rejected_derived = lower_model(parse_featurescript(derived, "00456498-derived-vertex"), {}) self.assertIn({ "code": "unsupported_engine_capability", "capability": "reference_plane:curve_point", "feature_id": "F1", "operation": "cPlane", "message": "CURVE_POINT point must name a direct source-curve endpoint or B-spline interpolation vertex", }, rejected_derived.diagnostics) def test_curve_point_plane_uses_a_direct_arc_endpoint_tangent(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0005/00057273.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") source = feature.read_text().replace( 'EDGE,"E1"', 'EDGE,"E0"', 1, ).replace( 'VERTEX,"E1.end"', 'VERTEX,"E0.end"', 1, ) result = lower_model(parse_featurescript(source, "00057273-arc-curve-point"), {}) plane = next(item for item in result.cdsl["features"] if item["id"] == "f_F1") self.assertEqual(plane["atomic_id"], "reference_plane") self.assertEqual(plane["params"]["plane"]["origin_mm"], [-24.6, 0.0, 0.0]) self.assertEqual(plane["params"]["plane"]["normal"], [0.0, -1.0, 0.0]) self.assertFalse(any( item.get("operation") == "cPlane" and item.get("feature_id") == "F1" for item in result.diagnostics )) def test_offset_reference_plane_honors_opposite_direction_without_reversing_its_frame(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0077/00777619.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") source = feature.read_text() opposite = lower_model(parse_featurescript(source, "00777619"), {}) opposite_plane = next(item for item in opposite.cdsl["features"] if item["id"] == "f_F2")["params"]["plane"] self.assertEqual(opposite_plane, { "origin_mm": [-76.2, 0.0, 0.0], "x_dir": [0.0, 1.0, 0.0], "normal": [1.0, 0.0, 0.0], }) default = lower_model(parse_featurescript(source.replace('"oppositeDirection" : true, ', ""), "00777619-default"), {}) default_plane = next(item for item in default.cdsl["features"] if item["id"] == "f_F2")["params"]["plane"] self.assertEqual(default_plane, { "origin_mm": [76.2, 0.0, 0.0], "x_dir": [0.0, 1.0, 0.0], "normal": [1.0, 0.0, 0.0], }) def test_shell_preserves_pattern_copy_cap_faces_and_offset_edge_fillet(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"), {}) features = {item["id"]: item for item in result.cdsl["features"]} sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} shell = features["f_F7"] fillet = features["f_F8"] self.assertEqual(sketches["sketch_F4"]["workplane"]["origin_mm"], [0.0, 0.0, -50.0]) self.assertEqual(features["f_F5"]["params"]["path"]["segment"]["points"][0], [-40.0, -50.0]) self.assertEqual(features["f_F5"]["params"]["path"]["segment"]["start_tangent"], [27.94, 92.49]) self.assertEqual(shell["selectors"][1]["geometry"], { "normal": [0.0, 0.0, 1.0], "plane_offset_mm": -50.0, "center_mm": [0.0, -40.0, -50.0], "minimum_area_mm2": 481.0563750809371, }) expected_centers = [[34.64101615137755, 20.0, -50.0], [0.0, -40.0, -50.0], [-34.64101615137754, 20.0, -50.0]] for center, expected in zip([selector["geometry"]["center_mm"] for selector in shell["selectors"][:3]], expected_centers): for value, target in zip(center, expected): self.assertAlmostEqual(value, target) self.assertEqual(shell["selectors"][3]["geometry"]["center_mm"], [0.0, 0.0, 50.0]) self.assertEqual(shell["atomic_id"], "shell") self.assertEqual(len(shell["selectors"]), 4) self.assertEqual( [selector["owner_feature_id"] for selector in shell["selectors"][:3]], ["f_F6.c1.f_F5", "f_F5", "f_F6.c2.f_F5"], ) self.assertEqual(fillet["atomic_id"], "fillet") self.assertEqual(fillet["selectors"][0]["geometry"]["source_circle_radius_mm"], 17.5) self.assertEqual(shell["params"]["target_feature_id"], "f_F5") self.assertFalse(any( diagnostic.get("capability") == "shell_parts_body_source" for diagnostic in result.diagnostics )) self.assertNotIn("F8", {item.get("feature_id") for item in result.diagnostics}) def test_shell_resolves_direct_prism_swept_faces_through_kernel_lineage(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0059/00594348.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00594348"), {}) self.assertEqual(result.status, "converted_complete") shell_index = next(index for index, item in enumerate(result.cdsl["features"]) if item["id"] == "f_F2") shell = result.cdsl["features"][shell_index] self.assertEqual(shell["atomic_id"], "shell") self.assertEqual([item["owner_feature_id"] for item in shell["selectors"]], ["f_F1", "f_F1"]) self.assertTrue(all("geometry" not in item and "stable_id" not in item for item in shell["selectors"])) self.assertTrue(all(item["selector_intent"]["query_family"] == "SWEPT_FACE" for item in shell["selectors"])) self.assertTrue(all(item["selector_intent"]["evidence"] == "kernel_history" for item in shell["selectors"])) self.assertTrue(all( item["selector_intent"]["derivation_policy"] == {"allowed": ["boundary"], "multiplicity": "one"} for item in shell["selectors"] )) with tempfile.TemporaryDirectory() as directory: outcome = rebuild_candidate(result.cdsl, Path(directory) / "swept-face-shell.step") self.assertEqual(outcome["status"], "rebuilt") resolutions = [ item for item in outcome["result"]["selector_resolution"] if item["feature_id"] == "f_F2" ] self.assertEqual(len(resolutions), 2) self.assertTrue(all(item["resolution_mode"] == "kernel_lineage" for item in resolutions)) self.assertTrue(all( item["evidence"]["relations"][0]["source_kind"] == "edge" and item["evidence"]["relations"][0]["result_kind"] == "face" for item in resolutions )) def test_shell_resolves_immediate_direct_prism_cap_faces_through_output_roles(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = (("00212904", "extrude.start"), ("00789939", "extrude.end")) for sample_id, output_role 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(encoding="utf-8"), sample_id), {}) self.assertEqual(result.status, "converted_complete") shell_index = next(index for index, item in enumerate(result.cdsl["features"]) if item["id"] == "f_F2") shell = result.cdsl["features"][shell_index] self.assertEqual(shell["atomic_id"], "shell") self.assertEqual(len(shell["selectors"]), 1) selector = shell["selectors"][0] self.assertEqual(selector["owner_feature_id"], "f_F1") self.assertEqual(selector["output_role"], output_role) self.assertEqual(selector["selector_intent"]["query_family"], "CAP_FACE") self.assertEqual(selector["selector_intent"]["evidence"], "operation_role") self.assertNotIn("stable_id", selector) self.assertNotIn("binding_feature_id", selector) self.assertNotIn("geometry", selector) prefix = deepcopy(result.cdsl) prefix["features"] = prefix["features"][:shell_index + 1] with tempfile.TemporaryDirectory() as directory: outcome = rebuild_candidate(prefix, Path(directory) / f"{sample_id}-cap-face-shell.step") self.assertEqual(outcome["status"], "rebuilt") resolution = next( item for item in outcome["result"]["selector_resolution"] if item["feature_id"] == "f_F2" ) self.assertEqual(resolution["status"], "resolved") self.assertEqual(resolution["resolution_mode"], "operation_role") self.assertEqual(resolution["selected"]["output_roles"], [output_role]) def test_shell_direct_prism_swept_face_rejects_unregistered_source_version(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0059/00594348.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") source = feature.read_text(encoding="utf-8").replace("FeatureScript 1511;", "FeatureScript 1793;", 1) result = lower_model(parse_featurescript(source, "00594348-version-1793"), {}) shell = next(item for item in result.cdsl["features"] if item["id"] == "f_F2") self.assertTrue(all( item["selector_intent"]["evidence"] == "feature_script_query" and item["selector_intent"]["derivation_policy"]["multiplicity"] == "none" for item in shell["selectors"] )) with tempfile.TemporaryDirectory() as directory: outcome = rebuild_candidate(result.cdsl, Path(directory) / "swept-face-shell-1793.step") self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], "f_F2: selector_query_unsupported during incremental replay") self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F1") def test_shell_direct_prism_swept_face_rejects_unregistered_standard_library_revision(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0059/00594348.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") source = feature.read_text(encoding="utf-8").replace( 'import(path : "onshape/std/geometry.fs", version : "1511.0");', 'import(path : "onshape/std/geometry.fs", version : "1512.0");', 1, ) result = lower_model(parse_featurescript(source, "00594348-library-1512"), {}) shell = next(item for item in result.cdsl["features"] if item["id"] == "f_F2") self.assertTrue(all( item["selector_intent"]["source_query"]["featurescript_version"] == "1511" and item["selector_intent"]["source_query"]["standard_library"] == "onshape/std/geometry.fs" and item["selector_intent"]["source_query"]["standard_library_version"] == "1512.0" for item in shell["selectors"] )) with tempfile.TemporaryDirectory() as directory: outcome = rebuild_candidate(result.cdsl, Path(directory) / "swept-face-shell-library-1512.step") self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], "f_F2: selector_query_unsupported during incremental replay") self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F1") def test_shell_offset_face_requires_true_dependency_cap_evidence(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0010/00107631.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") # Keep the same nested CAP_FACE outside a true-dependency relation. # It is source-profile evidence only and must not select an OFFSET_FACE. source = feature.read_text(encoding="utf-8").replace( 'TDD([makeQuery(id+"F1.opExtrude","CAP_FACE",FACE,{"disambiguationData":[OSD([subQ0])],"isStart":true})])', 'OSD([subQ0])', ) result = lower_model(parse_featurescript(source, "00107631-without-tdd"), {}) diagnostic = next(item for item in result.diagnostics if item.get("feature_id") == "F3") self.assertEqual(diagnostic["capability"], "shell_offset_face_selector") self.assertIn("true dependency", diagnostic["message"]) def test_shell_runtime_failure_exports_its_bound_executable_prefix(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0024/00248377.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00248377"), {}) self.assertEqual(result.status, "converted_complete") with tempfile.TemporaryDirectory() as directory: rebuilt = Path(directory) / "swept-face-shell-prefix.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertTrue(rebuilt.exists()) self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["type"], "ValueError") self.assertEqual(outcome["error"]["message"], "f_F5: selector_query_unsupported during incremental replay") self.assertIn("bound_cdsl", outcome) self.assertEqual(outcome["last_executable_prefix"]["failed_feature_id"], "f_F5") self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F4") self.assertEqual(outcome["last_executable_prefix"]["result"]["solid_count"], 1) def test_pattern_copy_intersection_query_preserves_its_prefix_without_instance_geometry_binding(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0042/00423838.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00423838"), {}) with tempfile.TemporaryDirectory() as directory: rebuilt = Path(directory) / "selector-prefix.step" outcome = rebuild_candidate(result.cdsl, rebuilt) self.assertTrue(rebuilt.exists()) self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], "f_F7: selector_query_unsupported during incremental replay") self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F6") reference = next(item for item in result.cdsl["features"] if item["id"] == "f_F7")["params"]["end_condition"]["reference"] self.assertEqual(reference["selector_intent"]["query_family"], "INTERSECT") self.assertEqual( [item["selector_intent"]["query_family"] for item in reference["intersection_of"][:2]], ["COPY", "COPY"], ) def test_shell_rejects_swept_faces_without_direct_linear_extrude_ownership(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" cases = (("00246716", "F7"), ("00051308", "F3")) for sample_id, shell_id 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), {}) diagnostic = next(item for item in result.diagnostics if item.get("feature_id") == shell_id) self.assertEqual(diagnostic["code"], "unsupported_engine_capability") self.assertEqual(diagnostic["capability"], "shell_face_selector") self.assertIn("direct blind/two-sided linear extrusion", diagnostic["message"]) def test_curve_point_plane_uses_its_projected_attachment_origin(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0019/00192744.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00192744"), {}) sketches = {item["id"]: item for item in result.cdsl["geometry"]["sketches"]} plane = sketches["sketch_F4"]["workplane"] self.assertEqual(plane["origin_mm"], [0.0, -2000.0, -4000.0]) self.assertAlmostEqual(_global(plane, [0.0, 8944.27])[1], -10000.0, places=2) self.assertAlmostEqual(_global(plane, [0.0, 8944.27])[2], 0.0, places=2) def test_delete_pattern_copies_lower_to_explicit_exclusions(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0019/00192744.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00192744"), {}) features = {item["id"]: item for item in result.cdsl["features"]} self.assertEqual(features["f_F6"]["params"]["excluded_instance_indices"], [2]) self.assertEqual(features["f_F11"]["params"]["excluded_instance_indices"], [2]) self.assertEqual(result.status, "converted_complete") self.assertFalse(result.diagnostics) self.assertEqual(features["f_F15"]["atomic_id"], "transform_bodies") self.assertEqual(features["f_F15"]["params"]["source_feature_ids"], ["f_F1", "f_F5"]) self.assertEqual(features["f_F15"]["params"]["pattern_instance_refs"], [ {"pattern_feature_id": "f_F6", "source_feature_id": "f_F5", "instance_index": 1}, {"pattern_feature_id": "f_F6", "source_feature_id": "f_F5", "instance_index": 3}, ]) def test_feature_face_profile_is_not_reused_as_original_sketch(self): source = SOURCE.replace('qSketchRegion(id + "F0", true)', 'makeQuery(id+"F1.opExtrude","CAP_FACE",FACE,{"isStart":false})') result = lower_model(parse_featurescript(source, "face-profile"), {}) self.assertIsNone(result.cdsl) self.assertEqual(result.diagnostics[0]["code"], "unsupported_engine_capability") self.assertIn("extrude_profile_topology:cap_face", result.diagnostics[0]["capability"]) def test_cap_face_selector_retains_versioned_provenance_intent(self): source = SOURCE.replace( "FeatureScript 1511;", 'FeatureScript 1511;\nimport(path : "onshape/std/geometry.fs", version : "1511.0");', 1, ).replace( '\n});\n', '\n extrude(context, id + "F2", {"entities":makeQuery(id + "F1.opExtrude", "CAP_FACE", FACE, {"isStart":false}), "depth":10 * mm});\n});\n', ) result = lower_model(parse_featurescript(source, "cap-intent"), {}) self.assertEqual(result.status, "converted_complete") selector = next(item for item in result.cdsl["features"] if item["id"] == "f_F2")["selectors"][0] self.assertEqual(selector["selector_intent"]["query_family"], "CAP_FACE") self.assertNotIn("selector_intent_version", selector) self.assertEqual(selector["selector_intent"]["source_query"]["featurescript_version"], "1511") self.assertEqual(selector["selector_intent"]["source_query"]["standard_library"], "onshape/std/geometry.fs") self.assertEqual(selector["selector_intent"]["source_query"]["standard_library_version"], "1511.0") self.assertEqual(selector["selector_intent"]["evidence"], "operation_role") from engine.cdsl_engine.semantic_validation import validate_semantic_cdsl self.assertTrue(validate_semantic_cdsl(result.cdsl)["future_rebuild_ready"]) def test_direct_boolean_intersection_lowering_keeps_two_source_contract(self): base = lower_model(parse_featurescript(SOURCE, "intersection-intent"), {}).cdsl sketch = base["geometry"]["sketches"][0] direct = {**base["features"][0], "id": "f_F2", "name": "F2"} feature_by_id = { "f_F1": base["features"][0], "f_F2": direct, "f_F3": { "id": "f_F3", "atomic_id": "boolean_bodies", "params": { "operation": "subtract", "target_feature_ids": ["f_F1"], "tool_feature_ids": ["f_F2"], "keep_tools": False, }, }, } cap = Call("makeQuery", ["F1.opExtrude", "CAP_FACE", "EntityType.FACE", {"isStart": False}]) source_edge = Call("sQuery", ["F0.wireOp", "EntityType.EDGE", "E0"]) swept = Call("makeQuery", [ "F2.opExtrude", "SWEPT_FACE", "EntityType.FACE", {"disambiguationData": [Call("OSD", [[source_edge]])]}, ]) query = Call("makeQuery", [ "F3.boolean.opBoolean", "INTERSECT", "EntityType.EDGE", {"derivedFrom": [cap, swept]}, ]) selector = _direct_boolean_intersection_selector( query, feature_by_id=feature_by_id, feature_frames={"F2": {"profile_source": "F0"}}, sketch_by_source={"F0": sketch}, sketches_by_id={sketch["id"]: sketch}, entity_by_sketch={"F0": {"E0": {"type": "circle", "center": [0, 0], "radius_mm": 9.53}}}, featurescript_version="1511", ) self.assertIsNotNone(selector) self.assertNotIn("stable_id", selector) intent = selector["selector_intent"] self.assertEqual(intent["derivation_policy"], {"allowed": ["intersection"], "multiplicity": "one"}) self.assertEqual(intent["intersection_sources"], [ {"query_family": "CAP_FACE", "owner_feature_id": "f_F1", "output_role": "extrude.end"}, {"query_family": "SWEPT_FACE", "owner_feature_id": "f_F2", "source_entity": {"sketch_id": "F0", "entity_id": "E0"}}, ]) def test_direct_primary_cut_intersection_requires_no_unverified_disambiguation(self): base = lower_model(parse_featurescript(SOURCE, "primary-intersection-intent"), {}).cdsl target = base["features"][0] target_sketch = base["geometry"]["sketches"][0] tool_sketch = deepcopy(target_sketch) tool_sketch.update({"id": "sketch_F2", "source_sketch_id": "F2"}) if tool_sketch["profile"].get("type") == "circle": tool_sketch["profile"]["source_entity_id"] = "E1" else: for contour in tool_sketch["profile"]["contours"]: for segment in contour["segments"]: segment["source_entity_id"] = "E1" tool = { "id": "f_F3", "atomic_id": "extrude_cut_blind", "sketch_id": "sketch_F2", "params": {"distance_mm": 10, "end_condition": {"type": "blind"}}, } cap = Call("makeQuery", ["F1.opExtrude", "CAP_FACE", "EntityType.FACE", {"isStart": False}]) tool_edge = Call("sQuery", ["F2.wireOp", "EntityType.EDGE", "E1"]) swept = Call("makeQuery", [ "F3.opExtrude", "SWEPT_FACE", "EntityType.FACE", {"disambiguationData": [Call("OSD", [[tool_edge]])]}, ]) query = Call("makeQuery", [ "F3.boolean.opBoolean", "INTERSECT", "EntityType.EDGE", {"derivedFrom": [cap, swept]}, ]) kwargs = { "feature_by_id": {"f_F1": target, "f_F3": tool}, "feature_frames": {"F3": {"profile_source": "F2"}}, "sketch_by_source": {"F2": tool_sketch}, "sketches_by_id": {tool_sketch["id"]: tool_sketch, target_sketch["id"]: target_sketch}, "entity_by_sketch": {"F2": {"E1": {"type": "circle", "center": [0, 0], "radius_mm": 9.53}}}, "previous": ["f_F1", "f_F3"], "featurescript_version": "1511", } selector = _direct_primary_cut_intersection_selector(query, **kwargs) self.assertIsNotNone(selector) self.assertEqual(selector["owner_feature_id"], "f_F3") self.assertEqual(selector["selector_intent"]["intersection_sources"][1], { "query_family": "SWEPT_FACE", "owner_feature_id": "f_F3", "source_entity": {"sketch_id": "F2", "entity_id": "E1"}, }) deferred = Call("makeQuery", [ "F3.boolean.opBoolean", "INTERSECT", "EntityType.EDGE", {"derivedFrom": [cap, swept], "disambiguationData": [Call("OD", [0.0])]}, ]) self.assertIsNone(_direct_primary_cut_intersection_selector(deferred, **kwargs)) def test_deferred_primary_intersect_keeps_the_convertible_f3_checkpoint(self): root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test" feature = root / "featurescript_rp/0002/00020311.txt" if not feature.exists(): self.skipTest("CADFS sample is not installed") result = lower_model(parse_featurescript(feature.read_text(), "00020311"), {}) f4 = next(item for item in result.cdsl["features"] if item["id"] == "f_F4") self.assertTrue(all( selector["kind"] == "edge" and selector["selector_intent"]["query_family"] == "INTERSECT" and selector["selector_intent"]["derivation_policy"]["multiplicity"] == "none" for selector in f4["selectors"] )) from engine.cdsl_engine.semantic_validation import validate_semantic_cdsl self.assertTrue(validate_semantic_cdsl(result.cdsl)["future_rebuild_ready"]) with tempfile.TemporaryDirectory() as directory: outcome = rebuild_candidate(result.cdsl, Path(directory) / "00020311.step") self.assertTrue((Path(directory) / "00020311.step").exists()) self.assertEqual(outcome["status"], "rebuild_failed") self.assertEqual(outcome["error"]["message"], "f_F4: selector_query_unsupported during incremental replay") self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F3") def test_conversion_writes_status_and_sidecars(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp); source = root / "00000173.txt"; source.write_text(SOURCE) sample = Sample("00000173", {"featurescript": str(source)}, {"featurescript": "x"}) status = convert_one(sample, root / "out", force=True) directory = root / "out/samples/00000173" self.assertEqual(status["conversion_status"], "converted_complete") for name in ("candidate.cdsl.json", "history.json", "diagnostics.json", "status.json"): self.assertTrue((directory / name).exists(), name) self.assertEqual(json.loads((directory / "candidate.cdsl.json").read_text())["part_id"], "00000173") def test_force_rebuild_refreshes_the_candidate_from_source(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp); source = root / "00000173.txt"; source.write_text(SOURCE) sample = Sample("00000173", {"featurescript": str(source)}, {"featurescript": "x"}) directory = root / "out/samples/00000173"; directory.mkdir(parents=True) (directory / "candidate.cdsl.json").write_text(json.dumps({"part_id": "stale"}), encoding="utf-8") (directory / "status.json").write_text(json.dumps({"sample_id": sample.sample_id}), encoding="utf-8") status = rebuild_one(sample, root / "out", force=True) self.assertEqual(status["rebuild_status"], "rebuilt") self.assertEqual(json.loads((directory / "candidate.cdsl.json").read_text())["part_id"], "00000173") if __name__ == "__main__": unittest.main()