|
| 1 | +"""Parametrized diagram freshness enforcement: bundled recipes must have non-stale |
| 2 | +diagrams; missing diagrams are xfail(strict=True) with shrink-enforcement meta-test. |
| 3 | +""" |
| 4 | + |
| 5 | +from __future__ import annotations |
| 6 | + |
| 7 | +from pathlib import Path |
| 8 | +from typing import Any |
| 9 | + |
| 10 | +import pytest |
| 11 | + |
| 12 | +from autoskillit.recipe.diagrams import check_diagram_staleness |
| 13 | +from autoskillit.recipe.io import builtin_recipes_dir |
| 14 | + |
| 15 | +pytestmark = [pytest.mark.layer("arch"), pytest.mark.small] |
| 16 | + |
| 17 | +_RECIPES_DIR = builtin_recipes_dir() |
| 18 | +_BUNDLED_RECIPE_YAML_PATHS = sorted(_RECIPES_DIR.glob("*.yaml")) |
| 19 | + |
| 20 | +MINIMUM_RECIPE_COUNT = 10 |
| 21 | +CURRENT_XFAIL_CAP = 10 |
| 22 | + |
| 23 | +_RECIPES_WITH_DIAGRAMS = [ |
| 24 | + p for p in _BUNDLED_RECIPE_YAML_PATHS if (_RECIPES_DIR / "diagrams" / f"{p.stem}.md").exists() |
| 25 | +] |
| 26 | +_WITHOUT_SET = set(_BUNDLED_RECIPE_YAML_PATHS) - set(_RECIPES_WITH_DIAGRAMS) |
| 27 | +_RECIPES_WITHOUT_DIAGRAMS = sorted(_WITHOUT_SET) |
| 28 | + |
| 29 | + |
| 30 | +def _make_params() -> list[Any]: |
| 31 | + params: list[Any] = [] |
| 32 | + for p in _BUNDLED_RECIPE_YAML_PATHS: |
| 33 | + if p in _WITHOUT_SET: |
| 34 | + params.append( |
| 35 | + pytest.param( |
| 36 | + p, |
| 37 | + id=p.stem, |
| 38 | + marks=pytest.mark.xfail( |
| 39 | + strict=True, |
| 40 | + reason=f"diagram not yet created for {p.stem}", |
| 41 | + ), |
| 42 | + ) |
| 43 | + ) |
| 44 | + else: |
| 45 | + params.append(pytest.param(p, id=p.stem)) |
| 46 | + return params |
| 47 | + |
| 48 | + |
| 49 | +@pytest.mark.parametrize("recipe_path", _make_params()) |
| 50 | +def test_bundled_recipe_diagram_not_stale(recipe_path: Path) -> None: |
| 51 | + is_stale = check_diagram_staleness(recipe_path.stem, _RECIPES_DIR, recipe_path) |
| 52 | + assert not is_stale, ( |
| 53 | + f"Diagram for '{recipe_path.stem}' is stale or missing. " |
| 54 | + f"Run '/render-recipe {recipe_path.stem}' to regenerate." |
| 55 | + ) |
| 56 | + |
| 57 | + |
| 58 | +def test_minimum_recipe_count() -> None: |
| 59 | + assert len(_BUNDLED_RECIPE_YAML_PATHS) >= MINIMUM_RECIPE_COUNT, ( |
| 60 | + f"Expected at least {MINIMUM_RECIPE_COUNT} bundled recipe YAMLs, " |
| 61 | + f"found {len(_BUNDLED_RECIPE_YAML_PATHS)}. " |
| 62 | + "Is builtin_recipes_dir() resolving correctly?" |
| 63 | + ) |
| 64 | + |
| 65 | + |
| 66 | +def test_xfail_diagram_count_is_shrinking() -> None: |
| 67 | + assert len(_RECIPES_WITHOUT_DIAGRAMS) <= CURRENT_XFAIL_CAP, ( |
| 68 | + f"Expected at most {CURRENT_XFAIL_CAP} recipes without diagrams, " |
| 69 | + f"found {len(_RECIPES_WITHOUT_DIAGRAMS)}: " |
| 70 | + f"{sorted(p.stem for p in _RECIPES_WITHOUT_DIAGRAMS)}. " |
| 71 | + "A new recipe was added without a diagram — either create the diagram " |
| 72 | + "or raise CURRENT_XFAIL_CAP (with justification)." |
| 73 | + ) |
| 74 | + |
| 75 | + |
| 76 | +def test_check_diagram_staleness_missing_is_stale(tmp_path: Path) -> None: |
| 77 | + (tmp_path / "diagrams").mkdir() |
| 78 | + recipe_yaml = tmp_path / "fake_recipe.yaml" |
| 79 | + recipe_yaml.write_text("steps: []\n") |
| 80 | + assert check_diagram_staleness("fake_recipe", tmp_path, recipe_yaml) |
0 commit comments