fix(task-6): bind the invalid-tag fixture to the reported letter and position
Every grammar error is prefixed with the tag's own letters, so the old
single-letter fragments (FCI/"I", PSVX/"X", ...) matched whatever the
grammar said: a mutation that dropped the letter and position from every
error left 9 of 11 invalid rows green. The fixture now quotes the error
text the spec demands ("unexpected letter I at position 3", "... after
valve V", "trailing O (open/closed) ...", "needs at least one function
letter after F"), and the test pins it to the single first error.
ABCDEF-106 was mispinned as a grammar rejection of "D": six letters
exceed the regex cap, so it never reached the grammar. It is now pinned
as a format rejection, and ABCDE-106 carries the "letter D at position 4"
case.
A fixture lint rejects any fragment that is a substring of its own tag
and requires grammar rows to name a letter, position or trailing rule,
so a future row cannot reintroduce the hole.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5
parent
b8de3968f9
commit
2344b3b9d4
+12
-11
@@ -58,17 +58,18 @@
|
||||
["CIC-903", "Indicating Controller", "903"]
|
||||
],
|
||||
"invalid": [
|
||||
["FCI-101", "I"],
|
||||
["FIH-102", "H"],
|
||||
["F-103", "function"],
|
||||
["FICC-104", "repeated"],
|
||||
["PSVX-105", "X"],
|
||||
["ABCDEF-106", "D"],
|
||||
["FQQ-107", "Q"],
|
||||
["1FC", "format"],
|
||||
["FIC", "format"],
|
||||
["fic-101-", "format"],
|
||||
["LSO-108", "O"]
|
||||
["FCI-101", "unexpected letter I at position 3"],
|
||||
["FIH-102", "trailing H needs an alarm (A) or switch (S) before it"],
|
||||
["F-103", "needs at least one function letter after F"],
|
||||
["FICC-104", "repeated letter C at position 4"],
|
||||
["PSVX-105", "unexpected letter X at position 4 after valve V"],
|
||||
["ABCDE-106", "unexpected letter D at position 4"],
|
||||
["ABCDEF-106", "not in [area-]LETTERS[-]loop[suffix] format"],
|
||||
["FQQ-107", "unexpected letter Q at position 3"],
|
||||
["1FC", "not in [area-]LETTERS[-]loop[suffix] format"],
|
||||
["FIC", "not in [area-]LETTERS[-]loop[suffix] format"],
|
||||
["fic-101-", "not in [area-]LETTERS[-]loop[suffix] format"],
|
||||
["LSO-108", "trailing O (open/closed) is only valid after a switch on a position (Z) tag"]
|
||||
],
|
||||
"formats": [
|
||||
["10-FIC-101A", "10", "FIC", "101", "A"],
|
||||
|
||||
+17
-1
@@ -39,7 +39,23 @@ def test_invalid_tags_name_the_offending_letter(tag, fragment):
|
||||
out = parse_tag(tag, kind="instrument")
|
||||
assert out["valid"] is False
|
||||
assert out["tag"] == tag
|
||||
assert any(fragment in err for err in out["errors"]), out["errors"]
|
||||
# The grammar stops at the first offending letter, so the fixture pins
|
||||
# exactly one error and the fragment must sit in *that* one.
|
||||
assert len(out["errors"]) == 1, out["errors"]
|
||||
assert fragment in out["errors"][0], out["errors"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag, fragment", FIXTURE["invalid"])
|
||||
def test_invalid_fixture_fragments_bind_the_letter_and_position(tag, fragment):
|
||||
# Every grammar error is prefixed with the tag's own letters, so a fragment
|
||||
# that is a substring of the tag ("I" for FCI) matches whatever the grammar
|
||||
# says and pins nothing. A row must quote the rule text, and a grammar row
|
||||
# must quote the reported position as well as the letter.
|
||||
assert fragment not in tag.upper(), f"{tag!r}: fragment {fragment!r} is part of the tag"
|
||||
if "format" not in fragment:
|
||||
assert "position" in fragment or "letter" in fragment or "trailing" in fragment, (
|
||||
f"{tag!r}: fragment {fragment!r} names neither a letter nor a position"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag, area, letters, loop, suffix", FIXTURE["formats"])
|
||||
|
||||
Reference in New Issue
Block a user