@@ -7681,7 +7681,70 @@ def test_save_and_load(self, project_dir):
76817681 assert loaded .workflow_id == "test-workflow"
76827682 assert loaded .status == RunStatus .RUNNING
76837683 assert loaded .inputs == {"name" : "login" }
7684- assert "step-one" in loaded .step_results
7684+ assert loaded .step_results == state .step_results
7685+
7686+ @pytest .mark .parametrize ("invalid_step_results" , [None , [], "invalid" , 1 , True ])
7687+ def test_load_rejects_non_object_step_results (
7688+ self , project_dir , invalid_step_results
7689+ ):
7690+ """Persisted step results must be a JSON object."""
7691+ from specify_cli .workflows .engine import RunState
7692+
7693+ state = RunState (
7694+ run_id = "invalid-results" ,
7695+ workflow_id = "test-workflow" ,
7696+ project_root = project_dir ,
7697+ )
7698+ state .save ()
7699+ state_path = state .runs_dir / "state.json"
7700+ state_data = json .loads (state_path .read_text (encoding = "utf-8" ))
7701+ state_data ["step_results" ] = invalid_step_results
7702+ state_path .write_text (json .dumps (state_data ), encoding = "utf-8" )
7703+
7704+ with pytest .raises (ValueError , match = "step_results.*JSON object" ):
7705+ RunState .load ("invalid-results" , project_dir )
7706+
7707+ @pytest .mark .parametrize ("invalid_result" , [None , [], "invalid" , 1 , True ])
7708+ def test_load_rejects_non_object_step_result_records (
7709+ self , project_dir , invalid_result
7710+ ):
7711+ """Each persisted step result must be a JSON object."""
7712+ from specify_cli .workflows .engine import RunState
7713+
7714+ state = RunState (
7715+ run_id = "invalid-record" ,
7716+ workflow_id = "test-workflow" ,
7717+ project_root = project_dir ,
7718+ )
7719+ state .save ()
7720+ state_path = state .runs_dir / "state.json"
7721+ state_data = json .loads (state_path .read_text (encoding = "utf-8" ))
7722+ state_data ["step_results" ] = {"step-one" : invalid_result }
7723+ state_path .write_text (json .dumps (state_data ), encoding = "utf-8" )
7724+
7725+ with pytest .raises (
7726+ ValueError ,
7727+ match = "step_results record 'step-one' must be a JSON object" ,
7728+ ):
7729+ RunState .load ("invalid-record" , project_dir )
7730+
7731+ def test_load_defaults_missing_step_results_for_legacy_state (self , project_dir ):
7732+ """Legacy states without step results load with an empty mapping."""
7733+ from specify_cli .workflows .engine import RunState
7734+
7735+ state = RunState (
7736+ run_id = "legacy-results" ,
7737+ workflow_id = "test-workflow" ,
7738+ project_root = project_dir ,
7739+ )
7740+ state .save ()
7741+ state_path = state .runs_dir / "state.json"
7742+ state_data = json .loads (state_path .read_text (encoding = "utf-8" ))
7743+ state_data .pop ("step_results" )
7744+ state_path .write_text (json .dumps (state_data ), encoding = "utf-8" )
7745+
7746+ loaded = RunState .load ("legacy-results" , project_dir )
7747+ assert loaded .step_results == {}
76857748
76867749 def test_load_not_found (self , project_dir ):
76877750 from specify_cli .workflows .engine import RunState
0 commit comments