use super::*;
#[test]
fn rejects_non_finite_location_and_non_positive_scale() {
for bad_location in [f32::NAN, f32::INFINITY, f32::NEG_INFINITY] {
assert!(matches!(
LogitNormalDensity::new(bad_location, 1.0),
Err(Error::Validation(_))
));
}
for bad_scale in [0.0, -1.0, f32::NAN, f32::INFINITY] {
assert!(matches!(
LogitNormalDensity::new(0.0, bad_scale),
Err(Error::Validation(_))
));
}
let density = LogitNormalDensity::new(-0.5, 0.8).unwrap();
assert_eq!((density.location(), density.scale()), (-0.5, 0.8));
}
#[test]
fn median_draw_lands_at_the_logistic_of_location() {
let centered = LogitNormalDensity::new(LogitNormalDensity::DEFAULT_LOCATION, 1.0).unwrap();
assert!((centered.sample(0.0) - 0.5).abs() < 1e-6);
assert!(LogitNormalDensity::new(2.0, 1.0).unwrap().sample(0.0) > 0.5);
assert!(LogitNormalDensity::new(-2.0, 1.0).unwrap().sample(0.0) < 0.5);
}
#[test]
fn deserialization_validates_and_rejects_unknown_fields() {
let density: LogitNormalDensity =
serde_json::from_str(r#"{"location":-0.5,"scale":0.8}"#).unwrap();
assert_eq!((density.location(), density.scale()), (-0.5, 0.8));
assert!(serde_json::from_str::<LogitNormalDensity>(r#"{"location":0.0,"scale":0.0}"#).is_err());
assert!(
serde_json::from_str::<LogitNormalDensity>(r#"{"location":0.0,"scale":1.0,"scle":0.2}"#)
.is_err()
);
}
#[test]
fn sample_is_monotone_and_saturates_into_the_unit_interval() {
let density = LogitNormalDensity::new(0.3, 1.5).unwrap();
assert!(density.sample(-3.0) < density.sample(0.0));
assert!(density.sample(0.0) < density.sample(3.0));
for n in [-1e3, 1e3, -50.0, 50.0] {
let t = density.sample(n);
assert!((0.0..=1.0).contains(&t), "t={t} out of range for n={n}");
}
}