"""Smoke-Test: Die echte Hauptschleife läuft einige Sekunden headless mit Zufallseingaben. Ein simulierter, zufällig klickender "Affe" bedient dabei alles, was ein Mensch auch bedienen könnte: Klicks in Welt und Sidebar, Ziehen und Werfen, Rechtsklicks, Mausrad und Tastenkürzel. Der Test gilt als bestanden, wenn keine Exception auftritt und die Simulation danach in einem gültigen Zustand ist. """ import random import pygame import pytest from sandbox.config import PHYSICS from sandbox.main import App SMOKE_SECONDS = 3.0 SAFE_KEYS = ("space", "g", "c", "delete", "1", "2", "f1") # alles außer "Beenden" class MonkeyApp(App): """Die echte Anwendung, die sich vor jedem Frame selbst zufällige Events schickt.""" def __init__(self, seed: int) -> None: super().__init__(rng=random.Random(seed)) self.monkey = random.Random(seed) self.frame_count = 0 def frame(self, frame_time: float) -> None: self._post_random_events() super().frame(frame_time) self.frame_count += 1 def _random_position(self) -> tuple[int, int]: return ( self.monkey.randrange(self.config.window.width), self.monkey.randrange(self.config.window.height), ) def _post_random_events(self) -> None: roll = self.monkey.random() position = self._random_position() if roll < 0.25: button = self.monkey.choice([pygame.BUTTON_LEFT, pygame.BUTTON_RIGHT]) pygame.event.post( pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=position, button=button) ) elif roll < 0.45: pygame.event.post(pygame.event.Event(pygame.MOUSEBUTTONUP, pos=position, button=1)) elif roll < 0.85: pygame.event.post( pygame.event.Event(pygame.MOUSEMOTION, pos=position, rel=(0, 0), buttons=(1, 0, 0)) ) elif roll < 0.93: pygame.event.post( pygame.event.Event(pygame.MOUSEWHEEL, x=0, y=self.monkey.choice([-1, 1])) ) else: key = pygame.key.key_code(self.monkey.choice(SAFE_KEYS)) pygame.event.post( pygame.event.Event(pygame.KEYDOWN, key=key, mod=0, unicode="", scancode=0) ) @pytest.mark.slow def test_main_loop_survives_seconds_of_random_input() -> None: app = MonkeyApp(seed=7) try: app.load_demo_scene() app.run(max_seconds=SMOKE_SECONDS) assert app.running assert app.frame_count > 0 for body in app.world.bodies: assert body.position.is_finite() assert body.velocity.length() <= PHYSICS.max_speed + 1e-6 finally: app.close()