#![cfg(all(feature = "tier2", feature = "tier3"))]
use mod_rand::tier1::Xoshiro256;
use mod_rand::{tier2, tier3};
#[test]
fn tier1_uniformity_1m_draws() {
let mut rng = Xoshiro256::seed_from_u64(0xC0DE_F00D_2026);
let mut counts = [0u64; 100];
for _ in 0..1_000_000 {
let v = rng.gen_range_u32(0..100);
counts[v as usize] += 1;
}
let expected = 10_000.0;
let chi: f64 = counts
.iter()
.map(|&c| {
let diff = c as f64 - expected;
diff * diff / expected
})
.sum();
assert!(
chi < 250.0,
"tier1 1M-draw chi-squared {chi} too high — bias detected"
);
}
#[test]
fn tier2_uniformity_1m_draws() {
let mut counts = [0u64; 100];
for _ in 0..1_000_000 {
let v = tier2::range_u32(0..100);
counts[v as usize] += 1;
}
let expected = 10_000.0;
let chi: f64 = counts
.iter()
.map(|&c| {
let diff = c as f64 - expected;
diff * diff / expected
})
.sum();
assert!(
chi < 250.0,
"tier2 1M-draw chi-squared {chi} too high — bias detected"
);
}
#[test]
fn tier3_uniformity_50k_draws() {
let mut counts = [0u64; 50];
for _ in 0..50_000 {
let v = tier3::random_range_u32(0..50).expect("CSPRNG available");
counts[v as usize] += 1;
}
let expected = 1000.0;
let chi: f64 = counts
.iter()
.map(|&c| {
let diff = c as f64 - expected;
diff * diff / expected
})
.sum();
assert!(
chi < 200.0,
"tier3 50k-draw chi-squared {chi} too high — bias detected"
);
}
#[test]
fn tier1_die_roll_uniformity() {
let mut rng = Xoshiro256::seed_from_u64(0xD1CE_2026);
let mut faces = [0u64; 6];
for _ in 0..600_000 {
let d = rng.gen_range_inclusive_u32(1..=6);
faces[(d - 1) as usize] += 1;
}
let expected = 100_000.0;
let chi: f64 = faces
.iter()
.map(|&c| {
let diff = c as f64 - expected;
diff * diff / expected
})
.sum();
assert!(chi < 50.0, "tier1 d6 chi-squared {chi} — bias detected");
}
#[test]
fn single_value_inclusive_ranges_return_start_on_all_tiers() {
let mut rng = Xoshiro256::seed_from_u64(1);
for v in [0u64, 1, 42, u64::MAX] {
assert_eq!(rng.gen_range_inclusive_u64(v..=v), v);
assert_eq!(tier2::range_inclusive_u64(v..=v), v);
assert_eq!(tier3::random_range_inclusive_u64(v..=v).unwrap(), v);
}
}
#[test]
fn full_width_inclusive_ranges_supported() {
let mut rng = Xoshiro256::seed_from_u64(2);
let _ = rng.gen_range_inclusive_u64(0..=u64::MAX);
let _ = rng.gen_range_inclusive_u32(0..=u32::MAX);
let _ = rng.gen_range_inclusive_i64(i64::MIN..=i64::MAX);
let _ = rng.gen_range_inclusive_i32(i32::MIN..=i32::MAX);
let _ = tier2::range_inclusive_u64(0..=u64::MAX);
let _ = tier2::range_inclusive_u32(0..=u32::MAX);
let _ = tier2::range_inclusive_i64(i64::MIN..=i64::MAX);
let _ = tier2::range_inclusive_i32(i32::MIN..=i32::MAX);
tier3::random_range_inclusive_u64(0..=u64::MAX).unwrap();
tier3::random_range_inclusive_u32(0..=u32::MAX).unwrap();
tier3::random_range_inclusive_i64(i64::MIN..=i64::MAX).unwrap();
tier3::random_range_inclusive_i32(i32::MIN..=i32::MAX).unwrap();
}
#[test]
fn half_open_never_produces_upper_bound_tier1() {
let mut rng = Xoshiro256::seed_from_u64(3);
for _ in 0..100_000 {
let v = rng.gen_range_u64(0..10);
assert!(v < 10);
}
}
#[test]
fn inclusive_produces_upper_bound_tier1() {
let mut rng = Xoshiro256::seed_from_u64(4);
let mut saw_top = false;
for _ in 0..10_000 {
let v = rng.gen_range_inclusive_u64(0..=10);
if v == 10 {
saw_top = true;
break;
}
}
assert!(saw_top, "inclusive range never produced its upper bound");
}
#[test]
fn tier1_bounded_range_is_deterministic() {
let mut a = Xoshiro256::seed_from_u64(0xDEAD_BEEF);
let mut b = Xoshiro256::seed_from_u64(0xDEAD_BEEF);
for _ in 0..1000 {
assert_eq!(a.gen_range_u64(0..1000), b.gen_range_u64(0..1000));
assert_eq!(a.gen_range_i32(-100..100), b.gen_range_i32(-100..100));
assert_eq!(
a.gen_range_inclusive_u32(1..=6),
b.gen_range_inclusive_u32(1..=6)
);
let af = a.gen_range_f64(-1.0..1.0);
let bf = b.gen_range_f64(-1.0..1.0);
assert!((af - bf).abs() < 1e-15);
}
}