diff --git a/src/random/crypto.rs b/src/random/crypto.rs index 7aaf866..a6367de 100644 --- a/src/random/crypto.rs +++ b/src/random/crypto.rs @@ -111,4 +111,58 @@ mod tests { let mut rng = crypto_rng(); let _ = rng.next_u64(); } + + #[test] + fn test_crypto_normal_zero_sd() { + let mut rng = CryptoRng::new(); + for _ in 0..5 { + let v = rng.normal(10.0, 0.0); + assert_eq!(v, 10.0); + } + } + + #[test] + fn test_crypto_shuffle_empty_slice() { + use crate::random::SliceRandom; + let mut rng = CryptoRng::new(); + let mut arr: [u8; 0] = []; + arr.shuffle(&mut rng); + assert!(arr.is_empty()); + } + + #[test] + fn test_crypto_chi_square_uniform() { + let mut rng = CryptoRng::new(); + let mut counts = [0usize; 10]; + let samples = 10000; + for _ in 0..samples { + let v = rng.random_range(0..10usize); + counts[v] += 1; + } + let expected = samples as f64 / 10.0; + let chi2: f64 = counts + .iter() + .map(|&c| { + let diff = c as f64 - expected; + diff * diff / expected + }) + .sum(); + assert!(chi2 < 40.0, "chi-square statistic too high: {chi2}"); + } + + #[test] + fn test_crypto_monobit() { + let mut rng = CryptoRng::new(); + let mut ones = 0usize; + let samples = 1000; + for _ in 0..samples { + ones += rng.next_u64().count_ones() as usize; + } + let total_bits = samples * 64; + let ratio = ones as f64 / total_bits as f64; + assert!( + (ratio - 0.5).abs() < 0.02, + "bit ratio far from 0.5: {ratio}" + ); + } } diff --git a/src/random/prng.rs b/src/random/prng.rs index 4c9dee5..2b0e304 100644 --- a/src/random/prng.rs +++ b/src/random/prng.rs @@ -155,4 +155,76 @@ mod tests { } assert!(seen_true && seen_false); } + + #[test] + fn test_random_range_single_usize() { + let mut rng = Prng::new(42); + for _ in 0..10 { + let v = rng.random_range(5..6); + assert_eq!(v, 5); + } + } + + #[test] + fn test_random_range_single_f64() { + let mut rng = Prng::new(42); + for _ in 0..10 { + let v = rng.random_range(1.234..1.235); + assert!(v >= 1.234 && v < 1.235); + } + } + + #[test] + fn test_prng_normal_zero_sd() { + let mut rng = Prng::new(7); + for _ in 0..5 { + let v = rng.normal(3.0, 0.0); + assert_eq!(v, 3.0); + } + } + + #[test] + fn test_random_range_extreme_usize() { + let mut rng = Prng::new(5); + for _ in 0..10 { + let v = rng.random_range(0..usize::MAX); + assert!(v < usize::MAX); + } + } + + #[test] + fn test_prng_chi_square_uniform() { + let mut rng = Prng::new(12345); + let mut counts = [0usize; 10]; + let samples = 10000; + for _ in 0..samples { + let v = rng.random_range(0..10usize); + counts[v] += 1; + } + let expected = samples as f64 / 10.0; + let chi2: f64 = counts + .iter() + .map(|&c| { + let diff = c as f64 - expected; + diff * diff / expected + }) + .sum(); + assert!(chi2 < 20.0, "chi-square statistic too high: {chi2}"); + } + + #[test] + fn test_prng_monobit() { + let mut rng = Prng::new(42); + let mut ones = 0usize; + let samples = 1000; + for _ in 0..samples { + ones += rng.next_u64().count_ones() as usize; + } + let total_bits = samples * 64; + let ratio = ones as f64 / total_bits as f64; + assert!( + (ratio - 0.5).abs() < 0.01, + "bit ratio far from 0.5: {ratio}" + ); + } } diff --git a/src/random/random_core.rs b/src/random/random_core.rs index 8c3a02c..5db5617 100644 --- a/src/random/random_core.rs +++ b/src/random/random_core.rs @@ -79,4 +79,20 @@ mod tests { assert!(f >= 2.0 && f <= 4.0); } } + + #[test] + fn test_range_sample_usize_single_value() { + for val in [0, 1, u64::MAX] { + let n = ::from_u64(val, &(5..6)); + assert_eq!(n, 5); + } + } + + #[test] + fn test_range_sample_f64_negative_range() { + for val in [0, u64::MAX / 3, u64::MAX] { + let f = ::from_u64(val, &(-2.0..2.0)); + assert!(f >= -2.0 && f <= 2.0); + } + } } diff --git a/src/random/seq.rs b/src/random/seq.rs index 35c0d0b..8df863f 100644 --- a/src/random/seq.rs +++ b/src/random/seq.rs @@ -73,4 +73,33 @@ mod tests { arr2.shuffle(&mut rng); assert_ne!(arr1, arr2); } + + #[test] + fn test_shuffle_empty_slice() { + let mut rng = Prng::new(1); + let mut arr: [i32; 0] = []; + arr.shuffle(&mut rng); + assert!(arr.is_empty()); + } + + #[test] + fn test_shuffle_three_uniform() { + use std::collections::HashMap; + let mut rng = Prng::new(123); + let mut counts: HashMap<[u8; 3], usize> = HashMap::new(); + for _ in 0..6000 { + let mut arr = [1u8, 2, 3]; + arr.shuffle(&mut rng); + *counts.entry(arr).or_insert(0) += 1; + } + let expected = 1000.0; + let chi2: f64 = counts + .values() + .map(|&c| { + let diff = c as f64 - expected; + diff * diff / expected + }) + .sum(); + assert!(chi2 < 30.0, "shuffle chi-square too high: {chi2}"); + } }