moons 0.0.3

Moon celestial simulation crate for the MilkyWay SolarSystem workspace
Documentation
use moons::rendering::dust::DustScattering;
use moons::rendering::exosphere::ExosphereEndpoint;
use moons::rendering::materials::PbrMaterial;
use moons::rendering::shaders::{ShaderEndpoint, UniformValue};

fn ensure_earth_binary() {
    let earth = moons::interactions::earths::ensure_earths_binary_or_simulate();
    assert!(earth.rotation_period_h > 23.0);
}

// ── dust ──

#[test]
fn dust_horizon_glow_opacity_positive() {
    ensure_earth_binary();
    let d = DustScattering::horizon_glow();
    assert!(d.opacity_at_height(0.0) > 0.0);
}

#[test]
fn dust_opacity_decreases_with_height() {
    ensure_earth_binary();
    let d = DustScattering::horizon_glow();
    assert!(d.opacity_at_height(10_000.0) < d.opacity_at_height(0.0));
}

// ── materials ──

#[test]
fn regolith_is_rougher_than_ice() {
    ensure_earth_binary();
    assert!(PbrMaterial::regolith().roughness > PbrMaterial::polar_ice().roughness);
}

#[test]
fn mare_basalt_darker_than_regolith() {
    ensure_earth_binary();
    assert!(PbrMaterial::mare_basalt().albedo[0] < PbrMaterial::regolith().albedo[0]);
}

#[test]
fn polar_ice_high_albedo() {
    ensure_earth_binary();
    let m = PbrMaterial::polar_ice();
    assert!(m.albedo[0] > 0.7);
    assert!(m.roughness < 0.5);
}

// ── exosphere ──

#[test]
fn exosphere_species_count() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    assert_eq!(exo.species.len(), 6);
}

#[test]
fn exosphere_body_radius() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    assert!((exo.body_radius_m - moons::MOON_RADIUS_M).abs() < 1.0);
}

#[test]
fn exosphere_helium_density_decreases() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    let d0 = exo.density_at_altitude("He", 0.0);
    let d100 = exo.density_at_altitude("He", 100_000.0);
    assert!(d0 > d100);
    assert!(d0 > 0.0);
}

#[test]
fn exosphere_argon_dominant_column() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    let ar = exo.species.iter().find(|s| s.symbol == "Ar").unwrap();
    let he = exo.species.iter().find(|s| s.symbol == "He").unwrap();
    assert!(ar.column_density_m2 > he.column_density_m2);
}

#[test]
fn exosphere_total_column_density() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    let total = exo.total_column_density();
    assert!(total > 1e14);
}

#[test]
fn exosphere_sodium_glow() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    let glow = exo.sodium_glow_intensity();
    assert!(glow > 0.0);
    assert!(glow <= 1.0);
}

#[test]
fn exosphere_unknown_species_zero() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    assert_eq!(exo.density_at_altitude("Xe", 0.0), 0.0);
}

#[test]
fn exosphere_molar_mass_positive() {
    ensure_earth_binary();
    let exo = ExosphereEndpoint::moon();
    for sp in &exo.species {
        assert!(
            sp.molar_mass_kg_mol > 0.0,
            "species {} has non-positive molar mass",
            sp.name
        );
    }
}

// ── shaders ──

#[test]
fn terrain_shader_name() {
    ensure_earth_binary();
    let s = ShaderEndpoint::terrain();
    assert_eq!(s.name, "moon_terrain_pbr");
    assert!(s.uniforms.len() >= 6);
}

#[test]
fn terrain_shader_has_radius_uniform() {
    ensure_earth_binary();
    let s = ShaderEndpoint::terrain();
    let radius_u = s
        .uniforms
        .iter()
        .find(|u| u.name == "u_planet_radius")
        .unwrap();
    match radius_u.value {
        UniformValue::Float(v) => assert!(v > 1e6),
        _ => panic!("expected Float"),
    }
}

#[test]
fn eclipse_shader_name() {
    ensure_earth_binary();
    let s = ShaderEndpoint::eclipse();
    assert_eq!(s.name, "moon_eclipse");
    assert!(s.uniforms.len() >= 3);
}

#[test]
fn eclipse_shader_lower_exposure() {
    ensure_earth_binary();
    let t = ShaderEndpoint::terrain();
    let e = ShaderEndpoint::eclipse();
    let t_flux = t
        .uniforms
        .iter()
        .find(|u| u.name == "u_solar_flux")
        .unwrap();
    let e_exp = e.uniforms.iter().find(|u| u.name == "u_exposure").unwrap();
    match (&t_flux.value, &e_exp.value) {
        (UniformValue::Float(flux), UniformValue::Float(exp)) => {
            assert!(flux > exp);
        }
        _ => panic!("expected Floats"),
    }
}

#[test]
fn exosphere_shader_name() {
    ensure_earth_binary();
    let s = ShaderEndpoint::exosphere();
    assert_eq!(s.name, "moon_exosphere");
    assert!(s.uniforms.len() >= 3);
}

#[test]
fn exosphere_shader_sodium_color() {
    ensure_earth_binary();
    let s = ShaderEndpoint::exosphere();
    let na = s
        .uniforms
        .iter()
        .find(|u| u.name == "u_sodium_color")
        .unwrap();
    match na.value {
        UniformValue::Vec3(c) => {
            assert!(c[0] > 0.9);
            assert!(c[1] > 0.5);
        }
        _ => panic!("expected Vec3"),
    }
}