| """Animation kit: deterministic pieces, and the bell theater resolving.""" |
|
|
| from __future__ import annotations |
|
|
| import random |
|
|
| from scrypt.ui import fx |
|
|
|
|
| def test_reduced_motion_reads_env(monkeypatch): |
| monkeypatch.setenv("SCRYPT_REDUCED_MOTION", "1") |
| assert fx.reduced_motion() |
| monkeypatch.setenv("SCRYPT_REDUCED_MOTION", "0") |
| assert not fx.reduced_motion() |
| monkeypatch.delenv("SCRYPT_REDUCED_MOTION") |
| assert not fx.reduced_motion() |
|
|
|
|
| def test_noise_and_corrupt_keep_shape(): |
| line = fx.noise_line(40, random.Random(1)) |
| assert len(line) == 40 |
| text = "the scale is honest" |
| glitched = fx.corrupt(text, fraction=0.5, rng=random.Random(2)) |
| assert len(glitched) == len(text) |
| assert glitched != text |
|
|
|
|
| def test_eye_tracks_blinks_and_widens(): |
| assert fx.eye(0, 5) == fx.EYE_FRAMES[0] |
| assert fx.eye(4, 5) == fx.EYE_FRAMES[-1] |
| assert fx.eye(2, 5, blink=True) == fx.EYE_BLINK |
| assert fx.eye(0, 1, wide=True) == fx.EYE_WIDE |
| assert fx.eye(0, 1) == fx.EYE_FRAMES[2] |
|
|
|
|
| def test_boardfx_empty(): |
| assert fx.BoardFX().empty |
| assert not fx.BoardFX(flash={("foe", 1)}).empty |
| assert not fx.BoardFX(scale=2).empty |
|
|
|
|
| async def test_bell_theater_resolves_combat(monkeypatch): |
| """With frames collapsed to zero delay, the theater path must reach the |
| same end state as the instant path: bell rung, fx cleared, input back.""" |
| from scrypt.app import ScryptApp |
| from scrypt.ui.board import BoardScreen |
|
|
| async def instant_frame(self, dt): |
| self.refresh_all() |
|
|
| async def no_glitch(self): |
| pass |
|
|
| monkeypatch.setenv("SCRYPT_REDUCED_MOTION", "0") |
| monkeypatch.setattr(BoardScreen, "_frame", instant_frame) |
| monkeypatch.setattr(BoardScreen, "_glitch", no_glitch) |
|
|
| app = ScryptApp(seed=11, skip_menu=True) |
| async with app.run_test() as pilot: |
| await pilot.pause() |
| screen = app.screen |
| assert isinstance(screen, BoardScreen) |
| state = screen.state |
| await pilot.press("s") |
| turn_before = state.turn |
| await pilot.press("b") |
| for _ in range(40): |
| await pilot.pause() |
| if not screen._animating and state.turn > turn_before: |
| break |
| assert state.turn > turn_before |
| assert screen._fx.empty |
| assert not screen._animating |
|
|