use std::sync::Arc;
use std::thread;
use crate::utils::bitset::AtomicBitSet;
#[test]
fn test_bitset_single_bit_returned() {
let bs = AtomicBitSet::new(64);
bs.set(7);
assert_eq!(bs.random_set_index(64), 7);
}
#[test]
fn test_bitset_empty_returns_zero() {
let bs = AtomicBitSet::new(64);
assert_eq!(bs.random_set_index(64), 0);
}
#[test]
fn test_bitset_out_of_range_is_noop() {
let bs = AtomicBitSet::new(8);
bs.set(8);
bs.set(255);
assert_eq!(bs.random_set_index(8), 0, "out-of-range set must be ignored");
}
#[test]
fn test_bitset_multi_bit_only_set_bits_returned() {
let bs = AtomicBitSet::new(64);
bs.set(3);
bs.set(17);
bs.set(60);
let valid = [3usize, 17, 60];
for _ in 0..200 {
let idx = bs.random_set_index(64);
assert!(valid.contains(&idx), "unexpected index {idx}");
}
}
#[test]
fn test_bitset_reservoir_sampling_roughly_uniform() {
let bs = AtomicBitSet::new(4);
bs.set(0);
bs.set(1);
bs.set(2);
bs.set(3);
let iters = 10_000u32;
let mut counts = [0u32; 4];
for _ in 0..iters {
counts[bs.random_set_index(4)] += 1;
}
let expected = iters / 4;
for (i, &count) in counts.iter().enumerate() {
let diff = (count as i64 - expected as i64).unsigned_abs() as u32;
assert!(diff < expected / 4, "bit {i} selected {count} times (expected ~{expected}, diff {diff})");
}
}
#[test]
fn test_bitset_concurrent_set() {
let bs = Arc::new(AtomicBitSet::new(64));
let mut handles = Vec::new();
for bit in 0u32..8 {
let bs_clone = Arc::clone(&bs);
handles.push(thread::spawn(move || bs_clone.set(bit as usize)));
}
for h in handles {
h.join().unwrap();
}
let valid: Vec<usize> = (0..8).collect();
for _ in 0..200 {
assert!(valid.contains(&bs.random_set_index(8)));
}
}
#[test]
fn test_bitset_num_bits_boundary() {
let bs = AtomicBitSet::new(64);
bs.set(0);
bs.set(3);
bs.set(4); for _ in 0..100 {
let idx = bs.random_set_index(4);
assert!(idx < 4, "expected index < 4, got {idx}");
}
}