import json import tempfile import unittest from pathlib import Path from spatial_lab.project import Project,write_json from spatial_lab.examples import small_project class Editing(unittest.TestCase): def setUp(self): self.tmp=tempfile.TemporaryDirectory();self.path=Path(self.tmp.name)/'study.json';write_json(self.path,small_project());self.project=Project(self.path) def tearDown(self):self.tmp.cleanup() def test_edit_undo_redo_exactly(self): original=self.project.build();modified=self.project.apply([{'action':'set_parameter','name':'height','value':8}]) self.assertNotEqual(original['bundle_hash'],modified['bundle_hash']);self.assertEqual([o['id'] for o in original['objects']],[o['id'] for o in modified['objects']]) self.assertEqual(Project(self.path).travel('undo'),original);self.assertEqual(Project(self.path).travel('redo'),modified) def test_failed_transaction_changes_nothing(self): before=self.path.read_bytes() with self.assertRaises(ValueError):self.project.apply([{'action':'set_parameter','name':'height','value':9},{'action':'patch_node','id':'path','patch':{'params':{'xyz':['1/0',0,0]}}}]) self.assertEqual(self.path.read_bytes(),before);self.assertFalse(self.project.history_path.exists()) def test_dependency_aware_removal(self): with self.assertRaisesRegex(ValueError,'used by'):self.project.apply([{'action':'remove_node','id':'path'}]) b=self.project.apply([{'action':'remove_node','id':'path','cascade':True}]);self.assertEqual(b['stats']['nodes'],0) self.assertEqual(self.project.travel('undo')['stats']['nodes'],3) def test_add_and_patch_nodes(self): b=self.project.apply([{'action':'upsert_node','node':{'id':'echo','op':'transform','inputs':{'source':'gallery'},'params':{'translate':[0,0,10]}}},{'action':'patch_node','id':'gallery','patch':{'visible':False}}]) self.assertEqual(b['objects'][0]['id'],'echo/main');self.assertGreater(b['bounds']['min'][2],9) def test_new_edit_clears_redo(self): self.project.apply([{'action':'set_parameter','name':'height','value':8}]);self.project.travel('undo');self.project.apply([{'action':'set_parameter','name':'height','value':6}]) with self.assertRaisesRegex(ValueError,'Nothing to redo'):self.project.travel('redo') def test_external_edit_does_not_restore_stale_history(self): self.project.apply([{'action':'set_parameter','name':'height','value':8}]);p=self.project.read();p['parameters']['height']=10;write_json(self.path,p) with self.assertRaisesRegex(ValueError,'Nothing to undo'):self.project.travel('undo') if __name__=='__main__':unittest.main()