import unittest from tools.step_service.freecad_trim_step import build_removal_names, collect_subtree_objects, get_script_arguments, get_tree_children, should_include_in_tree class FreeCADTrimStepTests(unittest.TestCase): def test_extracts_arguments_after_pass_marker(self): input_path, deleted_path, output_path = get_script_arguments( [ "FreeCADCmd.exe", "freecad_trim_step.py", "--pass", "input.step", "deleted_paths.json", "output.step", ] ) self.assertEqual(input_path, "input.step") self.assertEqual(deleted_path, "deleted_paths.json") self.assertEqual(output_path, "output.step") def test_excludes_freecad_reference_objects_from_tree_paths(self): class FakeObject: def __init__(self, type_id, children=None): self.TypeId = type_id self.OutList = children or [] self.assertEqual(should_include_in_tree(FakeObject("App::Part")), True) self.assertEqual(should_include_in_tree(FakeObject("Part::Feature")), False) self.assertEqual(should_include_in_tree(FakeObject("App::Origin")), False) self.assertEqual(should_include_in_tree(FakeObject("App::Line")), False) self.assertEqual(should_include_in_tree(FakeObject("App::Plane")), False) def test_orders_assemblies_before_leaf_parts(self): class FakeObject: def __init__(self, label, type_id, children=None): self.Label = label self.TypeId = type_id self.OutList = children or [] feature = FakeObject("SOLID", "Part::Feature") plate = FakeObject("PLATE", "App::Part", [feature]) bracket_child = FakeObject("L-BRACKET", "App::Part", [feature]) bracket_assembly = FakeObject("L_BRACKET_ASSEMBLY_ASM", "App::Part", [bracket_child]) rod_child = FakeObject("ROD", "App::Part", [feature]) rod_assembly = FakeObject("ROD_ASM", "App::Part", [rod_child]) ordered = get_tree_children([plate, bracket_assembly, rod_assembly]) self.assertEqual( [obj.Label for obj in ordered], ["L_BRACKET_ASSEMBLY_ASM", "ROD_ASM", "PLATE"], ) def test_collects_full_subtree_for_recursive_delete(self): class FakeObject: def __init__(self, label, type_id, children=None): self.Label = label self.TypeId = type_id self.OutList = children or [] bolt = FakeObject("BOLT", "App::Part") nut = FakeObject("NUT", "App::Part") sub_assembly = FakeObject("NUT_BOLT_ASSEMBLY_ASM", "App::Part", [bolt, nut]) bracket = FakeObject("L_BRACKET_ASSEMBLY_ASM", "App::Part", [sub_assembly]) plate = FakeObject("PLATE", "App::Part") collected = collect_subtree_objects([bracket, plate], "0") self.assertEqual( [obj.Label for obj in collected], ["L_BRACKET_ASSEMBLY_ASM", "NUT_BOLT_ASSEMBLY_ASM", "BOLT", "NUT"], ) def test_collects_hidden_shape_children_when_deleting_visible_part(self): class FakeObject: def __init__(self, label, type_id, children=None): self.Label = label self.TypeId = type_id self.OutList = children or [] shape = FakeObject("ROD_SHAPE", "Part::Feature") rod = FakeObject("ROD", "App::Part", [shape]) support_shape = FakeObject("SUPPORT_SHAPE", "Part::Feature") support = FakeObject("SUPPORT", "App::Part", [support_shape]) collected = collect_subtree_objects([rod, support], "0") self.assertEqual( [obj.Label for obj in collected], ["ROD", "ROD_SHAPE"], ) def test_builds_removal_names_before_objects_become_invalid(self): class FakeObject: def __init__(self, name, depth): self.Name = name self._depth = depth @property def OutListRecursive(self): return [object()] * self._depth removal_names = build_removal_names( [ FakeObject("ROD_ASM", 3), FakeObject("ROD", 1), FakeObject("ROD_SHAPE", 0), FakeObject("ROD", 1), ] ) self.assertEqual(removal_names, ["ROD_ASM", "ROD", "ROD_SHAPE"]) if __name__ == "__main__": unittest.main()