python -m turtle_challenges <challenge> and the turtle-challenges command open a window, run the named challenge and wait for a click. square and dashed-line are registered; a missing Tk is reported with a hint instead of a traceback. Task: MIL-002#6
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import pytest
|
||||
|
||||
from tests.fakes import FakePen, FakeWindow
|
||||
from turtle_challenges import cli
|
||||
from turtle_challenges.constants import (
|
||||
CHALLENGE_NAMES,
|
||||
DASH_COUNT,
|
||||
SQUARE_SIDES,
|
||||
)
|
||||
from turtle_challenges.pen import Pen, Window
|
||||
from turtle_challenges.window import TurtleUnavailableError
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_pen_and_window(monkeypatch: pytest.MonkeyPatch) -> tuple[FakePen, FakeWindow]:
|
||||
"""Replace the turtle window and pen of the command line with fakes."""
|
||||
pen = FakePen()
|
||||
window = FakeWindow()
|
||||
|
||||
def create_fake_window() -> Window:
|
||||
return window
|
||||
|
||||
def create_fake_pen() -> Pen:
|
||||
return pen
|
||||
|
||||
monkeypatch.setattr(cli, "create_window", create_fake_window)
|
||||
monkeypatch.setattr(cli, "create_pen", create_fake_pen)
|
||||
return pen, window
|
||||
|
||||
|
||||
def test_every_challenge_name_has_a_challenge() -> None:
|
||||
challenges = cli.build_challenges(FakePen())
|
||||
|
||||
assert set(challenges) == set(CHALLENGE_NAMES)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", CHALLENGE_NAMES)
|
||||
def test_parser_accepts_every_challenge_name(name: str) -> None:
|
||||
args = cli.build_parser().parse_args([name])
|
||||
|
||||
assert args.challenge == name
|
||||
|
||||
|
||||
def test_parser_rejects_an_unknown_challenge(
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
with pytest.raises(SystemExit) as exit_info:
|
||||
cli.build_parser().parse_args(["triangle"])
|
||||
|
||||
assert exit_info.value.code == 2
|
||||
assert "invalid choice" in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_help_lists_every_challenge(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
with pytest.raises(SystemExit) as exit_info:
|
||||
cli.build_parser().parse_args(["--help"])
|
||||
|
||||
assert exit_info.value.code == 0
|
||||
output = capsys.readouterr().out
|
||||
assert all(name in output for name in CHALLENGE_NAMES)
|
||||
|
||||
|
||||
def test_main_runs_the_square_and_waits_for_a_click(
|
||||
fake_pen_and_window: tuple[FakePen, FakeWindow],
|
||||
) -> None:
|
||||
pen, window = fake_pen_and_window
|
||||
|
||||
status = cli.main(["square"])
|
||||
|
||||
assert status == 0
|
||||
assert len(pen.args_of("forward")) == SQUARE_SIDES
|
||||
assert window.waited_for_click
|
||||
|
||||
|
||||
def test_main_runs_the_dashed_line(
|
||||
fake_pen_and_window: tuple[FakePen, FakeWindow],
|
||||
) -> None:
|
||||
pen, _ = fake_pen_and_window
|
||||
|
||||
cli.main(["dashed-line"])
|
||||
|
||||
assert len(pen.args_of("forward")) == 2 * DASH_COUNT
|
||||
|
||||
|
||||
def test_main_reports_a_missing_turtle_and_exits_with_status_1(
|
||||
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
def fail() -> Window:
|
||||
raise TurtleUnavailableError("no Tk here")
|
||||
|
||||
monkeypatch.setattr(cli, "create_window", fail)
|
||||
|
||||
with pytest.raises(SystemExit) as exit_info:
|
||||
cli.main(["square"])
|
||||
|
||||
assert exit_info.value.code == 1
|
||||
assert "no Tk here" in capsys.readouterr().err
|
||||
@@ -0,0 +1,5 @@
|
||||
from turtle_challenges import constants
|
||||
|
||||
|
||||
def test_challenge_names_are_unique() -> None:
|
||||
assert len(set(constants.CHALLENGE_NAMES)) == len(constants.CHALLENGE_NAMES)
|
||||
Reference in New Issue
Block a user