use std::time::{Duration, Instant};
#[derive(Debug, Clone, Default)]
pub struct FrameProfile {
pub cycle: u32,
pub duration_ms: u64,
pub memory_bytes: usize,
pub tests_passed: u32,
pub tests_failed: u32,
pub input_seed: u64,
pub input_size: usize,
}
#[derive(Debug, Clone, Default)]
pub struct StressReport {
pub frames: Vec<FrameProfile>,
pub cycles_completed: u32,
pub total_passed: u32,
pub total_failed: u32,
pub anomalies: Vec<Anomaly>,
}
impl StressReport {
#[must_use]
pub fn mean_frame_time_ms(&self) -> f64 {
if self.frames.is_empty() {
return 0.0;
}
let sum: u64 = self.frames.iter().map(|f| f.duration_ms).sum();
sum as f64 / self.frames.len() as f64
}
#[must_use]
pub fn timing_variance(&self) -> f64 {
if self.frames.len() < 2 {
return 0.0;
}
let mean = self.mean_frame_time_ms();
if mean == 0.0 {
return 0.0;
}
let variance: f64 = self
.frames
.iter()
.map(|f| {
let diff = f.duration_ms as f64 - mean;
diff * diff
})
.sum::<f64>()
/ self.frames.len() as f64;
variance.sqrt() / mean
}
#[must_use]
pub fn max_frame_time_ms(&self) -> u64 {
self.frames.iter().map(|f| f.duration_ms).max().unwrap_or(0)
}
#[must_use]
pub fn pass_rate(&self) -> f64 {
let total = self.total_passed + self.total_failed;
if total == 0 {
return 1.0;
}
self.total_passed as f64 / total as f64
}
pub fn add_frame(&mut self, profile: FrameProfile) {
self.total_passed += profile.tests_passed;
self.total_failed += profile.tests_failed;
self.cycles_completed += 1;
self.frames.push(profile);
}
}
#[derive(Debug, Clone)]
pub struct Anomaly {
pub cycle: u32,
pub kind: AnomalyKind,
pub description: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AnomalyKind {
SlowFrame,
HighMemory,
TestFailure,
TimingSpike,
NonDeterministic,
}
#[derive(Debug, Clone)]
pub struct PerformanceThresholds {
pub max_frame_time_ms: u64,
pub max_memory_bytes: usize,
pub max_timing_variance: f64,
pub max_failure_rate: f64,
}
impl Default for PerformanceThresholds {
fn default() -> Self {
Self {
max_frame_time_ms: 100, max_memory_bytes: 64 * 1024 * 1024, max_timing_variance: 0.2, max_failure_rate: 0.01, }
}
}
#[derive(Debug, Clone)]
pub struct PerformanceResult {
pub passed: bool,
pub max_frame_ms: u64,
pub mean_frame_ms: f64,
pub variance: f64,
pub pass_rate: f64,
pub violations: Vec<String>,
}
#[must_use]
pub fn verify_performance(
report: &StressReport,
thresholds: &PerformanceThresholds,
) -> PerformanceResult {
let max_frame = report.max_frame_time_ms();
let mean_frame = report.mean_frame_time_ms();
let variance = report.timing_variance();
let pass_rate = report.pass_rate();
let mut violations = Vec::new();
if max_frame > thresholds.max_frame_time_ms {
violations.push(format!(
"Max frame time {}ms exceeds threshold {}ms",
max_frame, thresholds.max_frame_time_ms
));
}
if variance > thresholds.max_timing_variance {
violations.push(format!(
"Timing variance {:.3} exceeds threshold {:.3}",
variance, thresholds.max_timing_variance
));
}
if pass_rate < (1.0 - thresholds.max_failure_rate) {
violations.push(format!(
"Pass rate {:.1}% below threshold {:.1}%",
pass_rate * 100.0,
(1.0 - thresholds.max_failure_rate) * 100.0
));
}
PerformanceResult {
passed: violations.is_empty(),
max_frame_ms: max_frame,
mean_frame_ms: mean_frame,
variance,
pass_rate,
violations,
}
}
#[derive(Debug, Clone)]
pub struct StressRng {
state: u64,
inc: u64,
}
impl StressRng {
#[must_use]
pub fn new(seed: u64) -> Self {
let mut rng = Self {
state: 0,
inc: (seed << 1) | 1,
};
rng.next_u32();
rng.state = rng.state.wrapping_add(seed);
rng.next_u32();
rng
}
pub fn next_u32(&mut self) -> u32 {
let old_state = self.state;
self.state = old_state
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(self.inc);
let xorshifted = (((old_state >> 18) ^ old_state) >> 27) as u32;
let rot = (old_state >> 59) as u32;
(xorshifted >> rot) | (xorshifted << ((!rot).wrapping_add(1) & 31))
}
pub fn next_u64(&mut self) -> u64 {
let high = self.next_u32() as u64;
let low = self.next_u32() as u64;
(high << 32) | low
}
pub fn gen_f32(&mut self) -> f32 {
(self.next_u32() as f64 / u32::MAX as f64) as f32
}
pub fn gen_range_u32(&mut self, min: u32, max: u32) -> u32 {
if max <= min {
return min;
}
let range = max - min;
min + (self.next_u32() % range)
}
}
#[derive(Debug, Clone)]
pub struct StressConfig {
pub cycles: u32,
pub interval_ms: u64,
pub seed: u64,
pub min_input_size: usize,
pub max_input_size: usize,
pub thresholds: PerformanceThresholds,
}
impl Default for StressConfig {
fn default() -> Self {
Self {
cycles: 100,
interval_ms: 100,
seed: 42,
min_input_size: 64,
max_input_size: 512,
thresholds: PerformanceThresholds::default(),
}
}
}
pub struct StressTestRunner {
rng: StressRng,
config: StressConfig,
report: StressReport,
}
impl StressTestRunner {
#[must_use]
pub fn new(config: StressConfig) -> Self {
Self {
rng: StressRng::new(config.seed),
config,
report: StressReport::default(),
}
}
pub fn generate_input(&mut self) -> (u64, Vec<f32>) {
let seed = self.rng.next_u64();
let size = self.rng.gen_range_u32(
self.config.min_input_size as u32,
self.config.max_input_size as u32,
) as usize;
let mut input_rng = StressRng::new(seed);
let input: Vec<f32> = (0..size).map(|_| input_rng.gen_f32()).collect();
(seed, input)
}
pub fn run_cycle<F>(&mut self, cycle: u32, test_fn: F) -> FrameProfile
where
F: FnOnce(&[f32]) -> (u32, u32), {
let (input_seed, input) = self.generate_input();
let input_size = input.len();
let start = Instant::now();
let (tests_passed, tests_failed) = test_fn(&input);
let duration = start.elapsed();
let profile = FrameProfile {
cycle,
duration_ms: duration.as_millis() as u64,
memory_bytes: input_size * std::mem::size_of::<f32>(),
tests_passed,
tests_failed,
input_seed,
input_size,
};
if profile.duration_ms > self.config.thresholds.max_frame_time_ms {
self.report.anomalies.push(Anomaly {
cycle,
kind: AnomalyKind::SlowFrame,
description: format!(
"Frame {}ms exceeds threshold {}ms",
profile.duration_ms, self.config.thresholds.max_frame_time_ms
),
});
}
if tests_failed > 0 {
self.report.anomalies.push(Anomaly {
cycle,
kind: AnomalyKind::TestFailure,
description: format!("{} tests failed in cycle {}", tests_failed, cycle),
});
}
self.report.add_frame(profile.clone());
profile
}
pub fn run_all<F>(&mut self, mut test_fn: F) -> &StressReport
where
F: FnMut(&[f32]) -> (u32, u32),
{
let interval = Duration::from_millis(self.config.interval_ms);
for cycle in 0..self.config.cycles {
let start = Instant::now();
self.run_cycle(cycle, &mut test_fn);
let elapsed = start.elapsed();
if let Some(remaining) = interval.checked_sub(elapsed) {
std::thread::sleep(remaining);
}
}
&self.report
}
#[must_use]
pub fn report(&self) -> &StressReport {
&self.report
}
#[must_use]
pub fn verify(&self) -> PerformanceResult {
verify_performance(&self.report, &self.config.thresholds)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stress_rng_deterministic() {
let mut rng1 = StressRng::new(42);
let mut rng2 = StressRng::new(42);
for _ in 0..100 {
assert_eq!(rng1.next_u32(), rng2.next_u32());
}
}
#[test]
fn test_stress_rng_gen_range() {
let mut rng = StressRng::new(12345);
for _ in 0..1000 {
let val = rng.gen_range_u32(10, 100);
assert!(val >= 10 && val < 100);
}
}
#[test]
fn test_stress_rng_gen_f32() {
let mut rng = StressRng::new(99999);
for _ in 0..1000 {
let val = rng.gen_f32();
assert!((0.0..1.0).contains(&val));
}
}
#[test]
fn test_frame_profile_default() {
let profile = FrameProfile::default();
assert_eq!(profile.cycle, 0);
assert_eq!(profile.duration_ms, 0);
}
#[test]
fn test_stress_report_metrics() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 100,
tests_passed: 5,
tests_failed: 0,
..Default::default()
});
report.add_frame(FrameProfile {
cycle: 1,
duration_ms: 120,
tests_passed: 5,
tests_failed: 0,
..Default::default()
});
assert_eq!(report.cycles_completed, 2);
assert_eq!(report.total_passed, 10);
assert_eq!(report.total_failed, 0);
assert_eq!(report.mean_frame_time_ms(), 110.0);
assert_eq!(report.max_frame_time_ms(), 120);
assert!((report.pass_rate() - 1.0).abs() < 0.001);
}
#[test]
fn test_stress_report_variance() {
let mut report = StressReport::default();
for i in 0..10 {
report.add_frame(FrameProfile {
cycle: i,
duration_ms: 100,
tests_passed: 1,
tests_failed: 0,
..Default::default()
});
}
assert!((report.timing_variance()).abs() < 0.001);
}
#[test]
fn test_performance_thresholds_default() {
let thresholds = PerformanceThresholds::default();
assert_eq!(thresholds.max_frame_time_ms, 100);
assert_eq!(thresholds.max_memory_bytes, 64 * 1024 * 1024);
assert!((thresholds.max_timing_variance - 0.2).abs() < 0.001);
}
#[test]
fn test_verify_performance_pass() {
let mut report = StressReport::default();
for i in 0..10 {
report.add_frame(FrameProfile {
cycle: i,
duration_ms: 50,
tests_passed: 5,
tests_failed: 0,
..Default::default()
});
}
let result = verify_performance(&report, &PerformanceThresholds::default());
assert!(result.passed);
assert!(result.violations.is_empty());
}
#[test]
fn test_verify_performance_fail_slow() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 200, tests_passed: 5,
tests_failed: 0,
..Default::default()
});
let result = verify_performance(&report, &PerformanceThresholds::default());
assert!(!result.passed);
assert_eq!(result.violations.len(), 1);
assert!(result.violations[0].contains("Max frame time"));
}
#[test]
fn test_stress_runner_generate_input() {
let config = StressConfig {
min_input_size: 100,
max_input_size: 200,
seed: 42,
..Default::default()
};
let mut runner = StressTestRunner::new(config);
let (seed1, input1) = runner.generate_input();
let (seed2, input2) = runner.generate_input();
assert_ne!(seed1, seed2);
assert!(input1.len() >= 100 && input1.len() < 200);
assert!(input2.len() >= 100 && input2.len() < 200);
}
#[test]
fn test_stress_runner_run_cycle() {
let config = StressConfig {
cycles: 1,
seed: 42,
..Default::default()
};
let mut runner = StressTestRunner::new(config);
let profile = runner.run_cycle(0, |input| {
let positive = input.iter().filter(|&&v| v > 0.5).count() as u32;
(positive, 0)
});
assert_eq!(profile.cycle, 0);
assert!(profile.tests_passed > 0);
assert_eq!(profile.tests_failed, 0);
}
#[test]
fn test_anomaly_detection() {
let config = StressConfig {
cycles: 1,
seed: 42,
thresholds: PerformanceThresholds {
max_frame_time_ms: 1, ..Default::default()
},
..Default::default()
};
let mut runner = StressTestRunner::new(config);
runner.run_cycle(0, |input| {
std::thread::sleep(Duration::from_millis(5));
(input.len() as u32, 0)
});
let report = runner.report();
assert!(!report.anomalies.is_empty());
assert_eq!(report.anomalies[0].kind, AnomalyKind::SlowFrame);
}
#[test]
fn test_stress_report_empty_frames() {
let report = StressReport::default();
assert_eq!(report.mean_frame_time_ms(), 0.0);
assert_eq!(report.max_frame_time_ms(), 0);
}
#[test]
fn test_stress_report_single_frame_variance() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 100,
tests_passed: 1,
tests_failed: 0,
..Default::default()
});
assert_eq!(report.timing_variance(), 0.0);
}
#[test]
fn test_stress_report_zero_mean_variance() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 0, tests_passed: 1,
tests_failed: 0,
..Default::default()
});
report.add_frame(FrameProfile {
cycle: 1,
duration_ms: 0, tests_passed: 1,
tests_failed: 0,
..Default::default()
});
assert_eq!(report.timing_variance(), 0.0);
}
#[test]
fn test_stress_report_pass_rate_no_tests() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 100,
tests_passed: 0, tests_failed: 0, ..Default::default()
});
assert_eq!(report.pass_rate(), 1.0);
}
#[test]
fn test_stress_rng_next_u64() {
let mut rng = StressRng::new(42);
let val1 = rng.next_u64();
let val2 = rng.next_u64();
assert_ne!(val1, val2);
let mut rng2 = StressRng::new(42);
assert_eq!(val1, rng2.next_u64());
}
#[test]
fn test_stress_rng_gen_range_edge_cases() {
let mut rng = StressRng::new(42);
assert_eq!(rng.gen_range_u32(50, 50), 50);
assert_eq!(rng.gen_range_u32(100, 50), 100);
}
#[test]
fn test_test_failure_anomaly_detection() {
let config = StressConfig {
cycles: 1,
seed: 42,
..Default::default()
};
let mut runner = StressTestRunner::new(config);
runner.run_cycle(0, |_input| {
(3, 2) });
let report = runner.report();
assert_eq!(report.total_passed, 3);
assert_eq!(report.total_failed, 2);
let failure_anomalies: Vec<_> = report
.anomalies
.iter()
.filter(|a| a.kind == AnomalyKind::TestFailure)
.collect();
assert_eq!(failure_anomalies.len(), 1);
assert!(failure_anomalies[0].description.contains("2 tests failed"));
}
#[test]
fn test_verify_performance_fail_variance() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 10,
tests_passed: 1,
tests_failed: 0,
..Default::default()
});
report.add_frame(FrameProfile {
cycle: 1,
duration_ms: 100, tests_passed: 1,
tests_failed: 0,
..Default::default()
});
let thresholds = PerformanceThresholds {
max_frame_time_ms: 200, max_timing_variance: 0.01, max_failure_rate: 0.5, ..Default::default()
};
let result = verify_performance(&report, &thresholds);
assert!(!result.passed);
assert!(result.violations.iter().any(|v| v.contains("variance")));
}
#[test]
fn test_verify_performance_fail_pass_rate() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 50,
tests_passed: 1,
tests_failed: 9, ..Default::default()
});
let thresholds = PerformanceThresholds {
max_frame_time_ms: 200,
max_timing_variance: 1.0,
max_failure_rate: 0.05, ..Default::default()
};
let result = verify_performance(&report, &thresholds);
assert!(!result.passed);
assert!(result.violations.iter().any(|v| v.contains("Pass rate")));
}
#[test]
fn test_runner_verify_method() {
let config = StressConfig {
cycles: 1,
seed: 42,
thresholds: PerformanceThresholds::default(),
..Default::default()
};
let mut runner = StressTestRunner::new(config);
runner.run_cycle(0, |_input| (5, 0));
let result = runner.verify();
assert!(result.passed);
assert_eq!(result.pass_rate, 1.0);
}
#[test]
fn test_run_all_cycles() {
let config = StressConfig {
cycles: 3,
interval_ms: 1, seed: 42,
min_input_size: 10,
max_input_size: 20,
thresholds: PerformanceThresholds::default(),
};
let mut runner = StressTestRunner::new(config);
let report = runner.run_all(|input| {
let sum: f32 = input.iter().sum();
if sum > 0.0 {
(1, 0)
} else {
(0, 1)
}
});
assert_eq!(report.cycles_completed, 3);
assert_eq!(report.frames.len(), 3);
assert!(report.total_passed >= 1);
}
#[test]
fn test_run_all_with_slow_test() {
let config = StressConfig {
cycles: 2,
interval_ms: 1, seed: 42,
min_input_size: 10,
max_input_size: 20,
thresholds: PerformanceThresholds {
max_frame_time_ms: 1000, ..Default::default()
},
};
let mut runner = StressTestRunner::new(config);
let report = runner.run_all(|_input| {
std::thread::sleep(Duration::from_millis(5));
(1, 0)
});
assert_eq!(report.cycles_completed, 2);
}
#[test]
fn test_anomaly_kinds_equality() {
assert_eq!(AnomalyKind::SlowFrame, AnomalyKind::SlowFrame);
assert_ne!(AnomalyKind::SlowFrame, AnomalyKind::HighMemory);
assert_ne!(AnomalyKind::TestFailure, AnomalyKind::TimingSpike);
assert_ne!(AnomalyKind::NonDeterministic, AnomalyKind::HighMemory);
}
#[test]
fn test_stress_config_default() {
let config = StressConfig::default();
assert_eq!(config.cycles, 100);
assert_eq!(config.interval_ms, 100);
assert_eq!(config.seed, 42);
assert_eq!(config.min_input_size, 64);
assert_eq!(config.max_input_size, 512);
}
#[test]
fn test_frame_profile_clone() {
let profile = FrameProfile {
cycle: 5,
duration_ms: 100,
memory_bytes: 1024,
tests_passed: 10,
tests_failed: 2,
input_seed: 12345,
input_size: 256,
};
let cloned = profile.clone();
assert_eq!(profile.cycle, cloned.cycle);
assert_eq!(profile.duration_ms, cloned.duration_ms);
assert_eq!(profile.memory_bytes, cloned.memory_bytes);
assert_eq!(profile.tests_passed, cloned.tests_passed);
assert_eq!(profile.tests_failed, cloned.tests_failed);
assert_eq!(profile.input_seed, cloned.input_seed);
assert_eq!(profile.input_size, cloned.input_size);
}
#[test]
fn test_stress_report_clone() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 50,
tests_passed: 5,
tests_failed: 1,
..Default::default()
});
report.anomalies.push(Anomaly {
cycle: 0,
kind: AnomalyKind::SlowFrame,
description: "Test anomaly".to_string(),
});
let cloned = report.clone();
assert_eq!(report.cycles_completed, cloned.cycles_completed);
assert_eq!(report.total_passed, cloned.total_passed);
assert_eq!(report.total_failed, cloned.total_failed);
assert_eq!(report.frames.len(), cloned.frames.len());
assert_eq!(report.anomalies.len(), cloned.anomalies.len());
}
#[test]
fn test_anomaly_clone() {
let anomaly = Anomaly {
cycle: 42,
kind: AnomalyKind::HighMemory,
description: "Memory exceeded threshold".to_string(),
};
let cloned = anomaly.clone();
assert_eq!(anomaly.cycle, cloned.cycle);
assert_eq!(anomaly.kind, cloned.kind);
assert_eq!(anomaly.description, cloned.description);
}
#[test]
fn test_performance_thresholds_clone() {
let thresholds = PerformanceThresholds {
max_frame_time_ms: 50,
max_memory_bytes: 1024,
max_timing_variance: 0.1,
max_failure_rate: 0.05,
};
let cloned = thresholds.clone();
assert_eq!(thresholds.max_frame_time_ms, cloned.max_frame_time_ms);
assert_eq!(thresholds.max_memory_bytes, cloned.max_memory_bytes);
assert!((thresholds.max_timing_variance - cloned.max_timing_variance).abs() < 0.001);
assert!((thresholds.max_failure_rate - cloned.max_failure_rate).abs() < 0.001);
}
#[test]
fn test_performance_result_clone() {
let result = PerformanceResult {
passed: false,
max_frame_ms: 100,
mean_frame_ms: 75.5,
variance: 0.15,
pass_rate: 0.95,
violations: vec!["Test violation".to_string()],
};
let cloned = result.clone();
assert_eq!(result.passed, cloned.passed);
assert_eq!(result.max_frame_ms, cloned.max_frame_ms);
assert!((result.mean_frame_ms - cloned.mean_frame_ms).abs() < 0.001);
assert!((result.variance - cloned.variance).abs() < 0.001);
assert!((result.pass_rate - cloned.pass_rate).abs() < 0.001);
assert_eq!(result.violations.len(), cloned.violations.len());
}
#[test]
fn test_stress_rng_clone() {
let mut rng = StressRng::new(42);
rng.next_u32();
let cloned = rng.clone();
assert_eq!(rng.next_u32(), cloned.clone().next_u32());
}
#[test]
fn test_stress_config_clone() {
let config = StressConfig {
cycles: 50,
interval_ms: 200,
seed: 12345,
min_input_size: 128,
max_input_size: 1024,
thresholds: PerformanceThresholds::default(),
};
let cloned = config.clone();
assert_eq!(config.cycles, cloned.cycles);
assert_eq!(config.interval_ms, cloned.interval_ms);
assert_eq!(config.seed, cloned.seed);
assert_eq!(config.min_input_size, cloned.min_input_size);
assert_eq!(config.max_input_size, cloned.max_input_size);
}
#[test]
fn test_stress_report_with_timing_variance() {
let mut report = StressReport::default();
for i in 0..5 {
report.add_frame(FrameProfile {
cycle: i,
duration_ms: if i % 2 == 0 { 50 } else { 150 },
tests_passed: 1,
tests_failed: 0,
..Default::default()
});
}
let variance = report.timing_variance();
assert!(variance > 0.0);
}
#[test]
fn test_multiple_anomaly_kinds() {
let anomalies = vec![
Anomaly {
cycle: 0,
kind: AnomalyKind::SlowFrame,
description: "Slow".to_string(),
},
Anomaly {
cycle: 1,
kind: AnomalyKind::HighMemory,
description: "High memory".to_string(),
},
Anomaly {
cycle: 2,
kind: AnomalyKind::TestFailure,
description: "Test failed".to_string(),
},
Anomaly {
cycle: 3,
kind: AnomalyKind::TimingSpike,
description: "Spike".to_string(),
},
Anomaly {
cycle: 4,
kind: AnomalyKind::NonDeterministic,
description: "Non-deterministic".to_string(),
},
];
for a in &anomalies {
let debug_str = format!("{:?}", a);
assert!(debug_str.contains("Anomaly"));
}
assert_eq!(anomalies.len(), 5);
}
#[test]
fn test_stress_report_debug() {
let mut report = StressReport::default();
report.add_frame(FrameProfile::default());
let debug_str = format!("{:?}", report);
assert!(debug_str.contains("StressReport"));
assert!(debug_str.contains("frames"));
}
#[test]
fn test_frame_profile_debug() {
let profile = FrameProfile {
cycle: 1,
duration_ms: 100,
..Default::default()
};
let debug_str = format!("{:?}", profile);
assert!(debug_str.contains("FrameProfile"));
assert!(debug_str.contains("cycle"));
}
#[test]
fn test_performance_thresholds_debug() {
let thresholds = PerformanceThresholds::default();
let debug_str = format!("{:?}", thresholds);
assert!(debug_str.contains("PerformanceThresholds"));
}
#[test]
fn test_performance_result_debug() {
let result = PerformanceResult {
passed: true,
max_frame_ms: 50,
mean_frame_ms: 40.0,
variance: 0.1,
pass_rate: 1.0,
violations: vec![],
};
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("PerformanceResult"));
}
#[test]
fn test_stress_rng_debug() {
let rng = StressRng::new(42);
let debug_str = format!("{:?}", rng);
assert!(debug_str.contains("StressRng"));
}
#[test]
fn test_stress_config_debug() {
let config = StressConfig::default();
let debug_str = format!("{:?}", config);
assert!(debug_str.contains("StressConfig"));
}
#[test]
fn test_anomaly_kind_debug() {
let kind = AnomalyKind::SlowFrame;
let copied = kind; let debug_str = format!("{:?}", copied);
assert!(debug_str.contains("SlowFrame"));
}
#[test]
fn test_frame_profile_all_fields() {
let profile = FrameProfile {
cycle: 10,
duration_ms: 50,
memory_bytes: 4096,
tests_passed: 8,
tests_failed: 2,
input_seed: 999,
input_size: 128,
};
assert_eq!(profile.cycle, 10);
assert_eq!(profile.duration_ms, 50);
assert_eq!(profile.memory_bytes, 4096);
assert_eq!(profile.tests_passed, 8);
assert_eq!(profile.tests_failed, 2);
assert_eq!(profile.input_seed, 999);
assert_eq!(profile.input_size, 128);
}
#[test]
fn test_stress_report_default_values() {
let report = StressReport::default();
assert!(report.frames.is_empty());
assert_eq!(report.cycles_completed, 0);
assert_eq!(report.total_passed, 0);
assert_eq!(report.total_failed, 0);
assert!(report.anomalies.is_empty());
}
#[test]
fn test_performance_result_all_fields() {
let result = PerformanceResult {
passed: true,
max_frame_ms: 75,
mean_frame_ms: 50.5,
variance: 0.12,
pass_rate: 0.98,
violations: vec!["violation1".to_string(), "violation2".to_string()],
};
assert!(result.passed);
assert_eq!(result.max_frame_ms, 75);
assert!((result.mean_frame_ms - 50.5).abs() < 0.001);
assert!((result.variance - 0.12).abs() < 0.001);
assert!((result.pass_rate - 0.98).abs() < 0.001);
assert_eq!(result.violations.len(), 2);
}
#[test]
fn test_performance_thresholds_all_fields() {
let thresholds = PerformanceThresholds {
max_frame_time_ms: 150,
max_memory_bytes: 1024 * 1024,
max_timing_variance: 0.3,
max_failure_rate: 0.1,
};
assert_eq!(thresholds.max_frame_time_ms, 150);
assert_eq!(thresholds.max_memory_bytes, 1024 * 1024);
assert!((thresholds.max_timing_variance - 0.3).abs() < 0.001);
assert!((thresholds.max_failure_rate - 0.1).abs() < 0.001);
}
#[test]
fn test_anomaly_all_fields() {
let anomaly = Anomaly {
cycle: 5,
kind: AnomalyKind::TimingSpike,
description: "Timing spike detected at cycle 5".to_string(),
};
assert_eq!(anomaly.cycle, 5);
assert_eq!(anomaly.kind, AnomalyKind::TimingSpike);
assert!(anomaly.description.contains("cycle 5"));
}
#[test]
fn test_stress_config_all_fields() {
let config = StressConfig {
cycles: 200,
interval_ms: 50,
seed: 12345,
min_input_size: 32,
max_input_size: 1024,
thresholds: PerformanceThresholds {
max_frame_time_ms: 200,
max_memory_bytes: 128 * 1024 * 1024,
max_timing_variance: 0.25,
max_failure_rate: 0.02,
},
};
assert_eq!(config.cycles, 200);
assert_eq!(config.interval_ms, 50);
assert_eq!(config.seed, 12345);
assert_eq!(config.min_input_size, 32);
assert_eq!(config.max_input_size, 1024);
assert_eq!(config.thresholds.max_frame_time_ms, 200);
}
#[test]
fn test_stress_runner_memory_bytes_calculation() {
let config = StressConfig {
cycles: 1,
seed: 42,
min_input_size: 100,
max_input_size: 101, ..Default::default()
};
let mut runner = StressTestRunner::new(config);
let profile = runner.run_cycle(0, |input| (input.len() as u32, 0));
assert_eq!(
profile.memory_bytes,
profile.input_size * std::mem::size_of::<f32>()
);
}
#[test]
fn test_verify_performance_multiple_violations() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 200, tests_passed: 1,
tests_failed: 99, ..Default::default()
});
report.add_frame(FrameProfile {
cycle: 1,
duration_ms: 10, tests_passed: 1,
tests_failed: 0,
..Default::default()
});
let thresholds = PerformanceThresholds {
max_frame_time_ms: 100, max_timing_variance: 0.1, max_failure_rate: 0.01, ..Default::default()
};
let result = verify_performance(&report, &thresholds);
assert!(!result.passed);
assert!(result.violations.len() >= 2); }
#[test]
fn test_stress_rng_sequence_consistency() {
let mut rng = StressRng::new(42);
let seq1: Vec<u32> = (0..10).map(|_| rng.next_u32()).collect();
let mut rng2 = StressRng::new(42);
let seq2: Vec<u32> = (0..10).map(|_| rng2.next_u32()).collect();
assert_eq!(seq1, seq2);
}
#[test]
fn test_stress_rng_different_seeds() {
let mut rng1 = StressRng::new(1);
let mut rng2 = StressRng::new(2);
let val1 = rng1.next_u32();
let val2 = rng2.next_u32();
assert_ne!(val1, val2);
}
#[test]
fn test_stress_runner_input_generation_determinism() {
let config1 = StressConfig {
seed: 12345,
min_input_size: 50,
max_input_size: 100,
..Default::default()
};
let config2 = StressConfig {
seed: 12345,
min_input_size: 50,
max_input_size: 100,
..Default::default()
};
let mut runner1 = StressTestRunner::new(config1);
let mut runner2 = StressTestRunner::new(config2);
let (seed1, input1) = runner1.generate_input();
let (seed2, input2) = runner2.generate_input();
assert_eq!(seed1, seed2);
assert_eq!(input1, input2);
}
#[test]
fn test_run_all_with_zero_interval() {
let config = StressConfig {
cycles: 3,
interval_ms: 0, seed: 42,
min_input_size: 10,
max_input_size: 20,
thresholds: PerformanceThresholds::default(),
};
let mut runner = StressTestRunner::new(config);
let report = runner.run_all(|_input| (1, 0));
assert_eq!(report.cycles_completed, 3);
}
#[test]
fn test_verify_performance_boundary_threshold() {
let mut report = StressReport::default();
report.add_frame(FrameProfile {
cycle: 0,
duration_ms: 100, tests_passed: 99,
tests_failed: 1, ..Default::default()
});
let thresholds = PerformanceThresholds {
max_frame_time_ms: 100, max_timing_variance: 1.0,
max_failure_rate: 0.01, ..Default::default()
};
let result = verify_performance(&report, &thresholds);
assert!(result.passed || result.violations.len() <= 1);
}
#[test]
fn test_stress_report_anomalies_field() {
let mut report = StressReport::default();
report.anomalies.push(Anomaly {
cycle: 0,
kind: AnomalyKind::HighMemory,
description: "Memory exceeded".to_string(),
});
assert_eq!(report.anomalies.len(), 1);
assert_eq!(report.anomalies[0].kind, AnomalyKind::HighMemory);
}
#[test]
fn test_stress_rng_gen_f32_range() {
let mut rng = StressRng::new(42);
for _ in 0..1000 {
let val = rng.gen_f32();
assert!(val >= 0.0, "Value should be >= 0.0");
assert!(val < 1.0, "Value should be < 1.0");
}
}
#[test]
fn test_anomaly_kind_copy_semantics() {
let kind1 = AnomalyKind::NonDeterministic;
let kind2 = kind1; let kind3 = kind1;
assert_eq!(kind1, kind2);
assert_eq!(kind2, kind3);
}
#[test]
fn test_performance_result_with_empty_violations() {
let result = PerformanceResult {
passed: true,
max_frame_ms: 50,
mean_frame_ms: 40.0,
variance: 0.05,
pass_rate: 1.0,
violations: Vec::new(),
};
assert!(result.passed);
assert!(result.violations.is_empty());
}
#[test]
fn test_stress_runner_report_method() {
let config = StressConfig::default();
let runner = StressTestRunner::new(config);
let report = runner.report();
assert_eq!(report.cycles_completed, 0);
assert!(report.frames.is_empty());
}
#[test]
fn test_run_cycle_with_failures_and_slow_frame() {
let config = StressConfig {
cycles: 1,
seed: 42,
thresholds: PerformanceThresholds {
max_frame_time_ms: 1, ..Default::default()
},
..Default::default()
};
let mut runner = StressTestRunner::new(config);
runner.run_cycle(0, |_input| {
std::thread::sleep(Duration::from_millis(5));
(3, 5) });
let report = runner.report();
let slow_count = report
.anomalies
.iter()
.filter(|a| a.kind == AnomalyKind::SlowFrame)
.count();
let failure_count = report
.anomalies
.iter()
.filter(|a| a.kind == AnomalyKind::TestFailure)
.count();
assert_eq!(slow_count, 1, "Should have one SlowFrame anomaly");
assert_eq!(failure_count, 1, "Should have one TestFailure anomaly");
}
}