use brightdate::astronomy::{
greenwich_mean_sidereal_time, julian_century, local_mean_sidereal_time,
lunar_illuminated_fraction, lunar_phase_angle, solar_declination, solar_longitude,
solar_right_ascension,
};
#[test]
fn julian_century_at_j2000() {
assert!((julian_century(0.0) - 0.0).abs() < 1e-12);
}
#[test]
fn julian_century_one_century_later() {
assert!((julian_century(36_525.0) - 1.0).abs() < 1e-12);
}
#[test]
fn julian_century_typical_value() {
let t = julian_century(9622.0);
assert!(t.is_finite());
assert!((t - 9622.0 / 36_525.0).abs() < 1e-12);
}
#[test]
fn gmst_at_j2000() {
let gmst = greenwich_mean_sidereal_time(0.0);
assert!(gmst >= 0.0 && gmst < 360.0, "GMST out of range: {gmst}");
}
#[test]
fn gmst_in_range_typical() {
let gmst = greenwich_mean_sidereal_time(9622.0);
assert!(gmst >= 0.0 && gmst < 360.0, "GMST out of range: {gmst}");
}
#[test]
fn gmst_in_range_negative_bd() {
let gmst = greenwich_mean_sidereal_time(-1000.0);
assert!(gmst >= 0.0 && gmst < 360.0, "GMST out of range: {gmst}");
}
#[test]
fn gmst_changes_with_time() {
let g0 = greenwich_mean_sidereal_time(0.0);
let g1 = greenwich_mean_sidereal_time(1.0);
assert!((g0 - g1).abs() > 0.01, "GMST should change over 1 day");
}
#[test]
fn lmst_equals_gmst_at_zero_longitude() {
let bd = 9622.0;
let gmst = greenwich_mean_sidereal_time(bd);
let lmst = local_mean_sidereal_time(bd, 0.0);
assert!((lmst - gmst).abs() < 1e-10);
}
#[test]
fn lmst_offset_by_longitude() {
let bd = 9622.0;
let gmst = greenwich_mean_sidereal_time(bd);
let lmst = local_mean_sidereal_time(bd, 90.0);
let diff = ((lmst - (gmst + 90.0)) % 360.0).abs();
assert!(diff < 1e-10 || (360.0 - diff).abs() < 1e-10);
}
#[test]
fn lmst_in_range() {
let lmst = local_mean_sidereal_time(9622.0, 45.0);
assert!(lmst >= 0.0 && lmst < 360.0, "LMST out of range: {lmst}");
}
#[test]
fn solar_longitude_in_range() {
let lon = solar_longitude(9622.0);
assert!(lon >= 0.0 && lon < 360.0, "solar longitude out of range: {lon}");
}
#[test]
fn solar_longitude_at_j2000_approx() {
let lon = solar_longitude(0.0);
assert!(lon > 240.0 && lon < 320.0, "unexpected solar lon at J2000: {lon}");
}
#[test]
fn solar_longitude_changes_per_day() {
let l0 = solar_longitude(0.0);
let l1 = solar_longitude(1.0);
let diff = ((l1 - l0 + 360.0) % 360.0).abs();
assert!(diff > 0.9 && diff < 1.1, "unexpected daily motion: {diff}");
}
#[test]
fn solar_declination_in_range() {
let dec = solar_declination(9622.0);
assert!(dec >= -90.0 && dec <= 90.0, "declination out of range: {dec}");
}
#[test]
fn solar_declination_summer_solstice_positive() {
let dec = solar_declination(172.0);
assert!(dec > 0.0, "summer solstice should have positive declination: {dec}");
}
#[test]
fn solar_declination_winter_solstice_negative() {
let dec = solar_declination(356.0);
assert!(dec < 0.0, "winter solstice should have negative declination: {dec}");
}
#[test]
fn solar_right_ascension_in_range() {
let ra = solar_right_ascension(9622.0);
assert!(ra >= 0.0 && ra < 360.0, "solar RA out of range: {ra}");
}
#[test]
fn lunar_phase_angle_in_range() {
for &bd in &[0.0, 1000.0, 9622.0, -1000.0] {
let phase = lunar_phase_angle(bd);
assert!(phase >= 0.0 && phase < 360.0, "phase={phase} at bd={bd}");
}
}
#[test]
fn lunar_illuminated_fraction_in_range() {
for &bd in &[0.0, 100.0, 9622.0, 18000.0] {
let frac = lunar_illuminated_fraction(bd);
assert!(frac >= 0.0 && frac <= 1.0, "fraction={frac} at bd={bd}");
}
}
#[test]
fn lunar_illuminated_fraction_monotone_from_new_to_full() {
let at_new = lunar_illuminated_fraction(0.0);
let at_quarter = lunar_illuminated_fraction(7.375);
assert!(at_new >= 0.0 && at_new <= 1.0);
assert!(at_quarter >= 0.0 && at_quarter <= 1.0);
}
#[test]
fn julian_century_half_century() {
let t = julian_century(36_525.0 / 2.0);
assert!((t - 0.5).abs() < 1e-12);
}
#[test]
fn julian_century_negative() {
let t = julian_century(-36_525.0);
assert!((t + 1.0).abs() < 1e-12);
}
#[test]
fn julian_century_proportional() {
let t1 = julian_century(1000.0);
let t2 = julian_century(2000.0);
assert!((t2 - 2.0 * t1).abs() < 1e-12);
}
#[test]
fn julian_century_zero_bd() {
assert_eq!(julian_century(0.0), 0.0);
}
#[test]
fn gmst_at_specific_date_finite() {
let g = greenwich_mean_sidereal_time(9622.5);
assert!(g.is_finite());
}
#[test]
fn gmst_never_negative() {
for bd in [-5000.0, 0.0, 100.0, 9622.0, 36525.0] {
let g = greenwich_mean_sidereal_time(bd);
assert!(g >= 0.0, "GMST negative at bd={bd}: {g}");
}
}
#[test]
fn gmst_always_below_360() {
for bd in [-5000.0, 0.0, 100.0, 9622.0, 36525.0] {
let g = greenwich_mean_sidereal_time(bd);
assert!(g < 360.0, "GMST >= 360 at bd={bd}: {g}");
}
}
#[test]
fn gmst_changes_over_year() {
let g0 = greenwich_mean_sidereal_time(0.0);
let g365 = greenwich_mean_sidereal_time(365.25);
let g100 = greenwich_mean_sidereal_time(100.0);
assert!((g0 - g100).abs() > 0.01);
let _ = g365;
}
#[test]
fn lmst_in_range_negative_longitude() {
let lmst = local_mean_sidereal_time(9622.0, -90.0);
assert!(lmst >= 0.0 && lmst < 360.0, "LMST={lmst}");
}
#[test]
fn lmst_wraps_at_360() {
let lmst = local_mean_sidereal_time(9622.0, 350.0);
assert!(lmst >= 0.0 && lmst < 360.0);
}
#[test]
fn lmst_full_circle_same_as_zero() {
let bd = 9622.0;
let a = local_mean_sidereal_time(bd, 0.0);
let b = local_mean_sidereal_time(bd, 360.0);
assert!((a - b).abs() < 1e-8);
}
#[test]
fn lmst_london_and_greenwich_same() {
let bd = 9622.0;
let greenwich = local_mean_sidereal_time(bd, 0.0);
let gmt = local_mean_sidereal_time(bd, 0.0);
assert!((greenwich - gmt).abs() < 1e-12);
}
#[test]
fn solar_longitude_finite() {
for bd in [-5000.0, 0.0, 9622.0, 36525.0] {
assert!(solar_longitude(bd).is_finite());
}
}
#[test]
fn solar_longitude_in_range_multiple_dates() {
for bd in [100.0, 200.0, 300.0, 9622.0] {
let lon = solar_longitude(bd);
assert!(lon >= 0.0 && lon < 360.0, "lon={lon} at bd={bd}");
}
}
#[test]
fn solar_longitude_approx_equinox() {
let lon = solar_longitude(79.0);
let close_to_zero = lon < 10.0 || lon > 350.0;
assert!(close_to_zero, "solar lon at vernal equinox should be near 0°, got {lon}");
}
#[test]
fn solar_declination_equinox_near_zero() {
let dec = solar_declination(79.0);
assert!(dec.abs() < 5.0, "declination at equinox should be near 0, got {dec}");
}
#[test]
fn solar_declination_bounded() {
for bd in [-1000.0, 0.0, 100.0, 9622.0] {
let dec = solar_declination(bd);
assert!(dec.abs() <= 90.0, "declination out of range: {dec}");
}
}
#[test]
fn solar_ra_in_range_all_dates() {
for bd in [0.0, 100.0, 200.0, 9622.0] {
let ra = solar_right_ascension(bd);
assert!(ra >= 0.0 && ra < 360.0, "RA={ra} at bd={bd}");
}
}
#[test]
fn solar_ra_finite() {
assert!(solar_right_ascension(9622.5).is_finite());
}
#[test]
fn lunar_phase_angle_full_moon_near_180() {
let mut found_near_180 = false;
for d in (0..30).map(|i| i as f64) {
let phase = lunar_phase_angle(d);
if (phase - 180.0).abs() < 30.0 {
found_near_180 = true;
}
}
assert!(found_near_180, "No full moon found in first 30 BDs");
}
#[test]
fn lunar_phase_angle_changes_daily() {
let p0 = lunar_phase_angle(0.0);
let p1 = lunar_phase_angle(1.0);
assert!((p0 - p1).abs() > 0.0, "phase should change day to day");
}
#[test]
fn lunar_illuminated_fraction_full_moon_near_one() {
let mut max_frac = 0.0_f64;
for d in (0..30).map(|i| i as f64) {
max_frac = max_frac.max(lunar_illuminated_fraction(d));
}
assert!(max_frac > 0.9, "expected near-full illumination, got {max_frac}");
}
#[test]
fn lunar_illuminated_fraction_new_moon_near_zero() {
let mut min_frac = 1.0_f64;
for d in (0..30).map(|i| i as f64) {
min_frac = min_frac.min(lunar_illuminated_fraction(d));
}
assert!(min_frac < 0.1, "expected near-zero illumination, got {min_frac}");
}