Spaces:
Running
Running
| """Tests for the expression -> movement planner. | |
| The planner is pure logic (no robot SDK), so it is fully unit-testable. We | |
| inject a seeded RNG to make the "random" movement selection deterministic. | |
| """ | |
| import random | |
| import pytest | |
| from face_detection.behavior import Movement, MovementPlanner | |
| def test_known_expressions_have_movements(): | |
| planner = MovementPlanner() | |
| for expression in ("happy", "neutral"): | |
| move = planner.plan(expression) | |
| assert isinstance(move, Movement) | |
| assert move.duration > 0 | |
| def test_unknown_expression_falls_back_to_neutral(): | |
| planner = MovementPlanner(rng=random.Random(0)) | |
| fallback = planner.plan("does-not-exist") | |
| assert fallback in planner.movements_for("neutral") | |
| def test_selection_is_deterministic_with_seeded_rng(): | |
| a = MovementPlanner(rng=random.Random(42)).plan("happy") | |
| b = MovementPlanner(rng=random.Random(42)).plan("happy") | |
| assert a == b | |
| def test_selection_varies_across_seeds_for_multi_option_expression(): | |
| planner = MovementPlanner(rng=random.Random(123)) | |
| picks = {planner.plan("happy").description for _ in range(50)} | |
| # "happy" defines more than one movement, so we expect variety. | |
| assert len(picks) > 1 | |
| def test_idle_movement_available(): | |
| planner = MovementPlanner() | |
| idle = planner.idle() | |
| assert isinstance(idle, Movement) | |
| def test_movement_fields_are_within_safe_ranges(): | |
| planner = MovementPlanner() | |
| for expression in planner.expressions: | |
| for move in planner.movements_for(expression): | |
| if move.antennas is not None: | |
| left, right = move.antennas | |
| assert -1.5 <= left <= 1.5 | |
| assert -1.5 <= right <= 1.5 | |
| if move.body_yaw is not None: | |
| assert -1.0 <= move.body_yaw <= 1.0 | |
| assert 0.1 <= move.duration <= 5.0 | |