roverdevkit / tests /conftest.py
jjreif's picture
Deploy roverdevkit @ 2676a67
b3d14e3
Raw
History Blame Contribute Delete
3.12 kB
"""Shared pytest fixtures.
Session-scoped fixtures cache expensive evaluator runs across modules so
the integration suites (real-rover validation) don't re-run the same
physics dozens of times.
"""
from __future__ import annotations
import pytest
from roverdevkit.schema import DesignVector, MissionScenario
from roverdevkit.validation.rover_comparison import (
ComparisonSummary,
RoverComparisonResult,
compare_all,
compare_one,
)
from roverdevkit.validation.rover_registry import flown_registry, registry_by_name
@pytest.fixture
def rashid_like_design() -> DesignVector:
"""A Rashid-like design vector for tests and worked examples.
Numbers chosen to match published Rashid specs where available
(see the Rashid registry entry and data/mass_validation_set.csv)
and reasonable defaults otherwise.
"""
return DesignVector(
wheel_radius_m=0.1,
wheel_width_m=0.06,
grouser_height_m=0.005,
grouser_count=12,
n_wheels=4,
chassis_mass_kg=6.0,
wheelbase_m=0.35,
solar_area_m2=0.4,
battery_capacity_wh=100.0,
avionics_power_w=15.0,
peak_wheel_torque_nm=1.5,
)
@pytest.fixture
def equatorial_scenario() -> MissionScenario:
return MissionScenario(
name="equatorial_mare_traverse",
latitude_deg=20.2,
traverse_distance_m=5000.0,
terrain_class="mare_nominal",
soil_simulant="Apollo_regolith_nominal",
mission_duration_earth_days=14.0,
max_slope_deg=15.0,
sun_geometry="diurnal",
operational_duty_cycle=0.30,
)
# ---------------------------------------------------------------------------
# Session-scoped evaluator caches
# ---------------------------------------------------------------------------
# These fixtures run the evaluator once per test session and let every
# downstream test consume the same precomputed results. They are pure
# (no test-induced state); reusing them across tests is safe because the
# evaluator is deterministic. If a test needs a *different* evaluator
# call, it should not depend on these fixtures and pay its own cost.
@pytest.fixture(scope="session")
def rover_compare_summary() -> ComparisonSummary:
"""Cached :func:`compare_all` output (one evaluator run per rover)."""
return compare_all()
@pytest.fixture(scope="session")
def rover_compare_results(
rover_compare_summary: ComparisonSummary,
) -> dict[str, RoverComparisonResult]:
"""Per-rover comparison results from the cached summary."""
return {r.rover_name: r for r in rover_compare_summary.results}
@pytest.fixture(scope="session")
def registered_rover_names() -> list[str]:
"""Stable list of rover names (the parametrize ids)."""
return [e.rover_name for e in flown_registry()]
# ``registry_by_name`` and ``compare_one`` are module-level helpers; we
# re-export them as symbols so tests can keep their existing call sites
# without changing imports during the refactor. They're intentionally
# *not* fixtures (they take arguments).
__all__ = ["compare_one", "registry_by_name"]