038d38ed98
- 新增 loft、双向切除、through-all/up-to-next 等 CADFS lowering 与 engine 支持 - 支持多种 reference plane、B-spline profile 和 circular pattern replay - 保留 transform 历史,并烘焙安全的单源平移/旋转变换 - 改进 selector 绑定、拓扑快照和 pattern 变换处理 - 建立 17 个代表样本的转换、重建与比较回归工具链 - 补充 schema、author guidance、运行时和几何回归测试
62 lines
2.6 KiB
Python
62 lines
2.6 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from cadfs_to_cdsl.featurescript_lexer import lex
|
|
from cadfs_to_cdsl.featurescript_parser import parse_featurescript
|
|
from cadfs_to_cdsl.ir import Call
|
|
from cadfs_to_cdsl.query_parser import parse_query
|
|
from cadfs_to_cdsl.units import length_mm
|
|
|
|
|
|
SOURCE = r'''
|
|
FeatureScript 1511;
|
|
export const f = defineFeature(function(context, id, definition) {
|
|
{ var Q0; Q0=qCreatedBy(makeId("Top.planeOp"), FACE);
|
|
var sketch = newSketch(context, id + "F0", {"sketchPlane":qUnion([Q0])});
|
|
skCircle(sketch, "E0", {"center":v(0, 0) * mm, "radius":9.53 * mm}); skSolve(sketch); }
|
|
{ var Q0; Q0=qSketchRegion(id + "F0", true);
|
|
extrude(context, id + "F1", {"entities":qUnion([Q0]), "depth":120 * mm}); }
|
|
});
|
|
'''
|
|
|
|
TRANSFORM_SOURCE = SOURCE.replace(
|
|
'\n});\n',
|
|
'''
|
|
transform(context, id + "F2", {"entities":qCreatedBy(id + "F1", BODY), "transformType":TransformType.TRANSLATION_3D, "dx":10 * mm, "dy":0 * mm, "dz":0 * mm, "makeCopy":false});
|
|
});
|
|
''',
|
|
)
|
|
|
|
|
|
class ParserTests(unittest.TestCase):
|
|
def test_lexer_ignores_comments_and_preserves_lines(self):
|
|
tokens = lex('// a\nfoo(/*b*/"x")')
|
|
self.assertEqual([token.value for token in tokens[:-1]], ["foo", "(", '"x"', ")"])
|
|
self.assertEqual(tokens[0].line, 2)
|
|
|
|
def test_nested_feature_script(self):
|
|
model = parse_featurescript(SOURCE, "00000173")
|
|
self.assertEqual([step.feature_id for step in model.steps], ["F0", "F1"])
|
|
self.assertEqual(model.sketches[0].entities[0].operation, "skCircle")
|
|
self.assertIsInstance(model.features[0].params["entities"], Call)
|
|
|
|
def test_transform_is_preserved_as_a_feature(self):
|
|
model = parse_featurescript(TRANSFORM_SOURCE, "transform")
|
|
self.assertEqual([step.feature_id for step in model.steps], ["F0", "F1", "F2"])
|
|
self.assertEqual(model.features[-1].operation, "transform")
|
|
self.assertEqual(model.features[-1].params["transformType"], "TransformType.TRANSLATION_3D")
|
|
|
|
def test_query_parser(self):
|
|
query = Call("makeQuery", [Call("__binary__", ["id", "+", "F1.opExtrude"]), "CAP_EDGE", "EDGE", {"isStart": False, "x": Call("sQuery", [Call("__binary__", ["id", "+", "F0.wireOp"]), "EDGE", "E0"])}])
|
|
value = parse_query(query)
|
|
self.assertEqual((value.owner_feature, value.source_sketch, value.source_entity), ("F1", "F0", "E0"))
|
|
self.assertFalse(value.is_start)
|
|
|
|
def test_safe_units(self):
|
|
self.assertEqual(length_mm("2 * inch"), 50.8)
|
|
self.assertEqual(length_mm("25.4 / 2 * mm"), 12.7)
|
|
with self.assertRaises(ValueError): length_mm("external.value * mm")
|
|
|
|
|
|
if __name__ == "__main__": unittest.main()
|