use jupiters::lighting::day_night::*;
use jupiters::lighting::seasons::*;
use jupiters::lighting::solar_position::*;
#[test]
fn axialtiltcorrect() {
assert!((JUPITERAXIALTILTDEG - 3.13).abs() < 0.01);
}
#[test]
fn solarpositiondistancenear5au() {
let sun = SolarPosition::compute(2451545.0, 0.0, 0.0);
let au_dist = sun.distanceau;
assert!(
au_dist > 4.9 && au_dist < 5.5,
"Should be ~5.2 AU: {au_dist}"
);
}
#[test]
fn solarpositionnoonequator() {
let jd = 2451545.0;
let sun = SolarPosition::compute(jd, 0.0, 0.0);
assert!(
sun.distanceau > 4.5 && sun.distanceau < 5.8,
"Distance should be ~5.2 AU: {}",
sun.distanceau
);
}
#[test]
fn solarpositiondistanceinmeters() {
let jd = 2451545.0;
let sun = SolarPosition::compute(jd, 0.0, 0.0);
let dm = sun.distancem();
assert!(dm > 6e11 && dm < 9e11, "Distance in meters off: {dm}");
}
#[test]
fn solarpositionisabovehorizonday() {
let jd = 2451545.0;
let sun = SolarPosition::compute(jd, 0.0, 0.0);
let sunsomewhere = SolarPosition::compute(jd, 0.0, -180.0);
assert!(
sun.isabovehorizon() || sunsomewhere.isabovehorizon(),
"Sun should be above horizon somewhere on equator"
);
}
#[test]
fn solarpositiondirectionunitvector() {
let jd = 2451545.0;
let sun = SolarPosition::compute(jd, 45.0, 90.0);
let len =
(sun.direction[0].powi(2) + sun.direction[1].powi(2) + sun.direction[2].powi(2)).sqrt();
assert!(
(len - 1.0).abs() < 0.1,
"Direction should be unit vector: {len}"
);
}
#[test]
fn solarpositionvarieswithlongitude() {
let jd = 2451545.0;
let suna = SolarPosition::compute(jd, 0.0, 0.0);
let sunb = SolarPosition::compute(jd, 0.0, 180.0);
assert!(
(suna.elevationdeg - sunb.elevationdeg).abs() > 1.0,
"Solar elevation should differ at different longitudes"
);
}
#[test]
fn solarelevationvarieswithdate() {
let jdsummer = 2451545.0 + 1083.0;
let jdwinter = 2451545.0 + 2166.0;
let suns = SolarPosition::compute(jdsummer, 60.0, 0.0);
let sunw = SolarPosition::compute(jdwinter, 60.0, 0.0);
assert!(
suns.elevationdeg != sunw.elevationdeg,
"Solar elevation should vary with season"
);
}
#[test]
fn solarfluxatjupiter() {
let sun = SolarPosition::compute(2451545.0, 0.0, 0.0);
let flux = sun.solarfluxwm2();
assert!(
flux > 40.0 && flux < 60.0,
"Jupiter solar flux ~50 W/m²: {flux}"
);
}
#[test]
fn daylightstateday() {
let jd = 2451545.0;
let cycle = DayNightCycle::new(jd);
let mut foundday = false;
for lon in (-180..180).step_by(15) {
if cycle.stateat(0.0, lon as f64) == DaylightState::Day {
foundday = true;
break;
}
}
assert!(foundday, "Should find daytime somewhere on the equator");
}
#[test]
fn daylightstatenight() {
let jd = 2451545.0;
let cycle = DayNightCycle::new(jd);
let mut foundnight = false;
for lon in (-180..180).step_by(15) {
if cycle.stateat(0.0, lon as f64) == DaylightState::Night {
foundnight = true;
break;
}
}
assert!(foundnight, "Should find nighttime somewhere on the equator");
}
#[test]
fn daylightstateenumvalues() {
assert_ne!(DaylightState::Day, DaylightState::Night);
assert_ne!(
DaylightState::CivilTwilight,
DaylightState::NauticalTwilight
);
assert_ne!(
DaylightState::NauticalTwilight,
DaylightState::AstronomicalTwilight
);
}
#[test]
fn terminatorpointscount() {
let cycle = DayNightCycle::new(2451545.0);
let pts = cycle.terminatorpoints(36);
assert_eq!(pts.len(), 36);
}
#[test]
fn terminatorpointsvalidcoordinates() {
let cycle = DayNightCycle::new(2451545.0);
let pts = cycle.terminatorpoints(72);
for pt in &pts {
assert!(
(-90.0..=90.0).contains(&pt[0]),
"Lat out of range: {}",
pt[0]
);
assert!(
(-180.0..=360.0).contains(&pt[1]),
"Lon out of range: {}",
pt[1]
);
}
}
#[test]
fn ambientlightday() {
let cycle = DayNightCycle::new(2451545.0);
for lon in (-180..180).step_by(10) {
let state = cycle.stateat(0.0, lon as f64);
if state == DaylightState::Day {
let al = cycle.ambientlight(0.0, lon as f64);
assert!(al > 0.001, "Daytime ambient should be positive: {al}");
return;
}
}
}
#[test]
fn ambientlightnight() {
let cycle = DayNightCycle::new(2451545.0);
for lon in (-180..180).step_by(10) {
let state = cycle.stateat(0.0, lon as f64);
if state == DaylightState::Night {
let al = cycle.ambientlight(0.0, lon as f64);
assert!(al < 0.01, "Nighttime ambient should be dim: {al}");
return;
}
}
}
#[test]
fn ambientlightrange() {
let cycle = DayNightCycle::new(2451545.0);
for lon in (-180..180).step_by(30) {
let al = cycle.ambientlight(45.0, lon as f64);
assert!(
(0.0..=1.0).contains(&al),
"Ambient light out of range: {al}"
);
}
}
#[test]
fn seasonscreation() {
let s = Seasons::new(2451545.0);
let lon = s.jupitersolarlongitudedeg();
assert!(
(0.0..=360.0).contains(&lon),
"Solar longitude out of range: {lon}"
);
}
#[test]
fn subsolarlatitudebounded() {
let s = Seasons::new(2451545.0);
let lat = s.subsolarlatitudedeg();
assert!(
(-3.2..=3.2).contains(&lat),
"Subsolar lat should be bounded by tilt: {lat}"
);
}
#[test]
fn seasonnamereturnsstring() {
let s = Seasons::new(2451545.0);
let name = s.seasonname();
assert!(!name.is_empty());
let valid = [
"Northern Spring",
"Northern Summer",
"Northern Autumn",
"Northern Winter",
];
assert!(valid.contains(&name), "Unexpected season name: {name}");
}
#[test]
fn daylighthoursequator() {
let s = Seasons::new(2451545.0);
let hours = s.daylighthours(0.0);
assert!(hours > 4.0 && hours <= 9.925, "Equator daylength: {hours}");
}
#[test]
fn daylighthourspolarsummer() {
for offset in (0..4332).step_by(100) {
let s = Seasons::new(2451545.0 + offset as f64);
let hours = s.daylighthours(89.0);
assert!((0.0..=9.925).contains(&hours), "Polar daylength: {hours}");
}
}
#[test]
fn insolationfactorequator() {
let s = Seasons::new(2451545.0);
let factor = s.insolationfactor(0.0);
assert!(
factor >= 0.0,
"Insolation factor should be non-negative: {factor}"
);
}
#[test]
fn insolationfactorpole() {
let s = Seasons::new(2451545.0);
let feq = s.insolationfactor(0.0);
let fpole = s.insolationfactor(85.0);
assert!(feq >= fpole, "Equator should get more insolation than pole");
}
#[test]
fn seasonsvaryoverorbitalperiod() {
let s1 = Seasons::new(2451545.0);
let s2 = Seasons::new(2451545.0 + 1083.0);
let s3 = Seasons::new(2451545.0 + 2166.0);
let n1 = s1.seasonname();
let n2 = s2.seasonname();
let n3 = s3.seasonname();
assert!(n1 != n2 || n2 != n3, "Seasons should change through orbit");
}
#[test]
fn subsolarlatitudevarieswithtime() {
let s1 = Seasons::new(2451545.0);
let s2 = Seasons::new(2451545.0 + 1083.0);
let l1 = s1.subsolarlatitudedeg();
let l2 = s2.subsolarlatitudedeg();
assert!(
(l1 - l2).abs() > 0.01,
"Subsolar lat should vary: {l1} vs {l2}"
);
}