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
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,14 @@ dependencies = [
[project.scripts]
anvil = "anvil.cli:app"

[dependency-groups]
dev = [
"pytest>=8.0",
]

[tool.uv]
package = true

[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]
8 changes: 6 additions & 2 deletions src/anvil/wizard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ class TestSpec:

def to_fail_to_pass_str(self) -> str:
"""Format fail_to_pass as a string list for instance_info.txt."""
return "[" + ", ".join(f"'{t}'" for t in self.fail_to_pass) + "]"
# Use repr so test IDs containing quotes (e.g. parametrized pytest ids
# like "test_x[can't]") stay valid Python literals that round-trip
# through the instance_info.txt parser. Manual quoting produced invalid
# syntax and silently dropped the whole list on parse.
return repr(list(self.fail_to_pass))

def to_pass_to_pass_str(self) -> str:
"""Format pass_to_pass as a string list for instance_info.txt."""
return "[" + ", ".join(f"'{t}'" for t in self.pass_to_pass) + "]"
return repr(list(self.pass_to_pass))


@dataclass
Expand Down
34 changes: 34 additions & 0 deletions tests/test_wizard_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Tests for anvil.wizard.models."""

from __future__ import annotations

import ast

from anvil.wizard import models


def test_test_spec_str_roundtrip_common_case():
spec = models.TestSpec(
fail_to_pass=["tests/test_a.py::test_one"],
pass_to_pass=["tests/test_a.py::test_two", "tests/test_b.py::test_three"],
)
assert ast.literal_eval(spec.to_fail_to_pass_str()) == spec.fail_to_pass
assert ast.literal_eval(spec.to_pass_to_pass_str()) == spec.pass_to_pass


def test_test_spec_str_roundtrip_with_quotes_in_test_id():
# Parametrized pytest ids can contain apostrophes, e.g. test_x[can't].
# These used to produce invalid Python and get silently dropped when the
# instance_info.txt parser evaluated the string.
fail = ["tests/test_x.py::test_quote[can't]"]
pass_ = ['tests/test_y.py::test_dquote[say "hi"]']
spec = models.TestSpec(fail_to_pass=fail, pass_to_pass=pass_)

assert ast.literal_eval(spec.to_fail_to_pass_str()) == fail
assert ast.literal_eval(spec.to_pass_to_pass_str()) == pass_


def test_test_spec_str_empty():
spec = models.TestSpec()
assert ast.literal_eval(spec.to_fail_to_pass_str()) == []
assert ast.literal_eval(spec.to_pass_to_pass_str()) == []