Files
018-turtle/tests/test_random_walk.py
Tirsvad 949d2edb63 Add random_walk with tests
200 steps of equal length, each in a random heading of 0, 90, 180 or 270 degrees and
a random RGB color, with a thick line and the fastest speed.

Task: MIL-004#1
2026-10-07 23:59:10 +08:00

111 lines
2.7 KiB
Python

import random
import pytest
from tests.fakes import FakePen
from turtle_challenges.constants import (
COLOR_CHANNEL_MAX,
COLOR_CHANNEL_MIN,
FASTEST_SPEED,
WALK_HEADINGS,
WALK_PEN_SIZE,
WALK_STEP_DISTANCE,
WALK_STEPS,
)
from turtle_challenges.random_walk import random_walk
def test_random_walk_sets_pen_size_and_speed_before_the_first_move() -> None:
pen = FakePen()
random_walk(pen, rng=random.Random(1))
assert pen.calls[0] == ("pensize", (WALK_PEN_SIZE,))
assert pen.calls[1] == ("speed", (FASTEST_SPEED,))
def test_random_walk_takes_the_default_number_of_equal_steps() -> None:
pen = FakePen()
random_walk(pen, rng=random.Random(2))
assert pen.args_of("forward") == [(WALK_STEP_DISTANCE,)] * WALK_STEPS
def test_random_walk_faces_only_the_four_headings() -> None:
pen = FakePen()
random_walk(pen, rng=random.Random(3))
headings = {args[0] for args in pen.args_of("setheading")}
assert headings <= set(WALK_HEADINGS)
assert len(headings) > 1
def test_random_walk_gives_every_step_an_rgb_color() -> None:
pen = FakePen()
random_walk(pen, steps=30, rng=random.Random(4))
colors = [args[0] for args in pen.args_of("color")]
assert len(colors) == 30
for color in colors:
assert isinstance(color, tuple)
assert len(color) == 3
assert all(
COLOR_CHANNEL_MIN <= channel <= COLOR_CHANNEL_MAX for channel in color
)
def test_random_walk_picks_color_and_heading_before_each_move() -> None:
pen = FakePen()
random_walk(pen, steps=2, rng=random.Random(5))
assert pen.names()[2:] == ["color", "setheading", "forward"] * 2
def test_random_walk_is_repeatable_with_the_same_seed() -> None:
first = FakePen()
second = FakePen()
random_walk(first, steps=25, rng=random.Random(8))
random_walk(second, steps=25, rng=random.Random(8))
assert first.calls == second.calls
def test_random_walk_with_no_steps_only_sets_up_the_pen() -> None:
pen = FakePen()
random_walk(pen, steps=0)
assert pen.names() == ["pensize", "speed"]
def test_random_walk_works_without_a_generator() -> None:
pen = FakePen()
random_walk(pen, steps=3)
assert len(pen.args_of("forward")) == 3
def test_random_walk_rejects_negative_steps() -> None:
pen = FakePen()
with pytest.raises(ValueError, match="steps"):
random_walk(pen, steps=-1)
assert pen.calls == []
@pytest.mark.parametrize("distance", [0, -3])
def test_random_walk_rejects_a_distance_that_is_not_positive(distance: float) -> None:
pen = FakePen()
with pytest.raises(ValueError, match="distance"):
random_walk(pen, distance=distance)
assert pen.calls == []