Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/pytest_just/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,34 @@ def assert_depends_on(
f"Expected exactly: {sorted(expected_set)}"
)

def assert_parameter(self, recipe: str, parameter: str) -> None:
"""Assert that ``recipe`` declares ``parameter``."""
def assert_parameter(self, recipe: str, parameter: str, **expected: Any) -> None:
"""Assert that ``recipe`` declares ``parameter``, optionally checking attributes.

When called without keyword arguments, checks that the parameter exists.
Each keyword argument is checked against the parameter's dump payload.

Args:
recipe: Recipe name or namepath.
parameter: Name of the parameter to inspect.
**expected: Attribute name/value pairs to verify (e.g.
``short="i"``, ``long="interactive"``, ``kind="singular"``).

Raises:
AssertionError: If the parameter does not exist or any attribute does not match.
"""
params = self.parameter_names(recipe)
assert parameter in params, (
f"Recipe `{recipe}` is missing parameter `{parameter}`. "
f"Available parameters: {params}"
)
if expected:
raw_params: list[dict[str, Any]] = self.parameters(recipe)
p: dict[str, Any] = next(p for p in raw_params if p.get("name") == parameter)
ctx: str = f"{recipe}.{parameter}"
for attr, want in expected.items():
assert attr in p, f"{ctx}: unexpected attribute `{attr}`"
got = p[attr]
assert got == want, f"{ctx}: expected {attr}={want!r}, got {got!r}"

def assert_body_contains(self, recipe: str, text: str) -> None:
"""Assert that rendered recipe text contains ``text``."""
Expand Down
64 changes: 64 additions & 0 deletions tests/test_assert_parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Tests for ``JustfileFixture.assert_parameter`` parameter attribute assertions."""

from __future__ import annotations

import shutil
from pathlib import Path

import pytest

from pytest_just import JustfileFixture


pytestmark = pytest.mark.skipif(shutil.which("just") is None, reason="just binary is required")


@pytest.fixture
def jf(tmp_path: Path) -> JustfileFixture:
"""Fixture with flag-annotated parameters."""
(tmp_path / "justfile").write_text(
"[arg('interactive', short = 'i', long, value = 'true')]\n"
"[arg('profile', short = 'p', long)]\n"
"deploy interactive='' profile='' name='':\n"
" @echo {{ interactive }} {{ profile }} {{ name }}\n",
encoding="utf-8",
)
return JustfileFixture(root=tmp_path)


def test_assert_parameter_short(jf: JustfileFixture) -> None:
"""Short flag assertion passes when correct."""
jf.assert_parameter("deploy", "interactive", short="i")


def test_assert_parameter_long(jf: JustfileFixture) -> None:
"""Long flag assertion passes when correct."""
jf.assert_parameter("deploy", "profile", long="profile")


def test_assert_parameter_value(jf: JustfileFixture) -> None:
"""Value flag assertion passes when correct."""
jf.assert_parameter("deploy", "interactive", value="true")


def test_assert_parameter_combined(jf: JustfileFixture) -> None:
"""Multiple flag assertions in one call."""
jf.assert_parameter("deploy", "interactive", short="i", long="interactive", value="true")


def test_assert_parameter_missing_param(jf: JustfileFixture) -> None:
"""Raises AssertionError for nonexistent parameter."""
with pytest.raises(AssertionError, match="missing parameter"):
jf.assert_parameter("deploy", "nonexistent", short="x")


def test_assert_parameter_wrong_short(jf: JustfileFixture) -> None:
"""Raises AssertionError when short flag doesn't match."""
with pytest.raises(AssertionError, match="expected short"):
jf.assert_parameter("deploy", "interactive", short="x")


def test_assert_parameter_unexpected_attr(jf: JustfileFixture) -> None:
"""Raises AssertionError for an attribute not in the dump schema."""
with pytest.raises(AssertionError, match="unexpected attribute"):
jf.assert_parameter("deploy", "interactive", bogus="x")