stack: docs verify prueft § Commands und § Error contracts in tools/CONTRACT.md getrennt, 10 fehlende Fehlerkontrakt-Zeilen nachgetragen (schliesst #91)
Files changed: - CHANGES.md - VERSION - tools/CONTRACT.md - tools/chemenu/commands/docs_verify.py - tools/chemenu/tests/test_docs_verify.py
This commit is contained in:
1 parent
441a8151ab
commit
203084477f
5 files changed
+266
-31
No files matched your search
@@ -42,13 +42,136 @@ def test_invented_subcommand_under_a_real_group_is_caught(tmp_path, monkeypatch)
|
||||
group. The reverse check must match the full registered path, not just
|
||||
the top-level word."""
|
||||
fake = tmp_path / "README.md"
|
||||
fake.write_text("| `xref frobnicate --a X --b Y` | does not exist |\n", encoding="utf-8")
|
||||
fake.write_text(
|
||||
"## Commands\n\n"
|
||||
"| `xref frobnicate --a X --b Y` | does not exist |\n\n"
|
||||
"## Error contracts\n\n"
|
||||
"| `xref frobnicate --a X --b Y` | does not exist |\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(docs_verify, "CLI_README", fake)
|
||||
monkeypatch.setattr(docs_verify, "registered_commands", lambda: {"xref add", "xref remove"})
|
||||
issues = docs_verify.check_cli_readme()
|
||||
assert any("xref frobnicate" in issue for issue in issues)
|
||||
|
||||
|
||||
# --- section-scoped § Commands vs. § Error contracts (Gitea #91) ------------
|
||||
|
||||
|
||||
def test_section_text_extracts_between_headings():
|
||||
text = "# T\n\n## A\n\nfoo\n\n## B\n\nbar\n"
|
||||
assert docs_verify.section_text(text, "## A").strip() == "foo"
|
||||
|
||||
|
||||
def test_section_text_extends_to_end_of_file_when_last():
|
||||
text = "# T\n\n## A\n\nfoo\nbar\n"
|
||||
assert docs_verify.section_text(text, "## A").strip() == "foo\nbar"
|
||||
|
||||
|
||||
def test_section_text_raises_on_missing_heading():
|
||||
with pytest.raises(ValueError):
|
||||
docs_verify.section_text("# T\n\nno headings here\n", "## Commands")
|
||||
|
||||
|
||||
def _fake_contract(tmp_path, commands_rows: str, error_rows: str):
|
||||
fake = tmp_path / "CONTRACT.md"
|
||||
fake.write_text(
|
||||
f"## Commands\n\n{commands_rows}\n## Error contracts\n\n{error_rows}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
return fake
|
||||
|
||||
|
||||
def test_a_row_deleted_from_commands_is_caught_even_if_error_contracts_still_has_it(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
"""Regression for the bug the section split fixes: before, a name
|
||||
surviving in either table hid its own deletion from the other, so
|
||||
§ Commands losing a row was invisible as long as § Error contracts still
|
||||
named it."""
|
||||
fake = _fake_contract(
|
||||
tmp_path,
|
||||
commands_rows="| Command | Purpose |\n", # `frobnicate`'s row was deleted here
|
||||
error_rows="| `frobnicate` | never | yes | retry |\n",
|
||||
)
|
||||
monkeypatch.setattr(docs_verify, "CLI_README", fake)
|
||||
monkeypatch.setattr(docs_verify, "registered_commands", lambda: {"frobnicate"})
|
||||
issues = docs_verify.check_cli_readme()
|
||||
assert any(
|
||||
"frobnicate" in issue and "§ Commands" in issue and "not documented" in issue
|
||||
for issue in issues
|
||||
)
|
||||
|
||||
|
||||
def test_error_contracts_is_enforced_against_registered_commands(tmp_path, monkeypatch):
|
||||
"""Before the split, § Error contracts was never itself compared against
|
||||
the registered commands - a row missing there was invisible."""
|
||||
fake = _fake_contract(
|
||||
tmp_path,
|
||||
commands_rows="| `frobnicate` | does things |\n",
|
||||
error_rows="| Command | Exit 1 means | Atomic? | Retry policy |\n",
|
||||
)
|
||||
monkeypatch.setattr(docs_verify, "CLI_README", fake)
|
||||
monkeypatch.setattr(docs_verify, "registered_commands", lambda: {"frobnicate"})
|
||||
issues = docs_verify.check_cli_readme()
|
||||
assert any(
|
||||
"frobnicate" in issue and "§ Error contracts" in issue and "not documented" in issue
|
||||
for issue in issues
|
||||
)
|
||||
|
||||
|
||||
def test_a_phantom_error_contract_row_is_reported(tmp_path, monkeypatch):
|
||||
"""The reverse direction inside § Error contracts: a row for a command
|
||||
that does not exist must be reported there too, not only in § Commands."""
|
||||
fake = _fake_contract(
|
||||
tmp_path,
|
||||
commands_rows="| `frobnicate` | does things |\n",
|
||||
error_rows="| `frobnicate` | never | yes | retry |\n| `ghost command` | never happened | no | n/a |\n",
|
||||
)
|
||||
monkeypatch.setattr(docs_verify, "CLI_README", fake)
|
||||
monkeypatch.setattr(docs_verify, "registered_commands", lambda: {"frobnicate"})
|
||||
issues = docs_verify.check_cli_readme()
|
||||
assert any(
|
||||
"ghost command" in issue and "§ Error contracts" in issue and "not a wikitool command" in issue
|
||||
for issue in issues
|
||||
)
|
||||
|
||||
|
||||
def test_a_renamed_commands_heading_is_reported_not_silently_scanned(tmp_path, monkeypatch):
|
||||
"""A renamed or removed `## Commands` heading must fail loudly - falling
|
||||
back to scanning the whole file would make the two tables indistinguishable
|
||||
again, which is the exact bug this check exists to prevent."""
|
||||
fake = tmp_path / "CONTRACT.md"
|
||||
fake.write_text(
|
||||
"## Kommandos\n\n"
|
||||
"| `frobnicate` | does things |\n\n"
|
||||
"## Error contracts\n\n"
|
||||
"| `frobnicate` | never | yes | retry |\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(docs_verify, "CLI_README", fake)
|
||||
monkeypatch.setattr(docs_verify, "registered_commands", lambda: {"frobnicate"})
|
||||
issues = docs_verify.check_cli_readme()
|
||||
assert any("no '## Commands' heading found" in issue for issue in issues)
|
||||
assert not any("§ Commands" in issue and "not documented" in issue for issue in issues)
|
||||
|
||||
|
||||
def test_a_renamed_error_contracts_heading_is_reported_not_silently_scanned(tmp_path, monkeypatch):
|
||||
fake = tmp_path / "CONTRACT.md"
|
||||
fake.write_text(
|
||||
"## Commands\n\n"
|
||||
"| `frobnicate` | does things |\n\n"
|
||||
"## Fehlerkontrakte\n\n"
|
||||
"| `frobnicate` | never | yes | retry |\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(docs_verify, "CLI_README", fake)
|
||||
monkeypatch.setattr(docs_verify, "registered_commands", lambda: {"frobnicate"})
|
||||
issues = docs_verify.check_cli_readme()
|
||||
assert any("no '## Error contracts' heading found" in issue for issue in issues)
|
||||
assert not any("§ Error contracts" in issue and "not documented" in issue for issue in issues)
|
||||
|
||||
|
||||
def test_collection_contracts_exist():
|
||||
assert docs_verify.check_collection_contracts() == []
|
||||
|
||||
|
||||
Reference in new issue
Block a user