#![allow(clippy::unreadable_literal)] #![allow(clippy::cast_precision_loss)]
use std::collections::HashMap;
use std::hash::BuildHasher;
pub const DEFAULT_TOLERANCE: f64 = 1e-10;
pub fn assert_approx_eq(a: f64, b: f64, tolerance: f64) {
let diff = (a - b).abs();
assert!(
diff <= tolerance,
"Values not approximately equal: {a} != {b} (diff: {diff}, tolerance: {tolerance})"
);
}
pub fn assert_vec_approx_eq(a: &[f64], b: &[f64], tolerance: f64) {
assert_eq!(
a.len(),
b.len(),
"Vectors have different lengths: {} != {}",
a.len(),
b.len()
);
for (i, (a_val, b_val)) in a.iter().zip(b.iter()).enumerate() {
let diff = (a_val - b_val).abs();
assert!(
diff <= tolerance,
"Element {i} not approximately equal: {a_val} != {b_val} (diff: {diff}, tolerance: {tolerance})"
);
}
}
pub fn assert_measurement_counts_close<S1: BuildHasher, S2: BuildHasher>(
actual: &HashMap<String, usize, S1>,
expected: &HashMap<String, usize, S2>,
relative_tolerance: f64,
) {
for (outcome, &expected_count) in expected {
let actual_count = actual.get(outcome).copied().unwrap_or(0);
let expected_count_f = expected_count as f64;
let actual_count_f = actual_count as f64;
let relative_diff = if expected_count_f > 0.0 {
(actual_count_f - expected_count_f).abs() / expected_count_f
} else {
actual_count_f
};
assert!(
relative_diff <= relative_tolerance,
"Measurement outcome '{}' not close: expected {}, got {} (relative diff: {:.2}%, tolerance: {:.2}%)",
outcome,
expected_count,
actual_count,
relative_diff * 100.0,
relative_tolerance * 100.0
);
}
}
pub fn generate_random_test_data(size: usize, seed: u64) -> Vec<f64> {
let mut state = seed;
(0..size)
.map(|_| {
state = state.wrapping_mul(1103515245).wrapping_add(12345);
(state as f64 / u64::MAX as f64).abs()
})
.collect()
}
pub const fn test_seed() -> u64 {
42
}
pub fn create_temp_test_dir() -> std::path::PathBuf {
let temp_dir = std::env::temp_dir().join(format!("quantrs2_test_{}", test_seed()));
std::fs::create_dir_all(&temp_dir).expect("Failed to create temp directory");
temp_dir
}
pub fn with_suppressed_output<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
f()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_assert_approx_eq() {
assert_approx_eq(1.0, 1.0, DEFAULT_TOLERANCE);
assert_approx_eq(1.0, 1.0 + 1e-11, DEFAULT_TOLERANCE);
}
#[test]
#[should_panic(expected = "not approximately equal")]
fn test_assert_approx_eq_fails() {
assert_approx_eq(1.0, 2.0, DEFAULT_TOLERANCE);
}
#[test]
fn test_assert_vec_approx_eq() {
let a = vec![1.0, 2.0, 3.0];
let b = vec![1.000_000_1, 2.000_000_1, 3.000_000_1];
assert_vec_approx_eq(&a, &b, 1e-6);
}
#[test]
#[should_panic(expected = "not approximately equal")]
fn test_assert_vec_approx_eq_fails() {
let a = vec![1.0, 2.0];
let b = vec![1.0, 3.0];
assert_vec_approx_eq(&a, &b, 1e-6);
}
#[test]
fn test_assert_measurement_counts_close() {
let mut actual = HashMap::new();
actual.insert("00".to_string(), 495);
actual.insert("11".to_string(), 505);
let mut expected = HashMap::new();
expected.insert("00".to_string(), 500);
expected.insert("11".to_string(), 500);
assert_measurement_counts_close(&actual, &expected, 0.05);
}
#[test]
fn test_generate_random_test_data() {
let data = generate_random_test_data(100, test_seed());
assert_eq!(data.len(), 100);
assert!(data.iter().all(|&x| (0.0..=1.0).contains(&x)));
let data2 = generate_random_test_data(100, test_seed());
assert_eq!(data, data2);
}
#[test]
fn test_test_seed() {
assert_eq!(test_seed(), 42);
}
#[test]
fn test_create_temp_test_dir() {
let dir = create_temp_test_dir();
assert!(dir.exists());
}
}