Skip to content

Commit 8263fc3

Browse files
committed
Add unit tests covering every FragmentFilename branch
Fill the remaining coverage gaps so every public property and every private branch of the new value object is hit by a focused test: - test_fragment_filename_slug_and_tier: one case per tier (patch / minor / major / skip), plus the dotted-slug and 'no match' outcomes — covers .slug and .tier for both populated and None paths. - test_fragment_filename_validity_and_kind: 4-row grid asserting the .is_valid / .is_fragment / .is_skip flags stay consistent with each other across fragments, skips, and unparseable names. - test_fragment_filename_rejects_forbidden_chars: parametrized over every character in FragmentFilename._FORBIDDEN_CHARS plus a representative ASCII control char and DEL, so each character is covered individually rather than relying on collective coverage from a few example slugs. - test_fragment_filename_rejects_structural_edge_cases: empty filename, suffix-only filenames (slug would be empty), and the '@{' substring git refnames forbid. - test_fragment_filename_suffixes_are_canonical: pins the SUFFIXES class attribute to the exact tuple it must remain — the wire format for fragment filenames is part of the contract.
1 parent f06e52b commit 8263fc3

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

tools/changelog/test/test_bump_suffix.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,90 @@ def test_fragment_filename_extracts_dotted_slug_and_tier():
138138
assert fn.tier == "minor"
139139

140140

141+
@pytest.mark.parametrize(
142+
"name,expected_slug,expected_tier",
143+
[
144+
# One representative case per tier so each branch of the SUFFIXES
145+
# tuple is exercised on its own.
146+
("plain.rst", "plain", "patch"),
147+
("with-feature.minor.rst", "with-feature", "minor"),
148+
("with-break.major.rst", "with-break", "major"),
149+
("ci-only.skip", "ci-only", "skip"),
150+
# Dotted slug carries the most-specific suffix.
151+
("v1.2.3-bump.major.rst", "v1.2.3-bump", "major"),
152+
# Filenames that don't match any suffix yield ``(None, None)``.
153+
("not-a-fragment", None, None),
154+
("README.md", None, None),
155+
],
156+
)
157+
def test_fragment_filename_slug_and_tier(name, expected_slug, expected_tier):
158+
fn = cli.FragmentFilename(name)
159+
assert fn.slug == expected_slug
160+
assert fn.tier == expected_tier
161+
162+
163+
@pytest.mark.parametrize(
164+
"name,is_valid,is_fragment,is_skip",
165+
[
166+
# ``is_valid`` is true for both fragments and skip markers; only the
167+
# latter two flags partition the parsed names. This grid asserts
168+
# they're consistent for the four interesting outcomes.
169+
("plain.rst", True, True, False),
170+
("plain.minor.rst", True, True, False),
171+
("ci-only.skip", True, False, True),
172+
("not-a-fragment", False, False, False),
173+
],
174+
)
175+
def test_fragment_filename_validity_and_kind(name, is_valid, is_fragment, is_skip):
176+
fn = cli.FragmentFilename(name)
177+
assert fn.is_valid is is_valid
178+
assert fn.is_fragment is is_fragment
179+
assert fn.is_skip is is_skip
180+
181+
182+
@pytest.mark.parametrize(
183+
"bad_char",
184+
# Each forbidden char in :attr:`FragmentFilename._FORBIDDEN_CHARS` plus a
185+
# representative ASCII control char and the ``DEL`` sentinel — the regex
186+
# used to call these out via membership checks; the parser should still
187+
# reject them per character.
188+
[" ", "~", "^", ":", "?", "*", "[", "\\", "\x01", "\x7f"],
189+
)
190+
def test_fragment_filename_rejects_forbidden_chars(bad_char):
191+
fn = cli.FragmentFilename(f"slug{bad_char}with-bad-char.rst")
192+
assert fn.is_valid is False
193+
assert fn.slug is None
194+
assert fn.tier is None
195+
196+
197+
@pytest.mark.parametrize(
198+
"name",
199+
# Edge cases that don't fit cleanly into the parametrized validity grid:
200+
# an empty filename, a filename that's *only* a suffix (slug would be
201+
# empty), and the ``@{`` substring git refnames forbid.
202+
[
203+
"",
204+
".rst",
205+
".minor.rst",
206+
".skip",
207+
"has@{atbrace}.rst",
208+
],
209+
)
210+
def test_fragment_filename_rejects_structural_edge_cases(name):
211+
fn = cli.FragmentFilename(name)
212+
assert fn.is_valid is False
213+
214+
215+
def test_fragment_filename_suffixes_are_canonical():
216+
"""``SUFFIXES`` is the wire-format contract — pin the exact tuple."""
217+
assert cli.FragmentFilename.SUFFIXES == (
218+
(".minor.rst", "minor"),
219+
(".major.rst", "major"),
220+
(".skip", "skip"),
221+
(".rst", "patch"),
222+
)
223+
224+
141225
# ---------------------------------------------------------------------------
142226
# Fragment.parse_slug — derived from filename for collision detection
143227
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)