use moonpool_sim::{
NetworkConfiguration, SimWorld, reset_sim_rng, sample_duration, set_sim_seed, sim_random,
sim_random_range,
};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;
#[test]
fn test_thread_local_rng_determinism() {
set_sim_seed(42);
let value1: f64 = sim_random();
let value2: u32 = sim_random();
let value3: bool = sim_random();
set_sim_seed(42);
assert_eq!(value1, sim_random::<f64>());
assert_eq!(value2, sim_random::<u32>());
assert_eq!(value3, sim_random::<bool>());
}
#[test]
fn test_simworld_with_seed_determinism() {
let sim1 = SimWorld::new_with_seed(123);
let delay1 = sim1.with_network_config(|config| sample_duration(&config.connect_latency));
let sim2 = SimWorld::new_with_seed(123);
let delay2 = sim2.with_network_config(|config| sample_duration(&config.connect_latency));
assert_eq!(delay1, delay2);
}
#[test]
fn test_simworld_different_seeds_different_behavior() {
let sim1 = SimWorld::new_with_seed(1);
let delay1 = sim1.with_network_config(|config| sample_duration(&config.connect_latency));
let sim2 = SimWorld::new_with_seed(2);
let delay2 = sim2.with_network_config(|config| sample_duration(&config.connect_latency));
assert_ne!(delay1, delay2);
}
#[test]
fn test_consecutive_simulations_same_thread() {
let mut delays = Vec::new();
for seed in [1, 2, 3, 4, 5] {
let sim = SimWorld::new_with_seed(seed);
let delay = sim.with_network_config(|config| sample_duration(&config.write_latency));
delays.push(delay);
}
for (i, seed) in [1, 2, 3, 4, 5].iter().enumerate() {
let sim = SimWorld::new_with_seed(*seed);
let delay = sim.with_network_config(|config| sample_duration(&config.write_latency));
assert_eq!(delays[i], delay, "Delay mismatch for seed {}", seed);
}
}
#[test]
fn test_latency_range_determinism() {
let range = Duration::from_millis(10)..Duration::from_millis(15);
set_sim_seed(42);
let delay1 = sample_duration(&range);
let delay2 = sample_duration(&range);
set_sim_seed(42);
assert_eq!(delay1, sample_duration(&range));
assert_eq!(delay2, sample_duration(&range));
}
#[test]
fn test_latency_range_bounds() {
let range = Duration::from_millis(100)..Duration::from_millis(150);
set_sim_seed(123);
for _ in 0..100 {
let delay = sample_duration(&range);
assert!(delay >= Duration::from_millis(100));
assert!(delay < Duration::from_millis(150));
}
}
#[test]
fn test_latency_range_fixed() {
let range = Duration::from_millis(42)..Duration::from_millis(42);
set_sim_seed(999);
for _ in 0..10 {
assert_eq!(sample_duration(&range), Duration::from_millis(42));
}
}
#[test]
fn test_reset_clears_state() {
set_sim_seed(42);
let _advance1: f64 = sim_random();
let _advance2: f64 = sim_random();
let after_advance: f64 = sim_random();
reset_sim_rng();
set_sim_seed(42);
let first_value: f64 = sim_random();
assert_ne!(after_advance, first_value);
}
#[test]
fn test_parallel_thread_isolation() {
let thread1_finished = Arc::new(AtomicBool::new(false));
let thread2_finished = Arc::new(AtomicBool::new(false));
let thread1_finished_clone = thread1_finished.clone();
let thread2_finished_clone = thread2_finished.clone();
let handle1 = thread::spawn(move || {
set_sim_seed(1);
let values: Vec<f64> = (0..10).map(|_| sim_random()).collect();
set_sim_seed(1);
for (i, &expected) in values.iter().enumerate() {
let actual: f64 = sim_random();
assert_eq!(expected, actual, "Thread 1 mismatch at index {}", i);
}
thread1_finished_clone.store(true, Ordering::Relaxed);
values
});
let handle2 = thread::spawn(move || {
set_sim_seed(2);
let values: Vec<u32> = (0..10).map(|_| sim_random()).collect();
set_sim_seed(2);
for (i, &expected) in values.iter().enumerate() {
let actual: u32 = sim_random();
assert_eq!(expected, actual, "Thread 2 mismatch at index {}", i);
}
thread2_finished_clone.store(true, Ordering::Relaxed);
values
});
let values1 = handle1.join().unwrap();
let values2 = handle2.join().unwrap();
assert!(thread1_finished.load(Ordering::Relaxed));
assert!(thread2_finished.load(Ordering::Relaxed));
let values2_as_f64: Vec<f64> = values2.iter().map(|&x| x as f64).collect();
assert_ne!(values1, values2_as_f64);
}
#[test]
fn test_simworld_network_config_integration() {
let config = NetworkConfiguration::default();
let sim = SimWorld::new_with_network_config_and_seed(config, 456);
let bind_delay = sim.with_network_config(|config| sample_duration(&config.bind_latency));
let connect_delay = sim.with_network_config(|config| sample_duration(&config.connect_latency));
let read_delay = sim.with_network_config(|config| sample_duration(&config.read_latency));
let write_delay = sim.with_network_config(|config| sample_duration(&config.write_latency));
assert!(bind_delay >= Duration::from_micros(50));
assert!(connect_delay >= Duration::from_millis(1));
assert!(read_delay >= Duration::from_micros(10));
assert!(write_delay >= Duration::from_micros(100));
let sim2 = SimWorld::new_with_network_config_and_seed(NetworkConfiguration::default(), 456);
assert_eq!(
bind_delay,
sim2.with_network_config(|config| sample_duration(&config.bind_latency))
);
assert_eq!(
connect_delay,
sim2.with_network_config(|config| sample_duration(&config.connect_latency))
);
assert_eq!(
read_delay,
sim2.with_network_config(|config| sample_duration(&config.read_latency))
);
assert_eq!(
write_delay,
sim2.with_network_config(|config| sample_duration(&config.write_latency))
);
}
#[test]
fn test_sim_random_range_determinism() {
set_sim_seed(789);
let range_value1 = sim_random_range(100..1000);
let range_value2 = sim_random_range(0.0..10.0);
set_sim_seed(789);
assert_eq!(range_value1, sim_random_range(100..1000));
assert_eq!(range_value2, sim_random_range(0.0..10.0));
}
#[test]
fn test_complex_simulation_sequence_determinism() {
let results1 = run_complex_simulation_sequence(12345);
let results2 = run_complex_simulation_sequence(12345);
assert_eq!(results1, results2);
}
fn run_complex_simulation_sequence(seed: u64) -> Vec<Duration> {
let sim = SimWorld::new_with_seed(seed);
let mut results = Vec::new();
for _ in 0..5 {
results.push(sim.with_network_config(|config| sample_duration(&config.bind_latency)));
results.push(sim.with_network_config(|config| sample_duration(&config.connect_latency)));
results.push(sim.with_network_config(|config| sample_duration(&config.write_latency)));
results.push(sim.with_network_config(|config| sample_duration(&config.read_latency)));
}
results
}
#[test]
fn test_multiple_simulations_same_thread_no_contamination() {
let mut all_results = Vec::new();
for seed in [100, 200, 300] {
let sim = SimWorld::new_with_seed(seed);
let mut sim_results = Vec::new();
for _ in 0..3 {
sim_results
.push(sim.with_network_config(|config| sample_duration(&config.connect_latency)));
}
all_results.push(sim_results);
}
for (i, seed) in [100, 200, 300].iter().enumerate() {
let sim = SimWorld::new_with_seed(*seed);
let mut sim_results = Vec::new();
for _ in 0..3 {
sim_results
.push(sim.with_network_config(|config| sample_duration(&config.connect_latency)));
}
assert_eq!(
all_results[i], sim_results,
"Results mismatch for seed {}",
seed
);
}
}