Skip to content

Commit e066716

Browse files
committed
Update pyproject.toml and tests: switch to setuptools, bump version to 0.1.4, and enhance trick validation tests
1 parent 323e535 commit e066716

File tree

2 files changed

+88
-94
lines changed

2 files changed

+88
-94
lines changed

pyproject.toml

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[build-system]
2-
requires = ["hatchling>=1.25"]
3-
build-backend = "hatchling.build"
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "wzrdbrain"
7-
version = "0.1.3"
8-
description = "A simple library to generate random trick combinations for wizard skating."
7+
version = "0.1.4"
8+
description = "A simple library to generate trick combinations for wizard skating."
99
readme = "README.md"
1010
requires-python = ">=3.9"
1111
license = "Apache-2.0"
@@ -14,29 +14,18 @@ authors = [
1414
]
1515
keywords = ["wizard skating", "tricks", "random", "generator", "inline skating"]
1616
classifiers = [
17-
"Development Status :: 5 - Production/Stable",
18-
"Intended Audience :: Developers",
19-
"License :: OSI Approved :: Apache Software License",
20-
"Programming Language :: Python",
2117
"Programming Language :: Python :: 3",
22-
"Programming Language :: Python :: 3 :: Only",
23-
"Programming Language :: Python :: 3.9",
24-
"Programming Language :: Python :: 3.10",
25-
"Programming Language :: Python :: 3.11",
26-
"Programming Language :: Python :: 3.12",
27-
"Programming Language :: Python :: 3.13",
28-
"Typing :: Typed",
2918
"Topic :: Games/Entertainment",
3019
"Topic :: Software Development :: Libraries",
3120
]
3221

3322
[project.optional-dependencies]
3423
dev = [
35-
"pytest>=8",
36-
"ruff>=0.5",
37-
"black>=24.3",
38-
"mypy>=1.10",
39-
"build>=1.2",
24+
"pytest",
25+
"ruff",
26+
"black",
27+
"mypy",
28+
"build"
4029
]
4130

4231
[project.urls]
@@ -57,9 +46,12 @@ lint.extend-ignore = ["E501"]
5746
line-length = 100
5847

5948
[tool.pytest.ini_options]
49+
pythonpath = ["src"]
6050
testpaths = ["tests"]
61-
addopts = "-q"
6251

6352
[tool.mypy]
6453
strict = true
6554
warn_unused_ignores = true
55+
56+
[tool.setuptools.packages.find]
57+
where = ["src"]

tests/test_wzrdbrain.py

Lines changed: 75 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,77 @@
1-
from pathlib import Path
2-
import sys
3-
from collections.abc import Iterator, Sequence
4-
51
import pytest
2+
from wzrdbrain.wzrdbrain import Trick, generate_combo, DIRECTIONS, MOVES, STANCES, only_first
3+
4+
5+
def test_trick_creation_with_validation():
6+
"""Test that creating a Trick with invalid data raises a ValueError."""
7+
with pytest.raises(ValueError, match="Invalid move"):
8+
Trick(move="invalid_move")
9+
with pytest.raises(ValueError, match="Invalid direction"):
10+
Trick(direction="invalid_direction")
11+
with pytest.raises(ValueError, match="Invalid stance"):
12+
Trick(stance="invalid_stance")
13+
14+
15+
def test_trick_default_creation():
16+
"""Test creating a Trick with no arguments uses random defaults."""
17+
trick = Trick()
18+
assert isinstance(trick, Trick)
19+
assert trick.move in MOVES
20+
assert trick.direction in DIRECTIONS
21+
if trick.move not in {"predator", "predator one"}:
22+
# Stance should be None for predator moves, otherwise it should be set
23+
if trick.stance:
24+
assert trick.stance in STANCES
25+
26+
27+
def test_trick_str_representation():
28+
"""Test the string formatting of a Trick, including the 'fakie' logic."""
29+
trick1 = Trick(direction="front", stance="open", move="gazelle")
30+
assert str(trick1) == "front open gazelle"
31+
32+
trick2 = Trick(direction="back", move="360")
33+
assert str(trick2) == "fakie 360"
34+
35+
trick3 = Trick(direction="front", move="soul slide")
36+
assert str(trick3) == "forward soul slide"
37+
38+
39+
def test_trick_to_dict():
40+
"""Test the to_dict method includes the 'name' key."""
41+
trick = Trick(direction="front", stance="open", move="gazelle")
42+
trick_dict = trick.to_dict()
43+
assert isinstance(trick_dict, dict)
44+
assert "name" in trick_dict
45+
assert trick_dict["name"] == "front open gazelle"
46+
assert trick_dict["move"] == "gazelle"
47+
48+
49+
def test_generate_combo_returns_list_of_dicts():
50+
"""Test that generate_combo returns a list of trick dictionaries."""
51+
combo = generate_combo(3)
52+
assert isinstance(combo, list)
53+
assert len(combo) == 3
54+
for trick_dict in combo:
55+
assert isinstance(trick_dict, dict)
56+
assert "name" in trick_dict
57+
assert "move" in trick_dict
58+
59+
60+
def test_generate_combo_linking():
61+
"""Test that tricks in a combo are linked by their exit/enter directions."""
62+
# Generate a long combo to increase the chance of seeing rotation
63+
combo = generate_combo(10)
64+
for i in range(len(combo) - 1):
65+
current_trick = combo[i]
66+
next_trick = combo[i + 1]
67+
assert current_trick["exit_from_trick"] == next_trick["enter_into_trick"]
68+
669

7-
# Ensure src is on path so we can import the module under test
8-
ROOT = Path(__file__).resolve().parents[1]
9-
SRC = ROOT / "src"
10-
sys.path.insert(0, str(SRC))
11-
12-
import wzrdbrain.wzrdbrain as wb # noqa: E402
13-
14-
15-
def test_generate_trick_exclude_stance(monkeypatch: pytest.MonkeyPatch) -> None:
16-
# Force choices so selected_move is in exclude_stance ('predator')
17-
def fake_choice(seq: Sequence[str]) -> str:
18-
if seq is wb.move:
19-
return "predator"
20-
if seq is wb.direction:
21-
return "front"
22-
if seq is wb.stance:
23-
return "open"
24-
raise RuntimeError("unexpected seq")
25-
26-
# patch the module-level random.choice by target string to avoid mypy attr warnings
27-
monkeypatch.setattr("wzrdbrain.wzrdbrain.random.choice", fake_choice)
28-
trick = wb.generate_trick()
29-
assert trick == ["front", "predator"]
30-
31-
32-
def test_generate_trick_with_stance(monkeypatch: pytest.MonkeyPatch) -> None:
33-
# Force choices so selected_move is NOT in exclude_stance ('parallel')
34-
def fake_choice(seq: Sequence[str]) -> str:
35-
if seq is wb.move:
36-
return "parallel"
37-
if seq is wb.direction:
38-
return "back"
39-
if seq is wb.stance:
40-
return "open"
41-
raise RuntimeError("unexpected seq")
42-
43-
monkeypatch.setattr("wzrdbrain.wzrdbrain.random.choice", fake_choice)
44-
trick = wb.generate_trick()
45-
assert trick == ["back", "open", "parallel"]
46-
47-
48-
def test_generate_combo_fakie_conversion(monkeypatch: pytest.MonkeyPatch) -> None:
49-
# Provide deterministic successive generate_trick outputs to test fakie/forward conversion
50-
seq: Iterator[list[str]] = iter(
51-
[
52-
["front", "parallel"], # not in use_fakie -> unchanged
53-
["back", "toe press"], # in use_fakie -> back -> fakie (since it's subsequent)
54-
["front", "360"], # in use_fakie -> front -> forward
55-
]
56-
)
57-
58-
def fake_generate_trick() -> list[str]:
59-
return next(seq)
60-
61-
monkeypatch.setattr(wb, "generate_trick", fake_generate_trick)
62-
line = wb.generate_combo(3)
63-
assert line == [
64-
"front parallel",
65-
"fakie toe press",
66-
"forward 360",
67-
]
68-
69-
70-
def test_generate_combo_default_length() -> None:
71-
# Default should produce between 1 and 5 tricks
72-
line = wb.generate_combo()
73-
assert 1 <= len(line) <= 5
74-
for item in line:
75-
assert isinstance(item, str)
70+
def test_generate_combo_only_first_rule():
71+
"""Test that moves in 'only_first' do not appear after the first trick."""
72+
# Run multiple times to ensure rule is consistently applied
73+
for _ in range(10):
74+
combo = generate_combo(5)
75+
# Check all tricks after the first one
76+
for trick_dict in combo[1:]:
77+
assert trick_dict["move"] not in only_first

0 commit comments

Comments
 (0)