"""SP40: tests for `cyclone validate-837 ` CLI.""" from __future__ import annotations import json from pathlib import Path import httpx import pytest from click.testing import CliRunner from cyclone import edifabric from cyclone.cli import validate_837_cmd _TEST_KEY = "test-edifabric-key-0123456789abcdef" def _make_client(handler): transport = httpx.MockTransport(handler) return httpx.Client(transport=transport, timeout=10.0) def _install(handler): edifabric.set_transport_factory(lambda: _make_client(handler)) @pytest.fixture(autouse=True) def _reset_transport(): yield edifabric._reset_transport_factory() # --- happy path ------------------------------------------------------- def test_validate_837_success_prints_status_and_exits_zero(tmp_path): """A clean file with Status='success' from Edifabric exits 0 and prints the OperationResult summary.""" fixture = Path("/home/tyler/dev/cyclone/backend/tests/fixtures/co_medicaid_837p.txt") sample = tmp_path / "ok.x12" sample.write_text(fixture.read_text()) def handler(request: httpx.Request) -> httpx.Response: if request.url.path.endswith("/read"): return httpx.Response(200, json=[{ "SegmentDelimiter": "~", "DataElementDelimiter": "*", "ISA": {"InterchangeControlNumber_13": "000000001"}, "Groups": [], "IEATrailers": [], }]) if request.url.path.endswith("/validate"): return httpx.Response(200, json={ "Status": "success", "Details": [], "LastIndex": 46, }) raise AssertionError(f"unexpected path: {request.url.path}") _install(handler) runner = CliRunner() result = runner.invoke(validate_837_cmd, [str(sample), "--api-key", _TEST_KEY]) assert result.exit_code == 0, result.output assert "Status: success" in result.output assert "Details: 0 item(s)" in result.output def test_validate_837_error_status_exits_two_and_prints_details(tmp_path): """Status='error' from Edifabric exits 2 and prints the offending segment + message for each Details item.""" sample = tmp_path / "bad.x12" sample.write_text("ISA*bad~") def handler(request: httpx.Request) -> httpx.Response: if request.url.path.endswith("/read"): return httpx.Response(200, json=[{ "SegmentDelimiter": "~", "DataElementDelimiter": "*", "ISA": {"InterchangeControlNumber_13": "000000001"}, "Groups": [], "IEATrailers": [], }]) if request.url.path.endswith("/validate"): return httpx.Response(200, json={ "Status": "error", "Details": [ {"SegmentId": "PER", "Message": "PER-04 is required", "Status": "error"}, {"SegmentId": "SBR", "Message": "SBR-09 is required", "Status": "error"}, ], "LastIndex": 5, }) raise AssertionError(f"unexpected path: {request.url.path}") _install(handler) runner = CliRunner() result = runner.invoke(validate_837_cmd, [str(sample), "--api-key", _TEST_KEY]) assert result.exit_code == 2, result.output assert "Status: error" in result.output assert "PER: PER-04 is required" in result.output assert "SBR: SBR-09 is required" in result.output def test_validate_837_missing_api_key_exits_one(tmp_path, monkeypatch): """With no API key anywhere (env var unset, keychain empty), the CLI exits 1 and surfaces a clear 'API key not configured' error.""" monkeypatch.delenv("CYCLONE_EDIFABRIC_API_KEY", raising=False) sample = tmp_path / "any.x12" sample.write_text("ISA*...~") def handler(request: httpx.Request) -> httpx.Response: raise AssertionError("transport should not be called when key is missing") _install(handler) runner = CliRunner() result = runner.invoke(validate_837_cmd, [str(sample)]) assert result.exit_code == 1, result.output assert "API key not configured" in result.output def test_validate_837_file_not_found_exits_two(): """Click's path validation rejects a missing file before the command body runs (exits 2 via Click's UsageError).""" runner = CliRunner() result = runner.invoke(validate_837_cmd, ["/nonexistent/path.x12", "--api-key", _TEST_KEY]) assert result.exit_code == 2, result.output