Add draw_spirograph with tests
Draws int(360 / size_of_gap) circles, each in a random RGB color, turning the heading by the gap after each. A gap that is not positive raises ValueError, and the integer count avoids the TypeError that range raises for a float. Task: MIL-004#2 Task: MIL-004#3
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import random
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.fakes import FakePen
|
||||
from turtle_challenges.constants import (
|
||||
FASTEST_SPEED,
|
||||
FULL_TURN_DEGREES,
|
||||
SPIROGRAPH_GAP_DEGREES,
|
||||
SPIROGRAPH_RADIUS,
|
||||
)
|
||||
from turtle_challenges.spirograph import draw_spirograph
|
||||
|
||||
|
||||
def test_draw_spirograph_draws_one_circle_per_gap_in_a_full_turn() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, rng=random.Random(1))
|
||||
|
||||
expected = FULL_TURN_DEGREES // SPIROGRAPH_GAP_DEGREES
|
||||
assert pen.args_of("circle") == [(SPIROGRAPH_RADIUS,)] * expected
|
||||
|
||||
|
||||
def test_draw_spirograph_turns_by_the_gap_after_each_circle() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=90, rng=random.Random(2))
|
||||
|
||||
assert pen.args_of("setheading") == [(90,), (180,), (270,), (360,)]
|
||||
|
||||
|
||||
def test_draw_spirograph_sets_a_color_before_each_circle() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=120, rng=random.Random(3))
|
||||
|
||||
assert pen.names()[1:] == ["color", "circle", "setheading"] * 3
|
||||
|
||||
|
||||
def test_draw_spirograph_gives_every_circle_an_rgb_color() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=30, rng=random.Random(4))
|
||||
|
||||
for (color,) in pen.args_of("color"):
|
||||
assert isinstance(color, tuple)
|
||||
assert len(color) == 3
|
||||
|
||||
|
||||
def test_draw_spirograph_sets_the_fastest_speed_first() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=180)
|
||||
|
||||
assert pen.calls[0] == ("speed", (FASTEST_SPEED,))
|
||||
|
||||
|
||||
def test_draw_spirograph_rounds_the_circle_count_down_for_an_uneven_gap() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=7)
|
||||
|
||||
assert len(pen.args_of("circle")) == 51
|
||||
|
||||
|
||||
def test_draw_spirograph_accepts_a_float_gap_without_a_type_error() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=2.5)
|
||||
|
||||
assert len(pen.args_of("circle")) == 144
|
||||
|
||||
|
||||
def test_draw_spirograph_uses_the_given_radius() -> None:
|
||||
pen = FakePen()
|
||||
|
||||
draw_spirograph(pen, size_of_gap=180, radius=42)
|
||||
|
||||
assert pen.args_of("circle") == [(42,), (42,)]
|
||||
|
||||
|
||||
def test_draw_spirograph_is_repeatable_with_the_same_seed() -> None:
|
||||
first = FakePen()
|
||||
second = FakePen()
|
||||
|
||||
draw_spirograph(first, size_of_gap=45, rng=random.Random(9))
|
||||
draw_spirograph(second, size_of_gap=45, rng=random.Random(9))
|
||||
|
||||
assert first.calls == second.calls
|
||||
|
||||
|
||||
@pytest.mark.parametrize("size_of_gap", [0, -5])
|
||||
def test_draw_spirograph_rejects_a_gap_that_is_not_positive(
|
||||
size_of_gap: float,
|
||||
) -> None:
|
||||
pen = FakePen()
|
||||
|
||||
with pytest.raises(ValueError, match="size_of_gap"):
|
||||
draw_spirograph(pen, size_of_gap=size_of_gap)
|
||||
|
||||
assert pen.calls == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize("radius", [0, -1])
|
||||
def test_draw_spirograph_rejects_a_radius_that_is_not_positive(radius: float) -> None:
|
||||
pen = FakePen()
|
||||
|
||||
with pytest.raises(ValueError, match="radius"):
|
||||
draw_spirograph(pen, radius=radius)
|
||||
|
||||
assert pen.calls == []
|
||||
Reference in New Issue
Block a user