astrora_core 0.1.1

Astrora - Rust-backed astrodynamics library - core computational components
Documentation
"""
Verification tests for pytest fixtures and test infrastructure.

This test file validates that the testing infrastructure from conftest.py
and test_utils.py is working correctly.
"""

import numpy as np
import pytest

from tests.test_utils import (
    assert_angular_momentum_conserved,
    assert_energy_conserved,
    assert_states_equal,
    classify_orbit_regime,
    compute_specific_energy,
    is_circular_orbit,
)


@pytest.mark.unit
class TestFixtures:
    """Test that shared fixtures work correctly."""

    def test_earth_params_fixture(self, earth_params):
        """Test Earth parameters fixture."""
        assert earth_params["gm"] > 0
        assert earth_params["radius"] > 0
        assert earth_params["j2"] > 0
        assert earth_params["angular_velocity"] > 0

    def test_numerical_tolerances_fixture(self, numerical_tolerances):
        """Test numerical tolerances fixture."""
        assert "position_m" in numerical_tolerances
        assert "velocity_m_s" in numerical_tolerances
        assert numerical_tolerances["position_m"] > 0
        assert numerical_tolerances["validation_position_m"] > numerical_tolerances["position_m"]

    def test_standard_epochs_fixture(self, standard_epochs):
        """Test standard epochs fixture."""
        assert "j2000" in standard_epochs
        assert "year_2025" in standard_epochs

    def test_leo_state_fixture(self, leo_state, earth_params):
        """Test LEO state fixture."""
        # Check that it's actually an orbit
        pos = np.array(leo_state.position)
        vel = np.array(leo_state.velocity)
        r = np.linalg.norm(pos)
        v = np.linalg.norm(vel)

        assert r > earth_params["radius"]
        assert r < earth_params["radius"] + 1e6  # Should be < 1000 km altitude
        assert v > 7000  # Should be orbital velocity

        # Check it's a valid orbit with negative energy
        energy = compute_specific_energy(leo_state, earth_params["gm"])
        assert energy < 0  # Bound orbit

    def test_geo_state_fixture(self, geo_state, earth_params):
        """Test GEO state fixture."""
        pos = np.array(geo_state.position)
        r = np.linalg.norm(pos)

        # GEO should be at ~42,164 km radius
        assert 42e6 < r < 43e6

    def test_circular_equatorial_elements_fixture(self, circular_equatorial_elements):
        """Test circular equatorial elements fixture."""
        assert is_circular_orbit(circular_equatorial_elements.e)
        assert abs(circular_equatorial_elements.i) < 1e-6

    def test_test_arrays_fixtures(self, test_true_anomalies, test_eccentricities):
        """Test that test array fixtures have expected properties."""
        assert len(test_true_anomalies) > 0
        assert test_true_anomalies[0] >= 0
        assert test_true_anomalies[-1] <= 2 * np.pi

        assert len(test_eccentricities) > 0
        assert all(0 <= e < 1 for e in test_eccentricities)


@pytest.mark.unit
class TestTestUtils:
    """Test utility functions from test_utils.py."""

    def test_assert_states_equal_identical(self, leo_state):
        """Test that identical states pass comparison."""
        # Should not raise
        assert_states_equal(leo_state, leo_state, position_tol=1e-6, velocity_tol=1e-9)

    def test_assert_states_equal_different(self, leo_state, geo_state):
        """Test that different states fail comparison."""
        with pytest.raises(AssertionError):
            assert_states_equal(leo_state, geo_state, position_tol=1e-6, velocity_tol=1e-9)

    def test_compute_specific_energy_negative_for_bound_orbit(self, leo_state, earth_params):
        """Test that bound orbits have negative energy."""
        energy = compute_specific_energy(leo_state, earth_params["gm"])
        assert energy < 0

    def test_energy_conservation_same_state(self, leo_state, earth_params):
        """Test that energy is conserved for same state."""
        # Should not raise
        assert_energy_conserved(leo_state, leo_state, earth_params["gm"], rtol=1e-10)

    def test_angular_momentum_conservation_same_state(self, leo_state):
        """Test that angular momentum is conserved for same state."""
        # Should not raise
        assert_angular_momentum_conserved(leo_state, leo_state, rtol=1e-10)

    def test_classify_orbit_regime(self, earth_params):
        """Test orbit regime classification."""
        r_earth = earth_params["radius"]

        leo_a = r_earth + 400e3
        assert classify_orbit_regime(leo_a, r_earth) == "LEO"

        geo_a = r_earth + 35786e3
        assert classify_orbit_regime(geo_a, r_earth) == "GEO"

        meo_a = r_earth + 20200e3
        assert classify_orbit_regime(meo_a, r_earth) == "MEO"

    def test_is_circular_orbit(self):
        """Test circular orbit detection."""
        assert is_circular_orbit(0.0)
        assert is_circular_orbit(1e-7)
        assert not is_circular_orbit(0.1)


@pytest.mark.unit
class TestMarkerAssignment:
    """Verify that pytest markers are assigned correctly."""

    def test_this_should_have_unit_marker(self):
        """This test should automatically get the unit marker."""
        # Just a placeholder to verify marker assignment
        pass


@pytest.mark.slow
@pytest.mark.validation
def test_slow_validation_markers():
    """Test that multiple markers can be applied."""
    # This test has both slow and validation markers
    pass