# Test Refactoring Optimization Strategy ## Tooling - `scripts/sim_engine.py` — Generic orbital mechanics simulator (Python, TOML 1.0 configs) - Replicates C++ physics: Kepler propagation, orbital↔Cartesian transforms, drift detection - Multi-body hierarchical propagation with global/local coordinate tracking - Use for precalculating expected values (transition times, final states, energy conservation) - TOML configs in `tests/` must use TOML 1.0 inline table syntax (single-line `{}`) - Old configs in `old_tests/` use multiline inline tables (toml-c17 style) — keep for reference - Python's `tomllib` requires single-line inline tables ## Sim Engine Capabilities ### Implemented - Body propagation (elliptical + parabolic via Barker's equation) - Orbital↔Cartesian transforms (full z-x-z Euler rotation) - Velocity drift detection and element reconstruction - Global coordinate computation (hierarchical parent→child) - Spacecraft struct, loading, propagation - Impulsive burns (prograde, retrograde, normal, antinormal, radial_in, radial_out, custom) - TOML 1.0 config parsing ### NOT Implemented (notify the user before beginning to refactor) - SOI transitions - Maneuver trigger system (TRIGGER_TIME, TRIGGER_TRUE_ANOMALY) - Hohmann transfer calculations - Rendezvous planning - OrbitTracker - Energy functions (KE, PE, total) - Hyperbolic propagation ## Refactoring Rules ### 1. Structure - One `SCENARIO("description")` per logical test group, with `[tag1][tag2]` annotations - Shared fixture: all constants, structs, and variables declared between `SCENARIO` opening and first `SECTION` - Precompute expected values analytically at fixture level (use `scripts/*.py` for complex simulations) ### 2. Duplication Elimination - Use lambdas that capture the fixture for repeated setup→call→assert patterns - Reuse shared structs in-place (mutate fields rather than recreating) - Single-line `SECTION`s when body is one statement: `SECTION("name") { helper(arg); }` ### 3. Assertions - `using Catch::Matchers::WithinAbs;` after includes - `REQUIRE_THAT(value, WithinAbs(expected, tolerance))` — never `Approx()` - **Always use named tolerance constants** — never hardcode raw numbers in `WithinAbs()`. #### Tolerance Reference | Constant | Value | Use for | |----------|-------|---------| | `A_TOL` | `1e-6` | Semi-major axis (meters) | | `E_TOL` | `1e-12` | Eccentricity | | `ANG_TOL` | `1e-12` | Angles (true anomaly, inclination, Ω, ω) — round-trip precision | | `ANG_TOL_COARSE` | `1e-4` | Angles — degenerate cases (polar/equatorial orbits, near-180° inclination) | | `R_TOL` | `1e-6` | Radius / distance magnitudes | | `V_TOL` | `1e-6` | Velocity magnitudes | | `M_TOL` | `1e-6` | Time / period values | - Declare tolerance constants in the fixture (between `SCENARIO` opening and first `SECTION`) - Tighten aggressively: if observed error is `1e-8`, use `1e-6` (two orders of margin) - Replace qualitative checks (`a > b`) with quantitative (`WithinAbs(expected, tol)`) - `INFO("label: " << value)` for debugging context ### 4. Precalc Scripts - For each test file, create `scripts/precalc_.py` that computes expected values. - **Check the capability matrix first** — only use sim_engine.py for implemented features. - **Always output local-frame values** (distances from parent, not global from origin). - C++ tests typically use local coordinates (e.g., `vec3_distance(craft->local_position, (Vec3){0,0,0})`). - Global distances are dominated by parent body positions (e.g., Earth-Sun distance swamps LEO orbit). - Output C++-style comments with precalculated constants for embedding in the test. - Run with: `python3 scripts/precalc_.py` - If sim_engine.py lacks a feature, use analytical formulas instead (**but notify the user what feature was missing**) ## Refactoring Procedure ### Step 1: Refactor - Verify the test file has a TOML config in `old_tests/`. If it doesn't, skip — it's likely hardcoded. - Check if the test is already in `tests/` (already refactored). Skip if so. - Check the capability matrix — if the test needs SOI, maneuvers, rendezvous, etc., flag this before starting. - Process **one test file at a time**. - Create `scripts/precalc_.py` and run it to get expected values. - Copy from `old_tests/` to `tests/`, rewrite using the pattern from `test_true_anomaly_roundtrip.cpp`. - Rewrite TOML configs to TOML 1.0 inline table syntax (single-line `{}`). - Follow all rules in sections 1-4 above. ### Step 2: Tighten Tolerances - Build and verify: `make test-build` then `./build/orbit_test '[tag]' -s`. - Run full suite: `make test`. - Review every tolerance against actual observed errors from `-s` output. - If a constant's margin is too loose (e.g., `1e-6` when error is `1e-10`), tighten to `1e-8`. - **If a test fails due to a tolerance being too tight, report the observed error to the user and ask whether to loosen the constant or investigate the root cause. Never silently widen a tolerance.** - Refer to the tolerance reference table in Section 3 for constant names. ### Step 3: Code Review - Remove unused includes (only include what's actually used). - Remove unused variables (e.g., `const double mu = G * M_sun;` if never referenced). - Look for repeated initialization patterns — extract into helper lambdas (`make_elements`, `convert_and_recover`). - Use `const` for all fixture data and recovered results. - Replace C-style arrays with `std::array` where appropriate. - Ensure consistent tolerance usage (no hardcoded `1e-4` when `ANG_TOL_COARSE` exists). - Check for `compare_vec3` availability in `test_utilities` instead of 6 individual `REQUIRE_THAT` calls. - Run full suite again: `make test`. - **Always ask for review** before moving to the next file. - **Only commit when asked.** ## Test Refactoring Status ### Completed - `test_barkers_equation` ✅ — Barker's equation unit tests + parabolic propagation - `test_cartesian_to_elements_advanced` ✅ — Advanced conversion tests (eccentricity spectrum, inclination, true anomaly, 3D orientation) - `test_cartesian_to_elements_basic` ✅ — Element round-trip conversion (semi-major axis, eccentricity, true anomaly, inclination, radius, velocity) - `test_parabolic_orbit` ✅ — Parabolic orbit energy conservation + escape trajectory + initial conditions ### Sim Engine Fix Applied - Added `semi_latus_rectum` → `OrbitalElements.p` mapping in `bodies_from_config()` and `spacecraft_from_config()` (needed for parabolic orbit configs) ### Can Refactor Now (sim_engine.py supports all features needed) - `test_extreme_eccentricity` — high-eccentricity orbits - `test_extreme_orientation_mixed` — extreme inclinations/eccentricities - `test_extreme_timescales` — various timescales - `test_analytical_propagation` — propagation through apsides - `test_moon_orbits` — multi-body propagation - `test_periapsis_burn` — prograde burns - `test_hybrid_burns` — impulse burns - `test_omega_debug` — burn + element reconstruction ### Blocked on Missing Features - `test_soi_transition` — needs SOI transitions - `test_root_body_transitions` — needs SOI transitions - `test_maneuver_planning` — needs maneuver trigger system - `test_hybrid_energy_conservation` — needs energy functions (KE, PE, total) - `test_hyperbolic_orbit` — needs hyperbolic propagation - `test_rendezvous` — needs Hohmann transfer calculations ### Skip (Hardcoded / No TOML) - `test_integration` — hardcoded vector tests, no TOML config