use rand::SeedableRng;
use rand_chacha::ChaCha8Rng;
use rust_unique_pass::TimingSafeOps;
type TestResult<T> = std::result::Result<T, String>;
#[test]
fn test_constant_time_select() {
let chars = vec!['a', 'b', 'c', 'd', 'e'];
for i in 0..chars.len() {
let result = TimingSafeOps::constant_time_select(&chars, i);
assert_eq!(result, Some(chars[i]));
}
let result = TimingSafeOps::constant_time_select(&chars, 10);
assert!(result.is_some());
}
#[test]
fn test_constant_time_compare() {
assert!(TimingSafeOps::constant_time_compare("hello", "hello"));
assert!(!TimingSafeOps::constant_time_compare("hello", "world"));
assert!(!TimingSafeOps::constant_time_compare("hello", "hello!"));
}
#[test]
fn test_secure_random_index() -> TestResult<()> {
let mut rng = ChaCha8Rng::from_seed([0x44; 32]);
for _ in 0..100 {
let index = TimingSafeOps::secure_random_index(&mut rng, 10)
.map_err(|e| format!("secure_random_index failed: {e}"))?;
assert!(index < 10);
}
let mut counts = [0usize; 10];
for _ in 0..10_000 {
let idx = TimingSafeOps::secure_random_index(&mut rng, 10)
.map_err(|e| format!("secure_random_index failed: {e}"))?;
counts[idx] += 1;
}
assert!(counts.iter().all(|&c| c > 0));
Ok(())
}
#[test]
fn test_secure_random_index_boundary_values() -> TestResult<()> {
let mut rng = ChaCha8Rng::from_seed([0x46; 32]);
let bounds = [
1usize, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, 129,
];
for max in bounds {
for _ in 0..512 {
let index = TimingSafeOps::secure_random_index(&mut rng, max)
.map_err(|e| format!("secure_random_index failed: {e}"))?;
assert!(index < max);
}
}
Ok(())
}
#[test]
fn test_secure_random_index_zero_max_returns_zero() -> TestResult<()> {
let mut rng = ChaCha8Rng::from_seed([0x47; 32]);
let index = TimingSafeOps::secure_random_index(&mut rng, 0)
.map_err(|e| format!("secure_random_index failed: {e}"))?;
assert_eq!(index, 0);
Ok(())
}
#[test]
fn test_secure_shuffle() -> TestResult<()> {
let mut items = vec![1, 2, 3, 4, 5];
let original = items.clone();
let mut rng = ChaCha8Rng::from_seed([0x45; 32]);
TimingSafeOps::secure_shuffle(&mut items, &mut rng)
.map_err(|e| format!("secure_shuffle failed: {e}"))?;
items.sort();
assert_eq!(items, original);
Ok(())
}