"""Round-trip smoke test: instance-local sketches + modifiers survive save/load. Builds a minimal project (component with a body, assembly with two instances, one carrying an instance sketch + cut modifier + fillet modifier), saves to a temp .fluency, reloads, and asserts: 1. the shared component is untouched by instance work, 2. the instance sketch + modifiers round-trip with sketch refs intact, 3. the plain instance has none. """ import os import tempfile import numpy as np from fluency.models.data_model import ( Project, Component, Body, Sketch, Feature, Assembly, AssemblyComponent, ) from fluency.io.project_io import save_project, load_project def main(): project = Project(name="inst test") comp = project.add_component() comp.name = "BasePart" body = comp.add_body(Body(name="MainBody")) base_sketch = comp.add_sketch(Sketch(name="BaseSketch")) body.features.append( Feature(operation="extrude", sketch=base_sketch, length=10.0) ) asm = project.add_assembly(Assembly(name="TestAsm")) ac1 = asm.add_component_instance(comp.id, name="Instance A") ac1.position = np.array([0.0, 0.0, 0.0]) ac2 = asm.add_component_instance(comp.id, name="Instance B") ac2.position = np.array([50.0, 0.0, 0.0]) # Instance A: local sketch + cut modifier referencing it + fillet. inst_sketch = ac1.add_instance_sketch() inst_sketch.name = "InstCutSketch" ac1.add_modifier(body.id, Feature(operation="cut", sketch=inst_sketch, length=5.0, through_all=True)) ac1.add_modifier(body.id, Feature(operation="fillet", radius=1.0)) # ---- save / load ---- fd, path = tempfile.mkstemp(suffix=".fluency") os.close(fd) try: save_project(project, path) loaded, _view = load_project(path) lcomp = loaded.components[comp.id] lac1 = None lac2 = None for lasm in loaded.assemblies.values(): for ac in lasm.components.values(): if ac.name == "Instance A": lac1 = ac elif ac.name == "Instance B": lac2 = ac assert lac1 is not None and lac2 is not None, "instances missing" # 1. component untouched assert len(lcomp.sketches) == 1, "component sketch count changed" assert len(lcomp.bodies[body.id].features) == 1, "feature chain changed" assert not getattr(lcomp.bodies[body.id], "modifiers", None) # 2. instance A round-trip assert len(lac1.sketches) == 1, "instance sketch missing" lsk_id, lsk = next(iter(lac1.sketches.items())) assert lsk.name == "InstCutSketch" mods = lac1.modifiers lbody_id = next(iter(lcomp.bodies)) assert len(mods.get(lbody_id, [])) == 2, f"modifiers missing: {mods}" cut, fil = mods[lbody_id][0], mods[lbody_id][1] assert cut.operation == "cut" and fil.operation == "fillet" assert cut.sketch is not None and cut.sketch.id == lsk_id, \ "cut sketch ref did not resolve to instance sketch" assert cut.length == 5.0 and cut.through_all # 3. plain instance clean assert not lac2.sketches and not lac2.modifiers print("ROUND_TRIP_OK") finally: os.unlink(path) if __name__ == "__main__": main()