import json from types import SimpleNamespace from typer.testing import CliRunner from tht.cli import app def test_preprocess_evidence_json_is_pristine(monkeypatch, tmp_path): import tht.cli.preprocess_cmd as command result = SimpleNamespace(model_dump=lambda mode=None: { "status": "succeeded", "generation": "gen:abc", "published": True }) monkeypatch.setattr(command, "run_from_config", lambda *args, **kwargs: result) response = CliRunner().invoke( app, ["preprocess", "evidence", "--json", "-c", str(tmp_path / "workspace.yaml")] ) assert response.exit_code == 0, response.output assert json.loads(response.output)["generation"] == "gen:abc" def test_preprocess_failure_is_structured_and_nonzero(monkeypatch, tmp_path): import tht.cli.preprocess_cmd as command monkeypatch.setattr(command, "run_from_config", lambda *a, **k: (_ for _ in ()).throw(RuntimeError("secret detail"))) response = CliRunner().invoke( app, ["preprocess", "evidence", "--json", "-c", str(tmp_path / "workspace.yaml")] ) assert response.exit_code != 0 assert json.loads(response.output) == {"status": "failed", "error": "preprocessing failed"} assert "secret detail" not in response.output def test_preprocess_resume_rejects_generation_id_before_configuration(monkeypatch, tmp_path): import tht.cli.preprocess_cmd as command called = False def forbidden(*args, **kwargs): nonlocal called called = True monkeypatch.setattr(command, "run_from_config", forbidden) response = CliRunner().invoke( app, [ "preprocess", "evidence", "--resume", "gen:" + "a" * 32, "--json", "-c", str(tmp_path / "workspace.yaml"), ], ) assert response.exit_code != 0 assert json.loads(response.output) == { "status": "failed", "error": "resume requires a preprocessing run id" } assert called is False