Skip to content

Commit ba33c5b

Browse files
authored
test: move the ADR scanner's self-tests out of the file consumers fetch (#122)
1 parent aac6a85 commit ba33c5b

2 files changed

Lines changed: 91 additions & 88 deletions

File tree

‎tests/test_adr_citations.py‎

Lines changed: 7 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import pytest
88

99

10-
_ADR_DIR: typing.Final = "docs/adr/"
10+
ADR_DIR: typing.Final = "docs/adr/"
1111
_CITATION: typing.Final = re.compile(r"docs/adr/\d{4}(?:-[a-z0-9-]+\.md)?")
12-
_NUMBER_PREFIX: typing.Final = "ADR-"
13-
_NUMBER_CITATION: typing.Final = re.compile(_NUMBER_PREFIX + r"\d{4}")
14-
_UNWALKED_DIR: typing.Final = "node_modules"
12+
NUMBER_PREFIX: typing.Final = "ADR-"
13+
_NUMBER_CITATION: typing.Final = re.compile(NUMBER_PREFIX + r"\d{4}")
14+
UNWALKED_DIR: typing.Final = "node_modules"
1515
# mkdocs build output: a second copy of docs/, whose citations are the originals'.
1616
_GENERATED_DIR: typing.Final = "site"
1717
_SCANNED_SUFFIXES: typing.Final = (".py", ".md", ".toml")
@@ -21,7 +21,7 @@ def _scanned_files(root: pathlib.Path) -> list[pathlib.Path]:
2121
found: list[pathlib.Path] = []
2222
for dirpath, dirnames, filenames in os.walk(root):
2323
dirnames[:] = sorted(
24-
name for name in dirnames if not name.startswith(".") and name not in (_UNWALKED_DIR, _GENERATED_DIR)
24+
name for name in dirnames if not name.startswith(".") and name not in (UNWALKED_DIR, _GENERATED_DIR)
2525
)
2626
found.extend(pathlib.Path(dirpath, name) for name in sorted(filenames) if name.endswith(_SCANNED_SUFFIXES))
2727
return found
@@ -41,9 +41,9 @@ def _citations(file: pathlib.Path, source: str) -> set[str]:
4141

4242

4343
def _resolves(root: pathlib.Path, cited: str) -> bool:
44-
if cited.startswith(_ADR_DIR):
44+
if cited.startswith(ADR_DIR):
4545
return (root / cited).is_file()
46-
return any((root / _ADR_DIR).glob(f"{cited.removeprefix(_NUMBER_PREFIX)}-*.md"))
46+
return any((root / ADR_DIR).glob(f"{cited.removeprefix(NUMBER_PREFIX)}-*.md"))
4747

4848

4949
def unresolved_citations(root: pathlib.Path) -> list[tuple[str, str]]:
@@ -75,84 +75,3 @@ def test_every_adr_citation_in_the_repo_resolves(pytestconfig: pytest.Config) ->
7575
unresolved = unresolved_citations(pytestconfig.rootpath)
7676

7777
assert unresolved == [], "\n".join(f"{file} cites {cited}" for file, cited in unresolved)
78-
79-
80-
def test_a_citation_of_a_missing_adr_is_reported_with_its_citing_file(tmp_path: pathlib.Path) -> None:
81-
"""The scanner is exercised against a known result, so an empty scan cannot pass as a green one."""
82-
(tmp_path / _ADR_DIR).mkdir(parents=True)
83-
(tmp_path / _ADR_DIR / "0001-kept.md").write_text("# kept\n", encoding="utf-8")
84-
(tmp_path / "pkg").mkdir()
85-
(tmp_path / "pkg" / "mod.py").write_text(
86-
f'"""Explained in {_ADR_DIR}0001-kept.md and {_ADR_DIR}9999-missing.md."""\n',
87-
encoding="utf-8",
88-
)
89-
90-
assert unresolved_citations(tmp_path) == [("pkg/mod.py", f"{_ADR_DIR}9999-missing.md")]
91-
92-
93-
def test_a_citation_split_across_adjacent_string_literals_is_found(tmp_path: pathlib.Path) -> None:
94-
"""Python joins adjacent literals at parse time, which is what the `nack` guard message relies on."""
95-
(tmp_path / "guard.py").write_text(
96-
f'MESSAGE = (\n "See https://example.invalid/blob/main/{_ADR_DIR}"\n "0003-split.md."\n)\n',
97-
encoding="utf-8",
98-
)
99-
100-
assert unresolved_citations(tmp_path) == [("guard.py", f"{_ADR_DIR}0003-split.md")]
101-
102-
103-
def test_a_citation_inside_a_hash_comment_is_found(tmp_path: pathlib.Path) -> None:
104-
"""Comments never reach the AST, so the raw text is scanned as well."""
105-
(tmp_path / "graph.py").write_text(f"# The rule is one-way, see {_ADR_DIR}0009-comment.md\n", encoding="utf-8")
106-
107-
assert unresolved_citations(tmp_path) == [("graph.py", f"{_ADR_DIR}0009-comment.md")]
108-
109-
110-
def test_a_bare_adr_number_naming_no_file_is_reported(tmp_path: pathlib.Path) -> None:
111-
"""A renumber leaves `ADR-NNNN` prose behind; only the path form was ever checked."""
112-
(tmp_path / _ADR_DIR).mkdir(parents=True)
113-
(tmp_path / _ADR_DIR / "0001-kept.md").write_text("# kept\n", encoding="utf-8")
114-
(tmp_path / "smoke.py").write_text(
115-
f"# the constraint {_NUMBER_PREFIX}0001 records, unlike {_NUMBER_PREFIX}9999\n", encoding="utf-8"
116-
)
117-
118-
assert unresolved_citations(tmp_path) == [("smoke.py", f"{_NUMBER_PREFIX}9999")]
119-
120-
121-
def test_a_bare_adr_path_is_reported_even_when_the_adr_exists(tmp_path: pathlib.Path) -> None:
122-
"""`docs/adr/NNNN` with no slug names nothing on disk, so a rename or a drop never breaks it."""
123-
(tmp_path / _ADR_DIR).mkdir(parents=True)
124-
(tmp_path / _ADR_DIR / "0002-kept.md").write_text("# kept\n", encoding="utf-8")
125-
(tmp_path / "pkg").mkdir()
126-
(tmp_path / "pkg" / "mod.py").write_text(
127-
f'"""Argued in {_ADR_DIR}0002 and {_ADR_DIR}0002-kept.md."""\n', encoding="utf-8"
128-
)
129-
130-
assert unresolved_citations(tmp_path) == [("pkg/mod.py", f"{_ADR_DIR}0002")]
131-
132-
133-
def test_a_citation_outside_python_is_found(tmp_path: pathlib.Path) -> None:
134-
"""`pyproject.toml` explains dependency floors by citing ADRs, and Markdown cites them in prose."""
135-
(tmp_path / _ADR_DIR).mkdir(parents=True)
136-
(tmp_path / "pyproject.toml").write_text(f"# see {_ADR_DIR}0002-floor.md\ndeps = []\n", encoding="utf-8")
137-
(tmp_path / "AGENTS.md").write_text(f"Read {_NUMBER_PREFIX}0004 before editing.\n", encoding="utf-8")
138-
139-
assert unresolved_citations(tmp_path) == [
140-
("AGENTS.md", f"{_NUMBER_PREFIX}0004"),
141-
("pyproject.toml", f"{_ADR_DIR}0002-floor.md"),
142-
]
143-
144-
145-
def test_a_tree_with_no_citations_and_no_adr_directory_reports_nothing(tmp_path: pathlib.Path) -> None:
146-
(tmp_path / "plain.py").write_text("X = 1\n", encoding="utf-8")
147-
148-
assert unresolved_citations(tmp_path) == []
149-
150-
151-
def test_files_under_dot_directories_are_not_scanned(tmp_path: pathlib.Path) -> None:
152-
"""A virtualenv or a cache is not this repo's citations."""
153-
(tmp_path / ".venv" / "lib").mkdir(parents=True)
154-
(tmp_path / ".venv" / "lib" / "vendored.py").write_text(f"# {_ADR_DIR}0001-elsewhere.md\n", encoding="utf-8")
155-
(tmp_path / _UNWALKED_DIR).mkdir()
156-
(tmp_path / _UNWALKED_DIR / "dep.py").write_text(f"# {_ADR_DIR}0002-elsewhere.md\n", encoding="utf-8")
157-
158-
assert unresolved_citations(tmp_path) == []

‎tests/test_adr_scanner.py‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import pathlib
2+
3+
from test_adr_citations import ADR_DIR, NUMBER_PREFIX, UNWALKED_DIR, unresolved_citations
4+
5+
6+
def test_a_citation_of_a_missing_adr_is_reported_with_its_citing_file(tmp_path: pathlib.Path) -> None:
7+
"""The scanner is exercised against a known result, so an empty scan cannot pass as a green one."""
8+
(tmp_path / ADR_DIR).mkdir(parents=True)
9+
(tmp_path / ADR_DIR / "0001-kept.md").write_text("# kept\n", encoding="utf-8")
10+
(tmp_path / "pkg").mkdir()
11+
(tmp_path / "pkg" / "mod.py").write_text(
12+
f'"""Explained in {ADR_DIR}0001-kept.md and {ADR_DIR}9999-missing.md."""\n',
13+
encoding="utf-8",
14+
)
15+
16+
assert unresolved_citations(tmp_path) == [("pkg/mod.py", f"{ADR_DIR}9999-missing.md")]
17+
18+
19+
def test_a_citation_split_across_adjacent_string_literals_is_found(tmp_path: pathlib.Path) -> None:
20+
"""Python joins adjacent literals at parse time, which is what the `nack` guard message relies on."""
21+
(tmp_path / "guard.py").write_text(
22+
f'MESSAGE = (\n "See https://example.invalid/blob/main/{ADR_DIR}"\n "0003-split.md."\n)\n',
23+
encoding="utf-8",
24+
)
25+
26+
assert unresolved_citations(tmp_path) == [("guard.py", f"{ADR_DIR}0003-split.md")]
27+
28+
29+
def test_a_citation_inside_a_hash_comment_is_found(tmp_path: pathlib.Path) -> None:
30+
"""Comments never reach the AST, so the raw text is scanned as well."""
31+
(tmp_path / "graph.py").write_text(f"# The rule is one-way, see {ADR_DIR}0009-comment.md\n", encoding="utf-8")
32+
33+
assert unresolved_citations(tmp_path) == [("graph.py", f"{ADR_DIR}0009-comment.md")]
34+
35+
36+
def test_a_bare_adr_number_naming_no_file_is_reported(tmp_path: pathlib.Path) -> None:
37+
"""A renumber leaves `ADR-NNNN` prose behind; only the path form was ever checked."""
38+
(tmp_path / ADR_DIR).mkdir(parents=True)
39+
(tmp_path / ADR_DIR / "0001-kept.md").write_text("# kept\n", encoding="utf-8")
40+
(tmp_path / "smoke.py").write_text(
41+
f"# the constraint {NUMBER_PREFIX}0001 records, unlike {NUMBER_PREFIX}9999\n", encoding="utf-8"
42+
)
43+
44+
assert unresolved_citations(tmp_path) == [("smoke.py", f"{NUMBER_PREFIX}9999")]
45+
46+
47+
def test_a_bare_adr_path_is_reported_even_when_the_adr_exists(tmp_path: pathlib.Path) -> None:
48+
"""`docs/adr/NNNN` with no slug names nothing on disk, so a rename or a drop never breaks it."""
49+
(tmp_path / ADR_DIR).mkdir(parents=True)
50+
(tmp_path / ADR_DIR / "0002-kept.md").write_text("# kept\n", encoding="utf-8")
51+
(tmp_path / "pkg").mkdir()
52+
(tmp_path / "pkg" / "mod.py").write_text(
53+
f'"""Argued in {ADR_DIR}0002 and {ADR_DIR}0002-kept.md."""\n', encoding="utf-8"
54+
)
55+
56+
assert unresolved_citations(tmp_path) == [("pkg/mod.py", f"{ADR_DIR}0002")]
57+
58+
59+
def test_a_citation_outside_python_is_found(tmp_path: pathlib.Path) -> None:
60+
"""`pyproject.toml` explains dependency floors by citing ADRs, and Markdown cites them in prose."""
61+
(tmp_path / ADR_DIR).mkdir(parents=True)
62+
(tmp_path / "pyproject.toml").write_text(f"# see {ADR_DIR}0002-floor.md\ndeps = []\n", encoding="utf-8")
63+
(tmp_path / "AGENTS.md").write_text(f"Read {NUMBER_PREFIX}0004 before editing.\n", encoding="utf-8")
64+
65+
assert unresolved_citations(tmp_path) == [
66+
("AGENTS.md", f"{NUMBER_PREFIX}0004"),
67+
("pyproject.toml", f"{ADR_DIR}0002-floor.md"),
68+
]
69+
70+
71+
def test_a_tree_with_no_citations_and_no_adr_directory_reports_nothing(tmp_path: pathlib.Path) -> None:
72+
(tmp_path / "plain.py").write_text("X = 1\n", encoding="utf-8")
73+
74+
assert unresolved_citations(tmp_path) == []
75+
76+
77+
def test_files_under_dot_directories_are_not_scanned(tmp_path: pathlib.Path) -> None:
78+
"""A virtualenv or a cache is not this repo's citations."""
79+
(tmp_path / ".venv" / "lib").mkdir(parents=True)
80+
(tmp_path / ".venv" / "lib" / "vendored.py").write_text(f"# {ADR_DIR}0001-elsewhere.md\n", encoding="utf-8")
81+
(tmp_path / UNWALKED_DIR).mkdir()
82+
(tmp_path / UNWALKED_DIR / "dep.py").write_text(f"# {ADR_DIR}0002-elsewhere.md\n", encoding="utf-8")
83+
84+
assert unresolved_citations(tmp_path) == []

0 commit comments

Comments
 (0)