from pathlib import Path from typing import Any import scripts.build_decisions_catalog as bc import scripts.decisions_lib as dl def test_catalog_lists_only_active_sorted_by_key(): recs = [ dl.Record( heading="H2", source=Path("x"), lineno=1, key="z.a", status="active", rule="Zeta rule", ), dl.Record( heading="H1", source=Path("x"), lineno=1, key="a.b", status="active", rule="Alpha rule", ), dl.Record( heading="Old", source=Path("x"), lineno=1, key="a.b", status="superseded", rule="old", ), ] out = bc.render_catalog(recs) assert "a.b" in out and "z.a" in out assert out.index("a.b") < out.index("z.a") # sorted assert "Alpha rule" in out and "Zeta rule" in out assert "old" not in out # superseded excluded assert "GENERATED" in out # do-not-edit banner def test_anchor_matches_gitea_double_hyphen_slug(): # Ground truth: Gitea does NOT collapse hyphen runs. " — " (space, em dash, space) becomes # "--" in the anchor (one hyphen per space/dash char), never collapsed to a single "-". a = bc._anchor( "2026-07-19 — CI `test` job reports a sampled true peak-anon, not cache-inflated `memory.peak` (#412)" ) assert a == ("2026-07-19--ci-test-job-reports-a-sampled-true-peak-anon-not-cache-inflated-memorypeak-412") b = bc._anchor("2026-07-16 — Optional advertised IPTV base URL (`iptv.base_url`)…") assert "iptvbase_url" in b def _r(key: str, **kw: Any) -> dl.Record: base: dict[str, Any] = dict( heading=f"H {key}", source=Path("decisions.md"), lineno=1, key=key, status="active", rule="r", ) base.update(kw) return dl.Record(**base) def test_review_due_section_lists_dated_records_soonest_first(): out = bc.render_catalog( [ _r("b.later", stale_after="2027-03-01"), _r("a.sooner", stale_after="2026-09-01"), _r("c.undated"), ] ) assert "## Review due" in out assert out.index("2026-09-01") < out.index("2027-03-01") assert "c.undated" not in out.split("## Review due")[1] def test_review_due_section_omitted_when_no_record_is_dated(): assert "## Review due" not in bc.render_catalog([_r("a.b")]) def test_catalog_is_date_independent(): """The generated file must never bake in 'today' — CI checks it with --check, so a time-dependent render would drift red on a calendar boundary with no commit touching it.""" past = bc.render_catalog([_r("a.b", stale_after="2020-01-01")]) future = bc.render_catalog([_r("a.b", stale_after="2099-01-01")]) # Guard against vacuity: without this the assertion below passes trivially on a renderer that # emits no dates at all (i.e. with the whole feature deleted). assert "2020-01-01" in past and "2099-01-01" in future # A long-past and a far-future date must produce byte-identical output apart from the date # itself: no stale/fresh verdict, no marker, nothing derived from the clock. assert past.replace("2020-01-01", "D") == future.replace("2099-01-01", "D") def test_review_due_row_links_correctly_from_a_topic_file(): """Review-due rows reuse _rel(), so a topic-file record must not get decisions.md's `../` form.""" out = bc.render_catalog( [ _r("t.opic", source=Path("docs/decisions/workflow-process.md"), stale_after="2027-01-01"), _r("m.ain", source=Path("docs/decisions.md"), stale_after="2027-01-02"), ] ) due = out.split("## Review due")[1] assert "(workflow-process.md#" in due assert "(../decisions.md#" in due