stdrandom 0.3.0

Generate random numbers using only Rust standard library
Documentation
use super::*;

use std::sync::{Arc, Mutex};

#[test]
fn test_u64_type() {
    let _result: u64 = gen_range(0..=(u64::MAX as u64), fast_u64);
}

#[test]
fn test_u32_type() {
    let _result: u32 = gen_range(0..=(u32::MAX as u64), fast_u64);
}

#[test]
fn test_u16_type() {
    let _result: u16 = gen_range(0..=(u16::MAX as u64), fast_u64);
}

#[test]
fn test_u8_type() {
    let _result: u8 = gen_range(0..=(u8::MAX as u64), fast_u64);
}

#[test]
#[should_panic(expected = "Conversion failed:")]
fn test_u32_type_overflow() {
    let start: u64 = (u32::MAX as u64) + 1;
    let _result: u32 = gen_range(start..=u64::MAX, fast_u64);
}

#[test]
#[should_panic(expected = "Conversion failed:")]
fn test_u16_type_overflow() {
    let start: u64 = (u16::MAX as u64) + 1;
    let _result: u16 = gen_range(start..=u64::MAX, fast_u64);
}

#[test]
#[should_panic(expected = "Conversion failed:")]
fn test_u8_type_overflow() {
    let start: u64 = (u8::MAX as u64) + 1;
    let _result: u8 = gen_range(start..=u64::MAX, fast_u64);
}

#[test]
fn test_top_u64_value() {
    let _result: u64 = gen_range(u64::MAX..=u64::MAX, fast_u64);
}

#[test]
fn test_maximum_range() {
    let _result: u64 = gen_range(0..=u64::MAX, fast_u64);
    let _result: u64 = gen_range(0..u64::MAX, fast_u64);
}

#[test]
fn test_single_value_range() {
    let result: u64 = gen_range(5..=5, fast_u64);
    assert_eq!(result, 5u64, "Single-value range should always return 5");
}

#[test]
fn test_small_range() {
    let result: u64 = gen_range(10..=11, fast_u64);
    assert!(
        matches!(result, 10u64 | 11u64),
        "Result should be either 10 or 11"
    );
}

#[test]
fn test_near_u64_max() {
    let start: u64 = u64::MAX - 5;
    let result: u64 = gen_range(start..=u64::MAX, fast_u64);
    assert!(
        (start..=u64::MAX).contains(&result),
        "Value should be within {}..={}",
        start,
        u64::MAX
    );
}

#[test]
#[should_panic]
fn test_empty_range_exclusive() {
    let _result: u64 = gen_range(5..5, fast_u64);
}

#[test]
fn test_large_inclusive_range() {
    let result: u64 = gen_range(0..=u64::MAX, fast_u64);
    assert!(
        (0..=u64::MAX).contains(&result),
        "Generated value should be within 0..=u64::MAX"
    );
}

#[test]
fn test_gen_range_state_changes_reference_passed() {
    let mut counter = 0u64;

    let mut rng_closure = move || {
        counter += 100;
        counter
    };

    let range = 0u64..=1000000;

    let val1: u64 = crate::gen_range(range.clone(), &mut rng_closure);
    let val2: u64 = crate::gen_range(range.clone(), &mut rng_closure);
    let val3: u64 = crate::gen_range(range.clone(), &mut rng_closure);

    // Verify that the RNG closure has mutated its internal state
    assert!(val1 < val2 && val2 < val3,
        "Expected RNG state to change across calls, but got: {} -> {} -> {}",
        val1, val2, val3
    );

    println!("Test successful. RNG closure mutated across calls.");
}

#[test]
fn test_gen_range_state_changes_value_passed() {
    let mut counter = 0u64;

    let rng_closure = move || {
        counter += 100;
        counter
    };

    let range = 0u64..=1000000;

    let val1: u64 = crate::gen_range(range.clone(), rng_closure);
    let val2: u64 = crate::gen_range(range.clone(), rng_closure);
    let val3: u64 = crate::gen_range(range.clone(), rng_closure);

    // Verify that the RNG closure has mutated its internal state
    assert!(val1 == val2 && val2 == val3,
        "Expected RNG state to did not changed across calls, but got: {} -> {} -> {}",
        val1, val2, val3
    );
}

#[test]
fn test_gen_range_with_mutable_increasing_closure() {
    let counter = Arc::new(Mutex::new(0u64));
    let counter_clone_for_closure = Arc::clone(&counter);

    let increasing_rng_closure = move || {
        let mut count = counter_clone_for_closure.lock().unwrap();
        *count += 1;
        *count
    };

    let range = 10u64..20u64;
    let returned_value: u64 = gen_range(range.clone(), increasing_rng_closure);

    let start_bound = match range.start_bound() {
        Bound::Included(&val) => val,
        Bound::Excluded(&val) => val + 1,
        Bound::Unbounded => u64::MIN,
    };

    let end_bound_exclusive = match range.end_bound() {
        Bound::Included(&val) => val + 1,
        Bound::Excluded(&val) => val,
        Bound::Unbounded => u64::MAX,
    };

    assert!(
        (start_bound..end_bound_exclusive).contains(&returned_value),
        "Generated value {} is out of expected range {:?}.",
        returned_value,
        range
    );

    let final_counter_value = *counter.lock().unwrap();
    assert_eq!(
        final_counter_value,
        1,
        "Expected counter in closure to be 1 after calling gen_range."
    );

    println!("Test successful.");
    println!("Returned value from gen_range: {}", returned_value);
    println!("Final counter value in closure: {}", final_counter_value);
}