marss 0.0.3

Mars celestial simulation crate for the MilkyWay SolarSystem workspace
Documentation
use marss::temporal::calendar::*;
use marss::temporal::epoch::*;
use marss::temporal::time_scale::*;

// === Calendar / MarsSolDate ===

#[test]
fn msd_from_julian_roundtrip() {
    let jd = 2451545.0;
    let msd = MarsSolDate::from_julian_date(jd);
    let jd2 = msd.to_julian_date();
    assert!((jd - jd2).abs() < 1e-6, "Roundtrip: {jd} vs {jd2}");
}

#[test]
fn msd_sol_number_positive() {
    let msd = MarsSolDate::from_julian_date(2460000.0);
    assert!(msd.sol_number() > 0.0);
}

#[test]
fn msd_ls_bounded() {
    let msd = MarsSolDate::from_julian_date(2451545.0);
    let ls = msd.ls_deg();
    assert!((0.0..360.0).contains(&ls), "Ls in [0,360): {ls}");
}

#[test]
fn mars_sol_date_fn_positive() {
    let msd = mars_sol_date(2451545.0);
    assert!(msd > 0.0, "MSD > 0: {msd}");
}

#[test]
fn coordinated_mars_time_bounded() {
    let cmt = coordinated_mars_time(2451545.0);
    assert!((0.0..24.0).contains(&cmt), "CMT in [0,24): {cmt}");
}

#[test]
fn msd_mars_year_field() {
    let msd = MarsSolDate::from_julian_date(2460000.0);
    assert!(msd.mars_year != 0, "Mars year: {}", msd.mars_year);
}

// === Epoch ===

#[test]
fn epoch_j2000() {
    let e = MarsEpoch::j2000();
    assert!((e.julian_date - 2451545.0).abs() < 1e-6);
}

#[test]
fn epoch_from_jd() {
    let jd = 2460000.0;
    let e = MarsEpoch::from_jd(jd);
    assert!((e.julian_date - jd).abs() < 1e-6);
}

#[test]
fn epoch_centuries_since_j2000() {
    let e = MarsEpoch::from_jd(2451545.0 + 36525.0);
    let c = e.centuries_since_j2000();
    assert!((c - 1.0).abs() < 0.01, "1 century: {c}");
}

#[test]
fn epoch_days_since_j2000() {
    let e = MarsEpoch::from_jd(2451545.0 + 100.0);
    let d = e.days_since_j2000();
    assert!((d - 100.0).abs() < 0.01);
}

#[test]
fn epoch_sols_since_j2000() {
    let e = MarsEpoch::from_jd(2451545.0 + 100.0);
    let sols = e.sols_since_j2000();
    assert!(sols > 0.0 && sols < 100.0, "Sols < days: {sols}");
}

#[test]
fn epoch_advance_sols() {
    let mut e = MarsEpoch::j2000();
    let jd0 = e.julian_date;
    e.advance_sols(668.6);
    let dy = e.julian_date - jd0;
    assert!(dy > 660.0, "668.6 sols ~ 687 days: {dy}");
}

#[test]
fn epoch_advance_seconds() {
    let mut e = MarsEpoch::j2000();
    let jd0 = e.julian_date;
    e.advance_seconds(86400.0);
    let dd = e.julian_date - jd0;
    assert!((dd - 1.0).abs() < 0.01, "86400s = 1 day: {dd}");
}

#[test]
fn epoch_mars_year() {
    let e = MarsEpoch::j2000();
    let my = e.mars_year();
    assert!(my != 0, "Mars year: {my}");
}

#[test]
fn epoch_ls() {
    let e = MarsEpoch::j2000();
    let ls = e.ls_deg();
    assert!((0.0..360.0).contains(&ls), "Ls: {ls}");
}

// === Constants ===

#[test]
fn constants_defined() {
    assert_eq!(MY1_EPOCH_JD, 2_435_208.5);
    assert_eq!(MSD_EPOCH_JD, 2_405_522.0);
    assert!((J2000_EPOCH - 2451545.0).abs() < 1e-6);
}

// === Time Scale ===

#[test]
fn time_scale_new() {
    let ts = TimeScale::new();
    assert!(ts.simulation_dt(1.0) >= 0.0);
}

#[test]
fn time_scale_realtime() {
    let ts = TimeScale::realtime();
    let dt = ts.simulation_dt(1.0);
    assert!((dt - 1.0).abs() < 0.1, "Realtime dt ~1: {dt}");
}

#[test]
fn time_scale_fast_forward() {
    let ts = TimeScale::fast_forward(10.0);
    let dt = ts.simulation_dt(1.0);
    assert!((dt - 10.0).abs() < 0.1, "FF 10x: {dt}");
}

#[test]
fn time_scale_step() {
    let mut ts = TimeScale::realtime();
    ts.step(1.0);
    let sols = ts.sim_sols();
    assert!(sols > 0.0, "After step, sols > 0: {sols}");
}

#[test]
fn time_scale_pause_resume() {
    let mut ts = TimeScale::realtime();
    ts.pause();
    let dt_paused = ts.simulation_dt(1.0);
    assert!((dt_paused - 0.0).abs() < 1e-9, "Paused dt=0");
    ts.resume();
    let dt_resumed = ts.simulation_dt(1.0);
    assert!(dt_resumed > 0.0, "Resumed dt > 0");
}

#[test]
fn time_scale_toggle_pause() {
    let mut ts = TimeScale::realtime();
    ts.toggle_pause();
    assert!(ts.simulation_dt(1.0).abs() < 1e-9);
    ts.toggle_pause();
    assert!(ts.simulation_dt(1.0) > 0.0);
}

#[test]
fn time_scale_set_speed() {
    let mut ts = TimeScale::realtime();
    ts.set_speed(5.0);
    assert!((ts.simulation_dt(1.0) - 5.0).abs() < 0.1);
}

#[test]
fn time_scale_sim_mars_years() {
    let mut ts = TimeScale::fast_forward(100.0);
    for _ in 0..1000 {
        ts.step(1.0);
    }
    let my = ts.sim_mars_years();
    assert!(my >= 0.0);
}

#[test]
fn time_scale_sim_sols_accumulate() {
    let mut ts = TimeScale::fast_forward(10.0);
    ts.step(1.0);
    ts.step(1.0);
    let sols = ts.sim_sols();
    assert!(sols > 0.0, "Sols accumulate: {sols}");
}