//! xoshiro256++ 测试

use std::{collections::HashSet, sync::Mutex};

use moa_rand::{rand_range, rand32, rand64, srand};

static TEST_LOCK: Mutex<()> = Mutex::new(());

#[test]
fn rand64_not_constant() {
    let _lock = TEST_LOCK.lock().unwrap();
    let a = rand64();
    let b = rand64();
    assert_ne!(a, b);
}

#[test]
fn rand32_not_constant() {
    let _lock = TEST_LOCK.lock().unwrap();
    let a = rand32();
    let b = rand32();
    assert_ne!(a, b);
}

#[test]
fn srand_deterministic() {
    let _lock = TEST_LOCK.lock().unwrap();
    srand(42);
    let seq1: Vec<u64> = (0..10).map(|_| rand64()).collect();
    srand(42);
    let seq2: Vec<u64> = (0..10).map(|_| rand64()).collect();
    assert_eq!(seq1, seq2);
}

#[test]
fn srand_different_seeds() {
    let _lock = TEST_LOCK.lock().unwrap();
    srand(1);
    let a = rand64();
    srand(2);
    let b = rand64();
    assert_ne!(a, b);
}

#[test]
fn srand_zero_corrected() {
    let _lock = TEST_LOCK.lock().unwrap();
    srand(0);
    let a = rand64();
    let b = rand64();
    assert_ne!(a, 0);
    assert_ne!(a, b);
}

#[test]
fn rand_range_within_bound() {
    let _lock = TEST_LOCK.lock().unwrap();
    srand(123);
    for _ in 0..1000 {
        assert!(rand_range(10) < 10);
    }
}

#[test]
fn rand_range_bound_one() {
    let _lock = TEST_LOCK.lock().unwrap();
    for _ in 0..100 {
        assert_eq!(rand_range(1), 0);
    }
}

#[test]
fn distribution_no_obvious_bias() {
    let _lock = TEST_LOCK.lock().unwrap();
    srand(999);
    let n = 10000;
    let mut set = HashSet::new();
    for _ in 0..n {
        set.insert(rand64());
    }
    assert!(set.len() > n * 99 / 100);
}

#[test]
fn all_bits_exercised() {
    let _lock = TEST_LOCK.lock().unwrap();
    srand(7);
    let mut or_all = 0u64;
    for _ in 0..1000 {
        or_all |= rand64();
    }
    assert_eq!(or_all, u64::MAX);
}
