use mercurys::physics::collisions::{
Impactor, MEAN_IMPACT_SPEED_KM_S, MERCURY_SURFACE_DENSITY, caloris_basin_diameter,
caloris_impactor, simple_complex_transition_m, typical_microimpact,
};
use mercurys::physics::orbit::{ECCENTRICITY, MERCURY_MASS, MERCURY_RADIUS, MercuryOrbit};
use mercurys::physics::rotation::MercuryRotation;
use mercurys::physics::tides::{
SolarTide, bulge_variation, perihelion_aphelion_tide_ratio, spin_orbit_resonance,
tidal_dissipation_rate, tidal_locking_timescale,
};
#[test]
fn orbital_period_about_88_days() {
let o = MercuryOrbit::new();
let days = o.orbital_period_days();
assert!((days - 87.969).abs() < 1.0);
}
#[test]
fn perihelion_lt_aphelion() {
let o = MercuryOrbit::new();
assert!(o.perihelion_m() < o.aphelion_m());
}
#[test]
fn eccentricity_about_0_206() {
assert!((ECCENTRICITY - 0.2056).abs() < 0.01);
}
#[test]
fn escape_velocity_about_4250() {
let v = MercuryOrbit::escape_velocity_at_surface();
assert!((v - 4250.0).abs() < 200.0);
}
#[test]
fn mean_motion_positive() {
let o = MercuryOrbit::new();
assert!(o.mean_motion() > 0.0);
}
#[test]
fn specific_orbital_energy_negative() {
let o = MercuryOrbit::new();
assert!(o.specific_orbital_energy() < 0.0);
}
#[test]
fn specific_angular_momentum_positive() {
let o = MercuryOrbit::new();
assert!(o.specific_angular_momentum() > 0.0);
}
#[test]
fn mean_orbital_velocity_about_47km() {
let o = MercuryOrbit::new();
let v = o.mean_orbital_velocity();
assert!((v - 47360.0).abs() < 1000.0);
}
#[test]
fn velocity_higher_at_perihelion() {
let o = MercuryOrbit::new();
let vp = o.velocity_at_distance(o.perihelion_m());
let va = o.velocity_at_distance(o.aphelion_m());
assert!(vp > va);
}
#[test]
fn gravitational_force_sun_positive() {
let o = MercuryOrbit::new();
assert!(o.gravitational_force_sun() > 0.0);
}
#[test]
fn position_tuple_finite() {
let o = MercuryOrbit::new();
let (x, y, z) = o.position();
assert!(x.is_finite() && y.is_finite() && z.is_finite());
}
#[test]
fn position_distance_matches_radius() {
let o = MercuryOrbit::new();
let (x, y, z) = o.position();
let dist = (x * x + y * y + z * z).sqrt();
let radius = o.current_radius();
assert!((dist - radius).abs() / radius < 0.01);
}
#[test]
fn solar_irradiance_positive() {
let o = MercuryOrbit::new();
assert!(o.solar_irradiance() > 0.0);
}
#[test]
fn gr_precession_positive() {
let o = MercuryOrbit::new();
assert!(o.gr_perihelion_precession_rad_per_orbit() > 0.0);
}
#[test]
fn step_advances_anomaly() {
let mut o = MercuryOrbit::new();
let ma_before = o.mean_anomaly_rad;
o.step(86400.0);
assert!(o.mean_anomaly_rad != ma_before);
}
#[test]
fn at_mean_anomaly_sets_true_anomaly() {
let o = MercuryOrbit::at_mean_anomaly(1.0);
assert!(o.true_anomaly_rad.is_finite());
assert!(o.true_anomaly_deg().is_finite());
}
#[test]
fn mercury_mass_about_3e23() {
assert!((MERCURY_MASS - 3.3011e23).abs() < 1.0e22);
}
#[test]
fn mercury_radius_about_2440km() {
assert!((MERCURY_RADIUS - 2_439_700.0).abs() < 10_000.0);
}
#[test]
fn spin_orbit_3_to_2() {
let (n, d) = MercuryRotation::spin_orbit_ratio();
assert_eq!((n, d), (3, 2));
}
#[test]
fn surface_velocity_at_equator_positive() {
let r = MercuryRotation::new();
assert!(r.surface_velocity_at_latitude(0.0) > 0.0);
}
#[test]
fn surface_velocity_decreases_with_lat() {
let r = MercuryRotation::new();
assert!(r.surface_velocity_at_latitude(0.0) > r.surface_velocity_at_latitude(60.0));
}
#[test]
fn coriolis_parameter_finite() {
let r = MercuryRotation::new();
assert!(r.coriolis_parameter(45.0).is_finite());
}
#[test]
fn centripetal_acceleration_positive() {
let r = MercuryRotation::new();
assert!(r.centripetal_acceleration_at_latitude(0.0) > 0.0);
}
#[test]
fn moment_of_inertia_positive() {
let r = MercuryRotation::new();
assert!(r.moment_of_inertia() > 0.0);
}
#[test]
fn rotational_ke_positive() {
let r = MercuryRotation::new();
assert!(r.rotational_kinetic_energy() > 0.0);
}
#[test]
fn angular_momentum_positive() {
let r = MercuryRotation::new();
assert!(r.angular_momentum() > 0.0);
}
#[test]
fn libration_amplitude_about_38() {
let amp = MercuryRotation::libration_amplitude_arcsec();
assert!((amp - 38.5).abs() < 5.0);
}
#[test]
fn libration_amplitude_rad_positive() {
assert!(MercuryRotation::libration_amplitude_rad() > 0.0);
}
#[test]
fn libration_angle_oscillates() {
let r = MercuryRotation::new();
let a1 = r.libration_angle_rad(0.0);
let a2 = r.libration_angle_rad(std::f64::consts::PI);
assert!((a1 - a2).abs() > 0.0 || a1 == 0.0);
}
#[test]
fn subsolar_longitude_finite() {
let r = MercuryRotation::new();
let lon = r.subsolar_longitude_deg(0.5, 1_000_000.0);
assert!(lon.is_finite());
}
#[test]
fn solar_day_about_176_earth_days() {
let sd = MercuryRotation::solar_day_s();
let earth_days = sd / 86400.0;
assert!((earth_days - 175.94).abs() < 2.0);
}
#[test]
fn sidereal_day_about_58_earth_days() {
let sd = MercuryRotation::sidereal_day_s();
let earth_days = sd / 86400.0;
assert!((earth_days - 58.646).abs() < 1.0);
}
#[test]
fn day_length_hours_finite() {
let r = MercuryRotation::new();
let h = r.day_length_hours(30.0);
assert!(h.is_finite() && h > 0.0);
}
#[test]
fn solar_tide_at_mean_distance() {
let t = SolarTide::at_mean_distance();
assert!(t.tidal_acceleration() > 0.0);
}
#[test]
fn perihelion_tide_stronger() {
let peri = SolarTide::at_perihelion();
let aph = SolarTide::at_aphelion();
assert!(peri.tidal_acceleration() > aph.tidal_acceleration());
}
#[test]
fn tidal_bulge_height_positive() {
let t = SolarTide::at_perihelion();
assert!(t.tidal_bulge_height() > 0.0);
}
#[test]
fn tidal_potential_finite() {
let t = SolarTide::at_mean_distance();
assert!(t.tidal_potential(0.0).is_finite());
}
#[test]
fn gravitational_attraction_positive() {
let t = SolarTide::at_mean_distance();
assert!(t.gravitational_attraction() > 0.0);
}
#[test]
fn spin_orbit_resonance_3_2() {
let (n, d) = spin_orbit_resonance();
assert_eq!((n, d), (3, 2));
}
#[test]
fn tidal_dissipation_positive() {
let d = tidal_dissipation_rate(mercurys::SEMI_MAJOR_AXIS_M);
assert!(d > 0.0);
}
#[test]
fn bulge_variation_ordered() {
let (peri, aph) = bulge_variation();
assert!(peri > aph, "perihelion bulge should exceed aphelion");
}
#[test]
fn tidal_locking_timescale_positive() {
let t = tidal_locking_timescale(1.0e11);
assert!(t > 0.0);
}
#[test]
fn perihelion_aphelion_tide_ratio_gt_1() {
assert!(perihelion_aphelion_tide_ratio() > 1.0);
}
#[test]
fn caloris_impactor_energy_huge() {
let imp = caloris_impactor();
assert!(imp.kinetic_energy_j() > 1.0e25);
}
#[test]
fn caloris_basin_diameter_about_1550km() {
let d = caloris_basin_diameter();
assert!((d - 1_550_000.0).abs() < 100_000.0);
}
#[test]
fn asteroid_crater_diameter_positive() {
let imp = Impactor::asteroid(1000.0, 42.5);
assert!(imp.crater_diameter_m(MERCURY_SURFACE_DENSITY) > 0.0);
}
#[test]
fn iron_asteroid_heavier() {
let stony = Impactor::asteroid(100.0, 42.5);
let iron = Impactor::iron_asteroid(100.0, 42.5);
assert!(iron.kinetic_energy_j() > stony.kinetic_energy_j());
}
#[test]
fn with_angle_modifies() {
let imp = Impactor::asteroid(100.0, 42.5).with_angle(30.0);
assert!((imp.angle_deg - 30.0).abs() < 0.01);
}
#[test]
fn fireball_radius_positive() {
let imp = Impactor::asteroid(100.0, 42.5);
assert!(imp.fireball_radius_m() > 0.0);
}
#[test]
fn ejecta_volume_positive() {
let imp = Impactor::asteroid(100.0, 42.5);
assert!(imp.ejecta_volume_m3(MERCURY_SURFACE_DENSITY) > 0.0);
}
#[test]
fn ejecta_escape_fraction_between_0_and_1() {
let imp = Impactor::asteroid(100.0, 42.5);
let f = imp.ejecta_escape_fraction();
assert!((0.0..=1.0).contains(&f));
}
#[test]
fn kinetic_energy_mt_positive() {
let imp = Impactor::asteroid(100.0, 42.5);
assert!(imp.kinetic_energy_mt() > 0.0);
}
#[test]
fn impact_velocity_matches() {
let imp = Impactor::asteroid(100.0, 42.5);
assert!(
imp.impact_velocity() > 42500.0,
"impact velocity includes escape velocity"
);
}
#[test]
fn typical_microimpact_small() {
let imp = typical_microimpact();
assert!(imp.mass_kg > 0.0 && imp.mass_kg.is_finite());
}
#[test]
fn simple_complex_transition_positive() {
assert!(simple_complex_transition_m() > 0.0);
}
#[test]
fn mean_impact_speed_about_42() {
assert!((MEAN_IMPACT_SPEED_KM_S - 42.5).abs() < 5.0);
}