feat(sp35): regression locks on parse-999/277ca/ta1 envelope guards
The 999, 277CA, and TA1 parsers already enforce envelope correctness at the parser level (parse_999.py line 290 raises 'No AK9 segment found'; parse_277ca.py line 298 raises 'Expected ST*277 or ST*277CA'; parse_ta1.py line 111 raises 'Expected TA1, got <other>'). These tests lock the HTTP surface contract: a wrong-kind file POSTed to those endpoints must come back as 400, never as 200 or 500. Tests added: - test_api_999.py: rejects_837_input, rejects_835_input - test_api_277ca.py: rejects_835_input, rejects_837_input - test_api_ta1.py: rejects_837_input, rejects_835_input If a future PR relaxes any of those parser-level guards, the corresponding regression lock fires immediately.
This commit is contained in:
@@ -163,4 +163,54 @@ def test_list_ta1_acks_newest_first(client: TestClient):
|
||||
assert len(items) == 2
|
||||
# The REJECTED (uploaded second) is first.
|
||||
assert items[0]["ack_code"] == "R"
|
||||
assert items[1]["ack_code"] == "A"
|
||||
assert items[1]["ack_code"] == "A"
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# SP35: parse-ta1 envelope regression lock
|
||||
# --------------------------------------------------------------------------- #
|
||||
#
|
||||
# The TA1 parser already raises CycloneParseError("Expected TA1, got <other>")
|
||||
# when fed a file that doesn't have a TA1 segment as its first payload
|
||||
# segment (parse_ta1.py line 111). This regression lock confirms the HTTP
|
||||
# surface converts that error into a 400 (never 200, never 500). TA1 has
|
||||
# no ST envelope, so the test uses an 837 fixture (which has ISA + GS +
|
||||
# ST*837 but no TA1 segment) to exercise the parser-level guard.
|
||||
|
||||
|
||||
def test_parse_ta1_endpoint_rejects_837_input(client: TestClient):
|
||||
"""Posting an 837P file to /api/parse-ta1 must surface 400, not 200.
|
||||
|
||||
The TA1 envelope has no ST (it's the bare interchange-ack segment),
|
||||
so the wrong-kind check is structural — the parser looks for the TA1
|
||||
segment and raises when it doesn't find one. An 837 file has ISA +
|
||||
GS + ST*837 but no TA1, which triggers that branch.
|
||||
"""
|
||||
wrong_kind = Path(__file__).parent / "fixtures" / "co_medicaid_837p.txt"
|
||||
text = wrong_kind.read_text()
|
||||
assert "ST*837" in text # sanity check on the fixture
|
||||
|
||||
resp = client.post(
|
||||
"/api/parse-ta1",
|
||||
files={"file": ("co_medicaid_837p.txt", text, "text/plain")},
|
||||
headers={"Accept": "application/json"},
|
||||
)
|
||||
assert resp.status_code == 400, resp.text
|
||||
body = resp.json()
|
||||
assert "error" in body
|
||||
detail = body.get("detail", "")
|
||||
assert "TA1" in detail or body["error"] == "Parse error", body
|
||||
|
||||
|
||||
def test_parse_ta1_endpoint_rejects_835_input(client: TestClient):
|
||||
"""Posting an 835 file to /api/parse-ta1 must surface 400, not 200."""
|
||||
wrong_kind = Path(__file__).parent / "fixtures" / "co_medicaid_835.txt"
|
||||
text = wrong_kind.read_text()
|
||||
assert "ST*835" in text # sanity check
|
||||
|
||||
resp = client.post(
|
||||
"/api/parse-ta1",
|
||||
files={"file": ("co_medicaid_835.txt", text, "text/plain")},
|
||||
headers={"Accept": "application/json"},
|
||||
)
|
||||
assert resp.status_code == 400, resp.text
|
||||
assert "error" in resp.json()
|
||||
|
||||
Reference in New Issue
Block a user