Spaces:
Running
Running
| """Tests for the mission-scenario YAML loader.""" | |
| from __future__ import annotations | |
| import pytest | |
| from roverdevkit.mission.scenarios import list_scenarios, load_scenario | |
| from roverdevkit.schema import MissionScenario | |
| from roverdevkit.terramechanics.soils import list_soil_simulants | |
| EXPECTED_SCENARIOS = { | |
| "equatorial_mare_traverse", | |
| "polar_prospecting", | |
| "highland_slope_capability", | |
| "crater_rim_survey", | |
| } | |
| def test_list_scenarios_returns_all_four_canonical_scenarios() -> None: | |
| names = set(list_scenarios()) | |
| missing = EXPECTED_SCENARIOS - names | |
| assert not missing, f"missing scenarios: {missing}" | |
| def test_load_scenario_round_trips_to_pydantic_model(name: str) -> None: | |
| scenario = load_scenario(name) | |
| assert isinstance(scenario, MissionScenario) | |
| assert scenario.name == name | |
| def test_soil_simulant_in_every_scenario_is_in_the_catalogue(name: str) -> None: | |
| # The traverse sim resolves soil names via the catalogue; if a | |
| # scenario references an unknown simulant the evaluator will crash | |
| # later. Catch it at config-load time. | |
| scenario = load_scenario(name) | |
| assert scenario.soil_simulant in list_soil_simulants() | |
| def test_unknown_scenario_raises_file_not_found() -> None: | |
| with pytest.raises(FileNotFoundError, match="scenario config"): | |
| load_scenario("nonexistent_scenario") | |
| def test_equatorial_scenario_has_expected_fields() -> None: | |
| s = load_scenario("equatorial_mare_traverse") | |
| assert s.latitude_deg == pytest.approx(20.2) | |
| assert s.mission_duration_earth_days == pytest.approx(14.0) | |
| assert s.traverse_distance_m > 0 | |
| def test_polar_scenario_has_high_latitude() -> None: | |
| s = load_scenario("polar_prospecting") | |
| assert abs(s.latitude_deg) >= 70.0 | |
| assert s.sun_geometry == "polar_intermittent" | |
| # --------------------------------------------------------------------------- | |
| # Schema v6 (v6 schema update): operational_duty_cycle calibration on YAMLs | |
| # --------------------------------------------------------------------------- | |
| # Pin the four canonical scenarios to the calibration agreed in | |
| # data/analytical/SCHEMA.md so an accidental YAML edit doesn't | |
| # silently shift the surrogate's training distribution. Mare 0.30, | |
| # crater 0.20, highland 0.15, polar 0.05 — see decision.md §"δ_ops | |
| # calibration" for the published-rover-anchored derivation. | |
| _EXPECTED_DOPS = { | |
| "equatorial_mare_traverse": 0.30, | |
| "crater_rim_survey": 0.20, | |
| "highland_slope_capability": 0.15, | |
| "polar_prospecting": 0.05, | |
| } | |
| def test_canonical_scenario_operational_duty_cycle_matches_calibration( | |
| name: str, expected: float | |
| ) -> None: | |
| """``operational_duty_cycle`` on each canonical scenario YAML matches | |
| the v6 schema update calibration. Catch silent YAML drift before it | |
| contaminates the LHS dataset.""" | |
| s = load_scenario(name) | |
| assert s.operational_duty_cycle == pytest.approx(expected, abs=1e-9), ( | |
| f"{name}: operational_duty_cycle drifted from the schema-v7 calibration" | |
| ) | |