@@ -7332,6 +7332,94 @@ def test_list_after_execution(self, project_dir):
73327332 assert len(runs) == 1
73337333 assert runs[0]["workflow_id"] == "list-test"
73347334
7335+ def test_list_skips_malformed_json(self, project_dir):
7336+ from specify_cli.workflows.engine import WorkflowEngine
7337+
7338+ runs_dir = project_dir / ".specify" / "workflows" / "runs"
7339+ bad_dir = runs_dir / "bad-run"
7340+ bad_dir.mkdir(parents=True)
7341+ (bad_dir / "state.json").write_text("{invalid json", encoding="utf-8")
7342+
7343+ engine = WorkflowEngine(project_dir)
7344+ assert engine.list_runs() == []
7345+
7346+ def test_list_skips_unreadable_file(self, project_dir):
7347+ import sys
7348+ import subprocess
7349+ from specify_cli.workflows.engine import WorkflowEngine
7350+
7351+ runs_dir = project_dir / ".specify" / "workflows" / "runs"
7352+ bad_dir = runs_dir / "bad-run"
7353+ bad_dir.mkdir(parents=True)
7354+ state_file = bad_dir / "state.json"
7355+ state_file.write_text('{"run_id": "x"}', encoding="utf-8")
7356+
7357+ if sys.platform == "win32":
7358+ subprocess.run(["attrib", "+R", str(state_file)], check=True)
7359+ else:
7360+ state_file.chmod(0o000)
7361+
7362+ try:
7363+ engine = WorkflowEngine(project_dir)
7364+ if sys.platform == "win32":
7365+ assert engine.list_runs() == [{"run_id": "x"}]
7366+ else:
7367+ assert engine.list_runs() == []
7368+ finally:
7369+ if sys.platform == "win32":
7370+ subprocess.run(["attrib", "-R", str(state_file)], check=True)
7371+ else:
7372+ state_file.chmod(0o644)
7373+
7374+ def test_list_skips_non_dict_payload(self, project_dir):
7375+ from specify_cli.workflows.engine import WorkflowEngine
7376+
7377+ runs_dir = project_dir / ".specify" / "workflows" / "runs"
7378+ bad_dir = runs_dir / "bad-run"
7379+ bad_dir.mkdir(parents=True)
7380+ (bad_dir / "state.json").write_text('["not", "a", "dict"]', encoding="utf-8")
7381+
7382+ engine = WorkflowEngine(project_dir)
7383+ assert engine.list_runs() == []
7384+
7385+ def test_list_skips_empty_dict_payload(self, project_dir):
7386+ from specify_cli.workflows.engine import WorkflowEngine
7387+
7388+ runs_dir = project_dir / ".specify" / "workflows" / "runs"
7389+ bad_dir = runs_dir / "bad-run"
7390+ bad_dir.mkdir(parents=True)
7391+ (bad_dir / "state.json").write_text('{}', encoding="utf-8")
7392+
7393+ engine = WorkflowEngine(project_dir)
7394+ assert engine.list_runs() == []
7395+
7396+ def test_list_skips_bad_file_with_valid_sibling(self, project_dir):
7397+ from specify_cli.workflows.engine import WorkflowEngine, WorkflowDefinition
7398+
7399+ runs_dir = project_dir / ".specify" / "workflows" / "runs"
7400+ bad_dir = runs_dir / "bad-run"
7401+ bad_dir.mkdir(parents=True)
7402+ (bad_dir / "state.json").write_text("{bad", encoding="utf-8")
7403+
7404+ yaml_str = """
7405+ schema_version: "1.0"
7406+ workflow:
7407+ id: "good-run"
7408+ name: "Good Run"
7409+ version: "1.0.0"
7410+ steps:
7411+ - id: step-one
7412+ type: shell
7413+ run: "echo test"
7414+ """
7415+ definition = WorkflowDefinition.from_string(yaml_str)
7416+ engine = WorkflowEngine(project_dir)
7417+ engine.execute(definition)
7418+
7419+ runs = engine.list_runs()
7420+ assert len(runs) == 1
7421+ assert runs[0]["workflow_id"] == "good-run"
7422+
73357423
73367424# ===== Workflow Registry Tests =====
73377425
0 commit comments