use super::*;
#[test]
fn f029_latency_exceeded() {
let mut validator =
StreamingUxValidator::new().with_max_latency(Duration::from_millis(100));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(150)));
let result = validator.validate();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(
err,
StreamingValidationError::LatencyExceeded { .. }
));
}
#[test]
fn f030_latency_acceptable() {
let mut validator =
StreamingUxValidator::new().with_max_latency(Duration::from_millis(100));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
assert!(validator.validate().is_ok());
}
#[test]
fn f031_buffer_underrun_threshold() {
let mut validator = StreamingUxValidator::new().with_buffer_underrun_threshold(2);
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::BufferUnderrun);
let result = validator.validate();
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
StreamingValidationError::BufferUnderrunThreshold { .. }
));
}
#[test]
fn f032_dropped_frames_threshold() {
let mut validator = StreamingUxValidator::new().with_max_dropped_frames(2);
for _ in 0..5 {
validator.record_metric(StreamingMetric::FrameDropped);
}
let result = validator.validate();
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
StreamingValidationError::DroppedFrameThreshold { .. }
));
}
#[test]
fn f033_state_idle_to_buffering() {
let mut validator = StreamingUxValidator::new();
assert_eq!(validator.state(), StreamingState::Idle);
validator.record_metric(StreamingMetric::FirstByteReceived);
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn f034_state_buffering_to_streaming() {
let mut validator = StreamingUxValidator::new();
validator.start();
assert_eq!(validator.state(), StreamingState::Buffering);
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn f035_state_streaming_to_stalled() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::BufferUnderrun);
assert_eq!(validator.state(), StreamingState::Stalled);
}
#[test]
fn f036_state_recovery_from_stalled() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
validator.record_metric(StreamingMetric::BufferUnderrun);
assert_eq!(validator.state(), StreamingState::Stalled);
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 1000 });
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn f037_fps_calculation() {
let mut validator = StreamingUxValidator::new();
for i in 0..31 {
validator.record_metric(StreamingMetric::FrameRendered {
timestamp: i * 33, });
}
let fps = validator.average_fps();
assert!((fps - 30.0).abs() < 1.0, "FPS was {fps}, expected ~30");
}
#[test]
fn f038_fps_below_minimum() {
let mut validator = StreamingUxValidator::new().with_min_fps(30.0);
for i in 0..16 {
validator.record_metric(StreamingMetric::FrameRendered {
timestamp: i * 66, });
}
let result = validator.validate();
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
StreamingValidationError::FpsBelowMinimum { .. }
));
}
#[test]
fn test_default_validator() {
let validator = StreamingUxValidator::new();
assert_eq!(validator.state(), StreamingState::Idle);
assert_eq!(validator.buffer_underruns(), 0);
assert_eq!(validator.dropped_frames(), 0);
}
#[test]
fn test_audio_preset() {
let validator = StreamingUxValidator::for_audio();
assert_eq!(validator.max_latency, Duration::from_millis(100));
assert_eq!(validator.buffer_underrun_threshold, 3);
}
#[test]
fn test_video_preset() {
let validator = StreamingUxValidator::for_video();
assert_eq!(validator.max_latency, Duration::from_millis(500));
assert!((validator.min_fps - 30.0).abs() < f64::EPSILON);
}
#[test]
fn test_complete_transition() {
let mut validator = StreamingUxValidator::new();
validator.complete();
assert_eq!(validator.state(), StreamingState::Completed);
}
#[test]
fn test_error_transition() {
let mut validator = StreamingUxValidator::new();
validator.error();
assert_eq!(validator.state(), StreamingState::Error);
assert!(validator.validate().is_err());
}
#[test]
fn test_reset() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::FrameDropped);
validator.reset();
assert_eq!(validator.state(), StreamingState::Idle);
assert_eq!(validator.buffer_underruns(), 0);
assert_eq!(validator.dropped_frames(), 0);
}
#[test]
fn test_validate_all_errors() {
let mut validator = StreamingUxValidator::new()
.with_max_latency(Duration::from_millis(50))
.with_buffer_underrun_threshold(1);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(100)));
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::BufferUnderrun);
let errors = validator.validate_all();
assert!(errors.len() >= 2);
}
#[test]
fn test_state_history() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
let history = validator.state_history();
assert!(!history.is_empty());
assert_eq!(history[0].0, StreamingState::Idle);
}
#[test]
fn test_buffer_level_transitions() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::BufferLevel(0.05));
assert_eq!(validator.state(), StreamingState::Stalled);
validator.record_metric(StreamingMetric::BufferLevel(0.5));
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_streaming_state_display() {
assert_eq!(format!("{}", StreamingState::Idle), "Idle");
assert_eq!(format!("{}", StreamingState::Streaming), "Streaming");
assert_eq!(format!("{}", StreamingState::Stalled), "Stalled");
}
#[test]
fn f039_vu_meter_negative_level_rejected() {
let config = VuMeterConfig::default();
let result = config.validate_sample(-0.5);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
VuMeterError::NegativeLevel(_)
));
}
#[test]
fn f040_vu_meter_clipping_detected() {
let config = VuMeterConfig::default().with_max_level(1.0);
let result = config.validate_sample(1.5);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), VuMeterError::Clipping(_)));
}
#[test]
fn f041_vu_meter_valid_level_accepted() {
let config = VuMeterConfig::default();
assert!(config.validate_sample(0.5).is_ok());
assert!(config.validate_sample(0.0).is_ok());
assert!(config.validate_sample(1.0).is_ok());
}
#[test]
fn f042_vu_meter_config_builder() {
let config = VuMeterConfig::default()
.with_min_level(0.1)
.with_max_level(0.9)
.with_update_rate_hz(60.0)
.with_max_stale_ms(50);
assert!((config.min_level - 0.1).abs() < f32::EPSILON);
assert!((config.max_level - 0.9).abs() < f32::EPSILON);
assert!((config.update_rate_hz - 60.0).abs() < f32::EPSILON);
assert_eq!(config.max_stale_ms, 50);
}
#[test]
fn f043_vu_meter_level_clamping() {
let config = VuMeterConfig::default()
.with_min_level(-5.0)
.with_max_level(10.0);
assert!((config.min_level - 0.0).abs() < f32::EPSILON);
assert!((config.max_level - 1.0).abs() < f32::EPSILON);
}
#[test]
fn f044_vu_meter_min_update_rate() {
let config = VuMeterConfig::default().with_update_rate_hz(0.1);
assert!((config.update_rate_hz - 1.0).abs() < f32::EPSILON);
}
#[test]
fn f045_vu_meter_error_display() {
let negative = VuMeterError::NegativeLevel(-0.5);
assert!(negative.to_string().contains("negative"));
let clipping = VuMeterError::Clipping(1.5);
assert!(clipping.to_string().contains("clipping"));
let stale = VuMeterError::Stale {
last_update_ms: 100,
current_ms: 300,
};
assert!(stale.to_string().contains("stale"));
let slow = VuMeterError::SlowUpdateRate {
measured_hz: 10.0,
expected_hz: 30.0,
};
assert!(slow.to_string().contains("slow"));
let not_animating = VuMeterError::NotAnimating {
sample_count: 10,
value: 0.5,
};
assert!(not_animating.to_string().contains("not animating"));
}
#[test]
fn f046_state_transition_tracking() {
let transition = StateTransition {
from: "Idle".to_string(),
to: "Recording".to_string(),
timestamp_ms: 1000.0,
duration_ms: 500.0,
};
assert_eq!(transition.from, "Idle");
assert_eq!(transition.to, "Recording");
assert!((transition.timestamp_ms - 1000.0).abs() < f64::EPSILON);
assert!((transition.duration_ms - 500.0).abs() < f64::EPSILON);
}
#[test]
fn f047_partial_result_tracking() {
let partial = PartialResult {
timestamp_ms: 1500.0,
text: "Hello wo".to_string(),
is_final: false,
};
assert!(!partial.is_final);
assert_eq!(partial.text, "Hello wo");
let final_result = PartialResult {
timestamp_ms: 2000.0,
text: "Hello world".to_string(),
is_final: true,
};
assert!(final_result.is_final);
}
#[test]
fn f048_vu_meter_sample_tracking() {
let samples = vec![
VuMeterSample {
timestamp_ms: 0.0,
level: 0.1,
},
VuMeterSample {
timestamp_ms: 33.3,
level: 0.3,
},
VuMeterSample {
timestamp_ms: 66.6,
level: 0.5,
},
VuMeterSample {
timestamp_ms: 100.0,
level: 0.4,
},
];
let avg: f32 = samples.iter().map(|s| s.level).sum::<f32>() / samples.len() as f32;
assert!((avg - 0.325).abs() < 0.01);
let duration = samples.last().unwrap().timestamp_ms - samples.first().unwrap().timestamp_ms;
assert!((duration - 100.0).abs() < f64::EPSILON);
}
#[test]
fn f049_test_execution_stats_creation() {
let stats = TestExecutionStats::new();
assert_eq!(stats.states_captured, 0);
assert_eq!(stats.bytes_raw, 0);
assert_eq!(stats.bytes_compressed, 0);
assert_eq!(stats.same_fill_pages, 0);
}
#[test]
fn f050_test_execution_stats_recording() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(4096, 1024);
stats.record_state_capture(4096, 2048);
assert_eq!(stats.states_captured, 2);
assert_eq!(stats.bytes_raw, 8192);
assert_eq!(stats.bytes_compressed, 3072);
}
#[test]
fn f051_test_execution_stats_compression_ratio() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(4000, 1000);
let ratio = stats.compression_ratio();
assert!((ratio - 4.0).abs() < 0.01);
}
#[test]
fn f052_test_execution_stats_efficiency() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(1000, 250);
let efficiency = stats.efficiency();
assert!((efficiency - 0.75).abs() < 0.01);
}
#[test]
fn f053_test_execution_stats_storage_savings() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(5_000_000, 1_000_000);
let savings = stats.storage_savings_mb();
assert!((savings - 4.0).abs() < 0.01);
}
#[test]
fn f054_test_execution_stats_same_fill_detection() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(4096, 100); stats.record_state_capture(4096, 1024);
assert_eq!(stats.same_fill_pages, 1);
assert!((stats.same_fill_ratio() - 0.5).abs() < 0.01);
}
#[test]
fn f055_test_execution_stats_reset() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(4096, 1024);
stats.reset();
assert_eq!(stats.states_captured, 0);
assert_eq!(stats.bytes_raw, 0);
assert_eq!(stats.bytes_compressed, 0);
}
#[test]
fn f056_test_execution_stats_edge_cases() {
let mut stats = TestExecutionStats::new();
assert!((stats.compression_ratio() - 0.0).abs() < f64::EPSILON);
assert!((stats.efficiency() - 0.0).abs() < f64::EPSILON);
assert!((stats.same_fill_ratio() - 0.0).abs() < f64::EPSILON);
stats.record_state_capture(1000, 0);
assert!((stats.compression_ratio() - 0.0).abs() < f64::EPSILON); }
#[test]
fn f057_screenshot_content_uniform_detection() {
let pixels: Vec<u8> = vec![255; 1000];
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 255 }
));
assert!((content.entropy() - 0.0).abs() < f32::EPSILON);
}
#[test]
fn f058_screenshot_content_ui_dominated() {
let mut pixels = vec![255u8; 900]; pixels.extend(vec![0u8; 50]); pixels.extend(vec![128u8; 50]);
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(
content,
ScreenshotContent::UiDominated { .. } | ScreenshotContent::Uniform { .. }
));
}
#[test]
fn f059_screenshot_content_high_entropy() {
let pixels: Vec<u8> = (0..1000).map(|i| ((i * 127 + 37) % 256) as u8).collect();
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(
content,
ScreenshotContent::GameWorld { .. } | ScreenshotContent::HighEntropy { .. }
));
}
#[test]
fn f060_screenshot_content_compression_algorithm() {
let uniform = ScreenshotContent::Uniform { fill_value: 0 };
assert_eq!(uniform.recommended_algorithm(), CompressionAlgorithm::Rle);
let ui = ScreenshotContent::UiDominated { entropy: 2.0 };
assert_eq!(ui.recommended_algorithm(), CompressionAlgorithm::Png);
let game = ScreenshotContent::GameWorld { entropy: 4.5 };
assert_eq!(game.recommended_algorithm(), CompressionAlgorithm::Zstd);
let high = ScreenshotContent::HighEntropy { entropy: 7.0 };
assert_eq!(high.recommended_algorithm(), CompressionAlgorithm::Lz4);
}
#[test]
fn f061_screenshot_content_ratio_hints() {
let uniform = ScreenshotContent::Uniform { fill_value: 0 };
assert!(uniform.expected_ratio_hint().contains("excellent"));
let ui = ScreenshotContent::UiDominated { entropy: 2.0 };
assert!(ui.expected_ratio_hint().contains("good"));
let game = ScreenshotContent::GameWorld { entropy: 4.5 };
assert!(game.expected_ratio_hint().contains("moderate"));
let high = ScreenshotContent::HighEntropy { entropy: 7.0 };
assert!(high.expected_ratio_hint().contains("poor"));
}
#[test]
fn f062_screenshot_content_empty_input() {
let content = ScreenshotContent::classify(&[]);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 0 }
));
}
#[test]
fn f063_screenshot_content_entropy_extraction() {
let variants = [
ScreenshotContent::UiDominated { entropy: 1.5 },
ScreenshotContent::GameWorld { entropy: 4.0 },
ScreenshotContent::HighEntropy { entropy: 7.5 },
ScreenshotContent::Uniform { fill_value: 128 },
];
let entropies: Vec<f32> = variants.iter().map(|v| v.entropy()).collect();
assert!((entropies[0] - 1.5).abs() < f32::EPSILON);
assert!((entropies[1] - 4.0).abs() < f32::EPSILON);
assert!((entropies[2] - 7.5).abs() < f32::EPSILON);
assert!((entropies[3] - 0.0).abs() < f32::EPSILON); }
#[test]
fn test_execution_stats_start_stop_throughput() {
let mut stats = TestExecutionStats::new();
stats.start();
stats.record_state_capture(1_000_000, 100_000);
stats.record_state_capture(1_000_000, 100_000);
stats.stop();
let throughput = stats.compress_throughput();
assert!(throughput >= 0.0);
}
#[test]
fn test_execution_stats_throughput_no_timing() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(1000, 100);
assert!((stats.compress_throughput() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_execution_stats_throughput_start_only() {
let mut stats = TestExecutionStats::new();
stats.start();
stats.record_state_capture(1000, 100);
assert!((stats.compress_throughput() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_streaming_validation_error_display() {
let latency_err = StreamingValidationError::LatencyExceeded {
measured: Duration::from_millis(500),
max: Duration::from_millis(100),
};
assert!(latency_err.to_string().contains("exceeded"));
let underrun_err = StreamingValidationError::BufferUnderrunThreshold {
count: 10,
threshold: 5,
};
assert!(underrun_err.to_string().contains("Buffer underruns"));
let dropped_err = StreamingValidationError::DroppedFrameThreshold { count: 20, max: 10 };
assert!(dropped_err.to_string().contains("Dropped frames"));
let fps_err = StreamingValidationError::FpsBelowMinimum {
measured: 15.0,
min: 30.0,
};
assert!(fps_err.to_string().contains("FPS below"));
let ttfb_err = StreamingValidationError::TtfbExceeded {
measured: Duration::from_secs(5),
max: Duration::from_secs(2),
};
assert!(ttfb_err.to_string().contains("first byte"));
let transition_err = StreamingValidationError::InvalidStateTransition {
from: StreamingState::Idle,
to: StreamingState::Completed,
};
assert!(transition_err.to_string().contains("Invalid state"));
let error_err = StreamingValidationError::EndedInError;
assert!(error_err.to_string().contains("error state"));
}
#[test]
fn test_streaming_state_default() {
let state: StreamingState = Default::default();
assert_eq!(state, StreamingState::Idle);
}
#[test]
fn test_streaming_state_display_all_variants() {
assert_eq!(format!("{}", StreamingState::Idle), "Idle");
assert_eq!(format!("{}", StreamingState::Buffering), "Buffering");
assert_eq!(format!("{}", StreamingState::Streaming), "Streaming");
assert_eq!(format!("{}", StreamingState::Stalled), "Stalled");
assert_eq!(format!("{}", StreamingState::Error), "Error");
assert_eq!(format!("{}", StreamingState::Completed), "Completed");
}
#[test]
fn test_streaming_metric_record_creation() {
let record = StreamingMetricRecord {
metric: StreamingMetric::BufferUnderrun,
timestamp: Instant::now(),
};
assert!(matches!(record.metric, StreamingMetric::BufferUnderrun));
}
#[test]
fn test_streaming_ux_validator_default() {
let validator: StreamingUxValidator = Default::default();
assert_eq!(validator.state(), StreamingState::Idle);
}
#[test]
fn test_ttfb_validation() {
let mut validator =
StreamingUxValidator::new().with_ttfb_timeout(Duration::from_millis(100));
validator.start();
std::thread::sleep(Duration::from_millis(150));
validator.record_metric(StreamingMetric::FirstByteReceived);
let result = validator.validate();
assert!(result.is_err());
if let Err(err) = result {
assert!(matches!(err, StreamingValidationError::TtfbExceeded { .. }));
}
}
#[test]
fn test_ttfb_validation_success() {
let mut validator = StreamingUxValidator::new().with_ttfb_timeout(Duration::from_secs(5));
validator.start();
validator.record_metric(StreamingMetric::FirstByteReceived);
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
let result = validator.validate();
assert!(result.is_ok());
}
#[test]
fn test_compression_algorithm_enum() {
assert_ne!(CompressionAlgorithm::Lz4, CompressionAlgorithm::Zstd);
assert_ne!(CompressionAlgorithm::Zstd, CompressionAlgorithm::Png);
assert_ne!(CompressionAlgorithm::Png, CompressionAlgorithm::Rle);
}
#[test]
fn test_vu_meter_config_debug() {
let config = VuMeterConfig::default();
let debug_str = format!("{:?}", config);
assert!(debug_str.contains("VuMeterConfig"));
}
#[test]
fn test_state_transition_debug() {
let transition = StateTransition {
from: "Idle".to_string(),
to: "Recording".to_string(),
timestamp_ms: 1000.0,
duration_ms: 500.0,
};
let debug_str = format!("{:?}", transition);
assert!(debug_str.contains("StateTransition"));
}
#[test]
fn test_partial_result_debug() {
let partial = PartialResult {
timestamp_ms: 1500.0,
text: "Hello".to_string(),
is_final: false,
};
let debug_str = format!("{:?}", partial);
assert!(debug_str.contains("PartialResult"));
}
#[test]
fn test_vu_meter_sample_debug() {
let sample = VuMeterSample {
timestamp_ms: 100.0,
level: 0.5,
};
let debug_str = format!("{:?}", sample);
assert!(debug_str.contains("VuMeterSample"));
}
#[test]
fn test_test_execution_stats_debug() {
let stats = TestExecutionStats::new();
let debug_str = format!("{:?}", stats);
assert!(debug_str.contains("TestExecutionStats"));
}
#[test]
fn test_screenshot_content_debug() {
let content = ScreenshotContent::UiDominated { entropy: 2.0 };
let debug_str = format!("{:?}", content);
assert!(debug_str.contains("UiDominated"));
}
#[test]
fn test_streaming_metric_debug() {
let metric = StreamingMetric::Latency(Duration::from_millis(50));
let debug_str = format!("{:?}", metric);
assert!(debug_str.contains("Latency"));
}
#[test]
fn test_streaming_validation_error_as_error() {
let err = StreamingValidationError::EndedInError;
let _: &dyn std::error::Error = &err;
}
#[test]
fn test_vu_meter_error_as_error() {
let err = VuMeterError::NegativeLevel(-0.5);
let _: &dyn std::error::Error = &err;
}
#[test]
fn test_streaming_metric_all_variants() {
let metrics = vec![
StreamingMetric::Latency(Duration::from_millis(50)),
StreamingMetric::FrameRendered { timestamp: 1000 },
StreamingMetric::FrameDropped,
StreamingMetric::BufferUnderrun,
StreamingMetric::FirstByteReceived,
StreamingMetric::BufferLevel(0.5),
StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
},
];
assert_eq!(metrics.len(), 7);
}
#[test]
fn test_streaming_ux_validator_clone() {
let validator = StreamingUxValidator::new()
.with_max_latency(Duration::from_millis(100))
.with_buffer_underrun_threshold(3);
let cloned = validator;
assert_eq!(cloned.state(), StreamingState::Idle);
}
#[test]
fn test_test_execution_stats_clone() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(1000, 100);
let cloned = stats.clone();
assert_eq!(cloned.states_captured, 1);
}
#[test]
fn test_vu_meter_config_clone() {
let config = VuMeterConfig::default().with_min_level(0.2);
let cloned = config;
assert!((cloned.min_level - 0.2).abs() < f32::EPSILON);
}
#[test]
fn test_state_transition_clone() {
let transition = StateTransition {
from: "Idle".to_string(),
to: "Recording".to_string(),
timestamp_ms: 1000.0,
duration_ms: 500.0,
};
let cloned = transition;
assert_eq!(cloned.from, "Idle");
}
#[test]
fn test_vu_meter_stale_error_display() {
let err = VuMeterError::Stale {
last_update_ms: 100,
current_ms: 300,
};
let display = format!("{}", err);
assert!(display.contains("stale"));
assert!(display.contains("200ms"));
}
#[test]
fn test_vu_meter_slow_update_rate_error_display() {
let err = VuMeterError::SlowUpdateRate {
measured_hz: 15.0,
expected_hz: 30.0,
};
let display = format!("{}", err);
assert!(display.contains("15.0Hz"));
assert!(display.contains("30.0Hz"));
}
#[test]
fn test_vu_meter_not_animating_error_display() {
let err = VuMeterError::NotAnimating {
sample_count: 100,
value: 0.5,
};
let display = format!("{}", err);
assert!(display.contains("100 samples"));
assert!(display.contains("0.5"));
}
#[test]
fn test_screenshot_content_game_world() {
let mut pixels = Vec::with_capacity(1000);
for i in 0..1000 {
pixels.push((i % 64) as u8); }
let content = ScreenshotContent::classify(&pixels);
match content {
ScreenshotContent::GameWorld { entropy } => {
assert!((3.0..6.0).contains(&entropy));
}
ScreenshotContent::HighEntropy { entropy } => {
assert!(entropy >= 6.0);
}
_ => {}
}
}
#[test]
fn test_streaming_validation_error_invalid_transition() {
let err = StreamingValidationError::InvalidStateTransition {
from: StreamingState::Idle,
to: StreamingState::Streaming,
};
let display = format!("{}", err);
assert!(display.contains("Invalid state transition"));
assert!(display.contains("Idle"));
assert!(display.contains("Streaming"));
}
#[test]
fn test_streaming_latency_transition() {
let mut validator = StreamingUxValidator::new();
validator.start();
assert_eq!(validator.state(), StreamingState::Buffering);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(10)));
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_streaming_buffer_level() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::BufferLevel(0.75));
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_streaming_frame_times_overflow() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
for i in 0..150 {
validator.record_metric(StreamingMetric::FrameRendered { timestamp: i * 33 });
}
let fps = validator.average_fps();
assert!(fps > 0.0);
}
#[test]
fn test_streaming_metrics_all_variants_coverage() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 0 });
validator.record_metric(StreamingMetric::FrameDropped);
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::FirstByteReceived);
validator.record_metric(StreamingMetric::BufferLevel(0.5));
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert!(validator.dropped_frames() >= 1);
assert!(validator.buffer_underruns() >= 1);
}
#[test]
fn test_max_recorded_latency() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(100)));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(75)));
let result = validator.validate();
assert!(result.is_ok());
}
#[test]
fn test_validate_all_with_fps_error() {
let mut validator = StreamingUxValidator::new()
.with_min_fps(60.0)
.with_max_dropped_frames(0);
for i in 0..10 {
validator.record_metric(StreamingMetric::FrameRendered {
timestamp: i * 100, });
}
validator.record_metric(StreamingMetric::FrameDropped);
let errors = validator.validate_all();
assert!(!errors.is_empty());
}
#[test]
fn test_screenshot_content_entropy_boundaries() {
let mut pixels = Vec::with_capacity(1000);
for i in 0..1000 {
pixels.push((i % 4) as u8); }
let content = ScreenshotContent::classify(&pixels);
match content {
ScreenshotContent::UiDominated { entropy } => {
assert!(entropy < 3.0);
}
_ => {} }
}
#[test]
fn test_test_execution_stats_default() {
let stats: TestExecutionStats = Default::default();
assert_eq!(stats.states_captured, 0);
}
#[test]
fn test_streaming_validation_result_success() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::FirstByteReceived);
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
for i in 0..60 {
validator.record_metric(StreamingMetric::FrameRendered { timestamp: i * 33 });
}
validator.complete();
let result = validator.validate();
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.max_latency_recorded >= Duration::ZERO);
assert!(result.average_fps >= 0.0);
}
}
#[test]
fn test_partial_result_clone() {
let result = PartialResult {
timestamp_ms: 100.0,
text: "test".to_string(),
is_final: false,
};
let cloned = result;
assert_eq!(cloned.text, "test");
}
#[test]
fn test_vu_meter_sample_clone() {
let sample = VuMeterSample {
timestamp_ms: 100.0,
level: 0.5,
};
let cloned = sample;
assert!((cloned.level - 0.5).abs() < f32::EPSILON);
}
#[test]
fn test_streaming_metric_record_clone() {
let record = StreamingMetricRecord {
metric: StreamingMetric::BufferLevel(0.5),
timestamp: Instant::now(),
};
let cloned = record;
assert!(matches!(cloned.metric, StreamingMetric::BufferLevel(..)));
}
#[test]
fn test_streaming_validation_error_clone() {
let err = StreamingValidationError::LatencyExceeded {
measured: Duration::from_millis(150),
max: Duration::from_millis(100),
};
let cloned = err;
assert!(matches!(
cloned,
StreamingValidationError::LatencyExceeded { .. }
));
}
#[test]
fn test_vu_meter_error_clone() {
let err = VuMeterError::Clipping(1.5);
let cloned = err;
assert!(matches!(cloned, VuMeterError::Clipping(..)));
}
#[test]
fn test_average_fps_with_zero_duration() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 100 });
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 100 });
assert!((validator.average_fps() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_average_fps_single_frame() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 100 });
assert!((validator.average_fps() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_streaming_validation_result_fields() {
let mut validator = StreamingUxValidator::new()
.with_max_latency(Duration::from_secs(10))
.with_buffer_underrun_threshold(100)
.with_max_dropped_frames(100)
.with_min_fps(1.0);
validator.start();
validator.record_metric(StreamingMetric::FirstByteReceived);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
for i in 0..60 {
validator.record_metric(StreamingMetric::FrameRendered { timestamp: i * 16 });
}
let result = validator.validate().unwrap();
assert_eq!(result.buffer_underruns, 0);
assert_eq!(result.dropped_frames, 0);
assert!(result.average_fps > 0.0);
assert!(result.total_frames > 0);
assert!(result.max_latency_recorded >= Duration::ZERO);
}
#[test]
fn test_max_recorded_latency_empty() {
let validator = StreamingUxValidator::new();
let result = validator.validate();
assert!(result.is_ok());
}
#[test]
fn test_compression_ratio_with_zero_raw() {
let mut stats = TestExecutionStats::new();
stats.bytes_raw = 0;
stats.bytes_compressed = 100;
assert!((stats.compression_ratio() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_throughput_with_zero_duration() {
let mut stats = TestExecutionStats::new();
stats.start();
stats.record_state_capture(1000, 100);
stats.stop();
let throughput = stats.compress_throughput();
assert!(throughput >= 0.0);
}
#[test]
fn test_vu_meter_error_stale_clone() {
let err = VuMeterError::Stale {
last_update_ms: 100,
current_ms: 200,
};
let cloned = err;
assert!(matches!(
cloned,
VuMeterError::Stale {
last_update_ms: 100,
current_ms: 200,
}
));
}
#[test]
fn test_vu_meter_error_slow_update_rate_clone() {
let err = VuMeterError::SlowUpdateRate {
measured_hz: 15.0,
expected_hz: 30.0,
};
let cloned = err;
match cloned {
VuMeterError::SlowUpdateRate {
measured_hz,
expected_hz,
} => {
assert!((measured_hz - 15.0).abs() < f32::EPSILON);
assert!((expected_hz - 30.0).abs() < f32::EPSILON);
}
_ => panic!("Expected SlowUpdateRate"),
}
}
#[test]
fn test_vu_meter_error_not_animating_clone() {
let err = VuMeterError::NotAnimating {
sample_count: 10,
value: 0.5,
};
let cloned = err;
match cloned {
VuMeterError::NotAnimating {
sample_count,
value,
} => {
assert_eq!(sample_count, 10);
assert!((value - 0.5).abs() < f32::EPSILON);
}
_ => panic!("Expected NotAnimating"),
}
}
#[test]
fn test_streaming_validation_error_all_clone_variants() {
let errors: Vec<StreamingValidationError> = vec![
StreamingValidationError::LatencyExceeded {
measured: Duration::from_millis(200),
max: Duration::from_millis(100),
},
StreamingValidationError::BufferUnderrunThreshold {
count: 10,
threshold: 5,
},
StreamingValidationError::DroppedFrameThreshold { count: 20, max: 10 },
StreamingValidationError::FpsBelowMinimum {
measured: 15.0,
min: 30.0,
},
StreamingValidationError::TtfbExceeded {
measured: Duration::from_secs(5),
max: Duration::from_secs(2),
},
StreamingValidationError::InvalidStateTransition {
from: StreamingState::Idle,
to: StreamingState::Completed,
},
StreamingValidationError::EndedInError,
];
for err in errors {
let cloned = err.clone();
let _ = cloned.to_string();
}
}
#[test]
fn test_streaming_metric_clone_all_variants() {
let metrics = vec![
StreamingMetric::Latency(Duration::from_millis(100)),
StreamingMetric::FrameRendered { timestamp: 1000 },
StreamingMetric::FrameDropped,
StreamingMetric::BufferUnderrun,
StreamingMetric::FirstByteReceived,
StreamingMetric::BufferLevel(0.75),
StreamingMetric::AudioChunk {
samples: 2048,
sample_rate: 44100,
},
];
for metric in metrics {
let cloned = metric.clone();
let _ = format!("{:?}", cloned);
}
}
#[test]
fn test_buffer_level_no_transition_when_not_streaming() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::BufferLevel(0.05));
assert_eq!(validator.state(), StreamingState::Idle);
validator.record_metric(StreamingMetric::BufferLevel(0.5));
assert_eq!(validator.state(), StreamingState::Idle);
}
#[test]
fn test_latency_no_transition_when_exceeds_max() {
let mut validator = StreamingUxValidator::new().with_max_latency(Duration::from_millis(50));
validator.start();
assert_eq!(validator.state(), StreamingState::Buffering);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(100)));
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_frame_rendered_no_transition_when_not_stalled() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 100 });
assert_eq!(validator.state(), StreamingState::Idle);
validator.start();
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 200 });
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_audio_chunk_no_transition_when_not_buffering() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Idle);
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_first_byte_no_transition_when_not_idle() {
let mut validator = StreamingUxValidator::new();
validator.start(); validator.record_metric(StreamingMetric::FirstByteReceived);
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_buffer_underrun_no_transition_when_not_streaming() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::BufferUnderrun);
assert_eq!(validator.state(), StreamingState::Idle);
assert_eq!(validator.buffer_underruns(), 1);
validator.start();
validator.record_metric(StreamingMetric::BufferUnderrun);
assert_eq!(validator.state(), StreamingState::Buffering);
assert_eq!(validator.buffer_underruns(), 2);
}
#[test]
fn test_transition_to_same_state() {
let mut validator = StreamingUxValidator::new();
validator.start();
let history_len = validator.state_history().len();
validator.record_metric(StreamingMetric::BufferLevel(0.5)); assert_eq!(validator.state_history().len(), history_len);
}
#[test]
fn test_screenshot_content_single_byte() {
let content = ScreenshotContent::classify(&[128]);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 128 }
));
}
#[test]
fn test_screenshot_content_two_bytes_same() {
let content = ScreenshotContent::classify(&[42, 42]);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 42 }
));
}
#[test]
fn test_screenshot_content_near_uniform_threshold() {
let mut pixels = vec![255u8; 94];
pixels.extend(vec![0u8; 6]);
let content = ScreenshotContent::classify(&pixels);
assert!(!matches!(content, ScreenshotContent::Uniform { .. }));
}
#[test]
fn test_screenshot_content_exactly_at_uniform_threshold() {
let mut pixels = vec![255u8; 96];
pixels.extend(vec![0u8; 4]);
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 255 }
));
}
#[test]
fn test_screenshot_content_entropy_at_boundary_3() {
let mut pixels = Vec::new();
for _ in 0..125 {
for v in 0u8..8u8 {
pixels.push(v);
}
}
let content = ScreenshotContent::classify(&pixels);
let entropy = content.entropy();
assert!((2.5..=3.5).contains(&entropy));
}
#[test]
fn test_screenshot_content_entropy_at_boundary_6() {
let mut pixels = Vec::new();
for _ in 0..16 {
for v in 0u8..64u8 {
pixels.push(v);
}
}
let content = ScreenshotContent::classify(&pixels);
let entropy = content.entropy();
assert!((5.5..=6.5).contains(&entropy));
}
#[test]
fn test_screenshot_content_maximum_entropy() {
let mut pixels = Vec::new();
for _ in 0..4 {
for v in 0u8..=255u8 {
pixels.push(v);
}
}
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(content, ScreenshotContent::HighEntropy { .. }));
assert!(content.entropy() > 7.0);
}
#[test]
fn test_validate_multiple_latency_exceeded() {
let mut validator = StreamingUxValidator::new().with_max_latency(Duration::from_millis(50));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(100)));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(150)));
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(200)));
let errors = validator.validate_all();
assert_eq!(errors.len(), 3);
for err in errors {
assert!(matches!(
err,
StreamingValidationError::LatencyExceeded { .. }
));
}
}
#[test]
fn test_streaming_validation_result_debug() {
let result = StreamingValidationResult {
buffer_underruns: 2,
dropped_frames: 5,
average_fps: 30.0,
max_latency_recorded: Duration::from_millis(100),
total_frames: 1000,
};
let debug = format!("{:?}", result);
assert!(debug.contains("StreamingValidationResult"));
assert!(debug.contains("buffer_underruns"));
}
#[test]
fn test_streaming_validation_result_clone() {
let result = StreamingValidationResult {
buffer_underruns: 3,
dropped_frames: 7,
average_fps: 60.0,
max_latency_recorded: Duration::from_millis(50),
total_frames: 2000,
};
let cloned = result;
assert_eq!(cloned.buffer_underruns, 3);
assert_eq!(cloned.dropped_frames, 7);
assert!((cloned.average_fps - 60.0).abs() < f64::EPSILON);
assert_eq!(cloned.max_latency_recorded, Duration::from_millis(50));
assert_eq!(cloned.total_frames, 2000);
}
#[test]
fn test_vu_meter_config_smoothing_tolerance() {
let config = VuMeterConfig {
min_level: 0.0,
max_level: 1.0,
update_rate_hz: 30.0,
smoothing_tolerance: 0.2,
max_stale_ms: 100,
};
assert!(config.validate_sample(1.19).is_ok());
assert!(config.validate_sample(1.21).is_err());
}
#[test]
fn test_compression_algorithm_debug() {
let algos = [
CompressionAlgorithm::Lz4,
CompressionAlgorithm::Zstd,
CompressionAlgorithm::Png,
CompressionAlgorithm::Rle,
];
for algo in algos {
let debug = format!("{:?}", algo);
assert!(!debug.is_empty());
}
}
#[test]
fn test_compression_algorithm_copy() {
let algo = CompressionAlgorithm::Lz4;
let copied = algo;
assert_eq!(algo, copied);
}
#[test]
fn test_test_execution_stats_large_values() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(u64::MAX / 2, u64::MAX / 4);
let ratio = stats.compression_ratio();
assert!(ratio > 0.0);
let efficiency = stats.efficiency();
assert!(efficiency > 0.0 && efficiency < 1.0);
}
#[test]
fn test_storage_savings_small_values() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(500_000, 400_000);
let savings = stats.storage_savings_mb();
assert!((savings - 0.1).abs() < 0.01);
}
#[test]
fn test_storage_savings_compressed_larger_than_raw() {
let mut stats = TestExecutionStats::new();
stats.bytes_raw = 100;
stats.bytes_compressed = 200;
let savings = stats.storage_savings_mb();
assert!((savings - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_same_fill_exactly_at_threshold() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(1000, 100);
assert_eq!(stats.same_fill_pages, 0);
stats.record_state_capture(1000, 99);
assert_eq!(stats.same_fill_pages, 1);
}
#[test]
fn test_streaming_ux_validator_debug() {
let validator = StreamingUxValidator::new();
let debug = format!("{:?}", validator);
assert!(debug.contains("StreamingUxValidator"));
}
#[test]
fn test_streaming_metric_record_debug() {
let record = StreamingMetricRecord {
metric: StreamingMetric::FrameDropped,
timestamp: Instant::now(),
};
let debug = format!("{:?}", record);
assert!(debug.contains("StreamingMetricRecord"));
}
#[test]
fn test_validate_all_empty_metrics() {
let validator = StreamingUxValidator::new();
let errors = validator.validate_all();
assert!(errors.is_empty());
}
#[test]
fn test_validate_with_error_state() {
let mut validator = StreamingUxValidator::new();
validator.error();
let result = validator.validate();
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
StreamingValidationError::EndedInError
));
}
#[test]
fn test_validate_all_multiple_error_types() {
let mut validator = StreamingUxValidator::new()
.with_max_latency(Duration::from_millis(10))
.with_buffer_underrun_threshold(0)
.with_max_dropped_frames(0)
.with_min_fps(100.0);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::FrameDropped);
for i in 0..5 {
validator.record_metric(StreamingMetric::FrameRendered {
timestamp: i * 500, });
}
validator.error();
let errors = validator.validate_all();
assert!(errors.len() >= 4);
}
#[test]
fn test_vu_meter_error_negative_level_value() {
let config = VuMeterConfig::default();
let result = config.validate_sample(-10.5);
match result {
Err(VuMeterError::NegativeLevel(v)) => {
assert!((v - (-10.5)).abs() < f32::EPSILON);
}
_ => panic!("Expected NegativeLevel error"),
}
}
#[test]
fn test_vu_meter_error_clipping_value() {
let config = VuMeterConfig::default().with_max_level(0.5);
let result = config.validate_sample(2.0);
match result {
Err(VuMeterError::Clipping(v)) => {
assert!((v - 2.0).abs() < f32::EPSILON);
}
_ => panic!("Expected Clipping error"),
}
}
#[test]
fn test_streaming_state_hash() {
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(StreamingState::Idle);
set.insert(StreamingState::Buffering);
set.insert(StreamingState::Streaming);
set.insert(StreamingState::Stalled);
set.insert(StreamingState::Error);
set.insert(StreamingState::Completed);
assert_eq!(set.len(), 6);
assert!(set.contains(&StreamingState::Idle));
}
#[test]
fn test_screenshot_content_clone() {
let contents = vec![
ScreenshotContent::Uniform { fill_value: 128 },
ScreenshotContent::UiDominated { entropy: 2.5 },
ScreenshotContent::GameWorld { entropy: 4.5 },
ScreenshotContent::HighEntropy { entropy: 7.0 },
];
for content in contents {
let cloned = content.clone();
assert!((cloned.entropy() - content.entropy()).abs() < f32::EPSILON);
}
}
#[test]
fn test_test_execution_stats_all_fields() {
let mut stats = TestExecutionStats::new();
stats.start();
stats.record_state_capture(1000, 100);
stats.record_state_capture(2000, 50); stats.stop();
assert_eq!(stats.states_captured, 2);
assert_eq!(stats.bytes_raw, 3000);
assert_eq!(stats.bytes_compressed, 150);
assert_eq!(stats.same_fill_pages, 1);
}
#[test]
fn test_frame_times_exactly_120() {
let mut validator = StreamingUxValidator::new();
for i in 0..120 {
validator.record_metric(StreamingMetric::FrameRendered { timestamp: i * 16 });
}
assert!(validator.average_fps() > 0.0);
}
#[test]
fn test_frame_times_121() {
let mut validator = StreamingUxValidator::new();
for i in 0..121 {
validator.record_metric(StreamingMetric::FrameRendered { timestamp: i * 16 });
}
assert!(validator.average_fps() > 0.0);
}
#[test]
fn test_state_transition_fields_access() {
let transition = StateTransition {
from: "State1".to_string(),
to: "State2".to_string(),
timestamp_ms: 12345.67,
duration_ms: 890.12,
};
assert_eq!(transition.from.as_str(), "State1");
assert_eq!(transition.to.as_str(), "State2");
assert!((transition.timestamp_ms - 12345.67).abs() < f64::EPSILON);
assert!((transition.duration_ms - 890.12).abs() < f64::EPSILON);
}
#[test]
fn test_partial_result_fields_access() {
let partial = PartialResult {
timestamp_ms: 999.99,
text: "Hello World".to_string(),
is_final: true,
};
assert!((partial.timestamp_ms - 999.99).abs() < f64::EPSILON);
assert_eq!(partial.text.as_str(), "Hello World");
assert!(partial.is_final);
}
#[test]
fn test_vu_meter_sample_fields_access() {
let sample = VuMeterSample {
timestamp_ms: 1234.5,
level: 0.789,
};
assert!((sample.timestamp_ms - 1234.5).abs() < f64::EPSILON);
assert!((sample.level - 0.789).abs() < f32::EPSILON);
}
#[test]
fn test_streaming_metric_record_fields_access() {
let timestamp = Instant::now();
let record = StreamingMetricRecord {
metric: StreamingMetric::BufferLevel(0.42),
timestamp,
};
assert!(matches!(record.metric, StreamingMetric::BufferLevel(..)));
assert_eq!(record.timestamp, timestamp);
}
#[test]
fn test_validate_returns_first_error() {
let mut validator = StreamingUxValidator::new()
.with_max_latency(Duration::from_millis(10))
.with_buffer_underrun_threshold(0);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
validator.record_metric(StreamingMetric::BufferUnderrun);
let result = validator.validate();
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
StreamingValidationError::LatencyExceeded { .. }
));
}
#[test]
fn test_validate_fps_error_only_when_positive() {
let mut validator = StreamingUxValidator::new().with_min_fps(100.0);
let result = validator.validate();
assert!(result.is_ok());
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 0 });
let result = validator.validate();
assert!(result.is_ok());
}
#[test]
fn test_buffer_level_recovery_threshold() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::BufferLevel(0.05));
assert_eq!(validator.state(), StreamingState::Stalled);
validator.record_metric(StreamingMetric::BufferLevel(0.3));
assert_eq!(validator.state(), StreamingState::Stalled);
validator.record_metric(StreamingMetric::BufferLevel(0.31));
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_buffer_level_stall_threshold() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::BufferLevel(0.1));
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::BufferLevel(0.09));
assert_eq!(validator.state(), StreamingState::Stalled);
}
#[test]
fn test_vu_meter_config_default_values() {
let config = VuMeterConfig::default();
assert!((config.min_level - 0.0).abs() < f32::EPSILON);
assert!((config.max_level - 1.0).abs() < f32::EPSILON);
assert!((config.update_rate_hz - 30.0).abs() < f32::EPSILON);
assert!((config.smoothing_tolerance - 0.1).abs() < f32::EPSILON);
assert_eq!(config.max_stale_ms, 100);
}
#[test]
fn test_vu_meter_error_display_all_variants() {
let err = VuMeterError::NegativeLevel(-0.25);
let display = format!("{}", err);
assert!(display.contains("-0.25"));
assert!(display.contains("negative"));
let err = VuMeterError::Clipping(1.75);
let display = format!("{}", err);
assert!(display.contains("1.75"));
assert!(display.contains("clipping"));
let err = VuMeterError::Stale {
last_update_ms: 50,
current_ms: 250,
};
let display = format!("{}", err);
assert!(display.contains("200ms"));
let err = VuMeterError::SlowUpdateRate {
measured_hz: 20.0,
expected_hz: 60.0,
};
let display = format!("{}", err);
assert!(display.contains("20.0Hz"));
assert!(display.contains("60.0Hz"));
let err = VuMeterError::NotAnimating {
sample_count: 50,
value: 0.75,
};
let display = format!("{}", err);
assert!(display.contains("50 samples"));
assert!(display.contains("0.75"));
}
#[test]
fn test_streaming_validation_error_display_all_variants() {
let err = StreamingValidationError::LatencyExceeded {
measured: Duration::from_millis(300),
max: Duration::from_millis(100),
};
assert!(err.to_string().contains("300"));
let err = StreamingValidationError::BufferUnderrunThreshold {
count: 15,
threshold: 5,
};
assert!(err.to_string().contains("15"));
assert!(err.to_string().contains('5'));
let err = StreamingValidationError::DroppedFrameThreshold { count: 25, max: 10 };
assert!(err.to_string().contains("25"));
assert!(err.to_string().contains("10"));
let err = StreamingValidationError::FpsBelowMinimum {
measured: 20.5,
min: 60.0,
};
assert!(err.to_string().contains("20.5"));
assert!(err.to_string().contains("60.0"));
let err = StreamingValidationError::TtfbExceeded {
measured: Duration::from_secs(10),
max: Duration::from_secs(3),
};
let display = err.to_string();
assert!(display.contains("first byte"));
let err = StreamingValidationError::InvalidStateTransition {
from: StreamingState::Buffering,
to: StreamingState::Completed,
};
let display = err.to_string();
assert!(display.contains("Buffering"));
assert!(display.contains("Completed"));
let err = StreamingValidationError::EndedInError;
assert!(err.to_string().contains("error state"));
}
#[test]
fn test_streaming_state_display_coverage() {
assert_eq!(format!("{}", StreamingState::Idle), "Idle");
assert_eq!(format!("{}", StreamingState::Buffering), "Buffering");
assert_eq!(format!("{}", StreamingState::Streaming), "Streaming");
assert_eq!(format!("{}", StreamingState::Stalled), "Stalled");
assert_eq!(format!("{}", StreamingState::Error), "Error");
assert_eq!(format!("{}", StreamingState::Completed), "Completed");
}
#[test]
fn test_test_execution_stats_zero_raw_bytes() {
let stats = TestExecutionStats::new();
assert!((stats.efficiency() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_test_execution_stats_zero_compressed_bytes() {
let mut stats = TestExecutionStats::new();
stats.bytes_raw = 1000;
stats.bytes_compressed = 0;
assert!((stats.compression_ratio() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_test_execution_stats_zero_states_captured() {
let stats = TestExecutionStats::new();
assert!((stats.same_fill_ratio() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_test_execution_stats_throughput_no_start() {
let mut stats = TestExecutionStats::new();
stats.stop();
stats.record_state_capture(1000, 100);
assert!((stats.compress_throughput() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_test_execution_stats_throughput_only_end() {
let mut stats = TestExecutionStats::new();
stats.stop();
assert!((stats.compress_throughput() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_test_execution_stats_same_fill_with_zero_raw() {
let mut stats = TestExecutionStats::new();
stats.record_state_capture(0, 0);
assert_eq!(stats.same_fill_pages, 0);
}
#[test]
fn test_screenshot_content_classify_single_pixel() {
let content = ScreenshotContent::classify(&[42]);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 42 }
));
}
#[test]
fn test_screenshot_content_all_different_values() {
let pixels: Vec<u8> = (0..=255).collect();
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(content, ScreenshotContent::HighEntropy { .. }));
assert!(content.entropy() > 7.5);
}
#[test]
fn test_screenshot_content_entropy_method_uniform() {
let content = ScreenshotContent::Uniform { fill_value: 200 };
assert!((content.entropy() - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_screenshot_content_recommended_algorithm_all() {
assert_eq!(
ScreenshotContent::Uniform { fill_value: 0 }.recommended_algorithm(),
CompressionAlgorithm::Rle
);
assert_eq!(
ScreenshotContent::UiDominated { entropy: 2.0 }.recommended_algorithm(),
CompressionAlgorithm::Png
);
assert_eq!(
ScreenshotContent::GameWorld { entropy: 4.5 }.recommended_algorithm(),
CompressionAlgorithm::Zstd
);
assert_eq!(
ScreenshotContent::HighEntropy { entropy: 7.0 }.recommended_algorithm(),
CompressionAlgorithm::Lz4
);
}
#[test]
fn test_screenshot_content_expected_ratio_hint_all() {
assert!(ScreenshotContent::Uniform { fill_value: 0 }
.expected_ratio_hint()
.contains("excellent"));
assert!(ScreenshotContent::UiDominated { entropy: 2.0 }
.expected_ratio_hint()
.contains("good"));
assert!(ScreenshotContent::GameWorld { entropy: 4.5 }
.expected_ratio_hint()
.contains("moderate"));
assert!(ScreenshotContent::HighEntropy { entropy: 7.0 }
.expected_ratio_hint()
.contains("poor"));
}
#[test]
fn test_streaming_ux_validator_builder_chain() {
let validator = StreamingUxValidator::new()
.with_max_latency(Duration::from_millis(150))
.with_buffer_underrun_threshold(10)
.with_max_dropped_frames(20)
.with_min_fps(45.0)
.with_ttfb_timeout(Duration::from_secs(5));
assert_eq!(validator.max_latency, Duration::from_millis(150));
assert_eq!(validator.buffer_underrun_threshold, 10);
assert_eq!(validator.max_dropped_frames, 20);
assert!((validator.min_fps - 45.0).abs() < f64::EPSILON);
assert_eq!(validator.ttfb_timeout, Duration::from_secs(5));
}
#[test]
fn test_streaming_validator_for_audio_preset() {
let validator = StreamingUxValidator::for_audio();
assert_eq!(validator.max_latency, Duration::from_millis(100));
assert_eq!(validator.buffer_underrun_threshold, 3);
assert_eq!(validator.ttfb_timeout, Duration::from_secs(2));
}
#[test]
fn test_streaming_validator_for_video_preset() {
let validator = StreamingUxValidator::for_video();
assert_eq!(validator.max_latency, Duration::from_millis(500));
assert!((validator.min_fps - 30.0).abs() < f64::EPSILON);
assert_eq!(validator.max_dropped_frames, 5);
}
#[test]
fn test_streaming_validator_average_fps_no_frames() {
let validator = StreamingUxValidator::new();
assert!((validator.average_fps() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_streaming_validator_average_fps_one_frame() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 1000 });
assert!((validator.average_fps() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_streaming_validator_average_fps_same_timestamp() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 1000 });
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 1000 });
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 1000 });
assert!((validator.average_fps() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_streaming_validator_max_recorded_latency_none() {
let validator = StreamingUxValidator::new();
let result = validator.validate();
assert!(result.is_ok());
let res = result.unwrap();
assert_eq!(res.max_latency_recorded, Duration::ZERO);
}
#[test]
fn test_streaming_validator_validate_no_ttfb() {
let mut validator = StreamingUxValidator::new();
validator.start();
let result = validator.validate();
assert!(result.is_ok());
}
#[test]
fn test_streaming_validator_complete_and_validate() {
let mut validator = StreamingUxValidator::new();
validator.complete();
assert_eq!(validator.state(), StreamingState::Completed);
let result = validator.validate();
assert!(result.is_ok());
}
#[test]
fn test_streaming_validator_error_and_validate() {
let mut validator = StreamingUxValidator::new();
validator.error();
assert_eq!(validator.state(), StreamingState::Error);
let result = validator.validate();
assert!(result.is_err());
}
#[test]
fn test_streaming_validator_state_history_empty() {
let validator = StreamingUxValidator::new();
assert!(validator.state_history().is_empty());
}
#[test]
fn test_streaming_validator_state_history_with_transitions() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
validator.complete();
let history = validator.state_history();
assert!(history.len() >= 2);
}
#[test]
fn test_streaming_validator_reset_full() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::FrameDropped);
validator.record_metric(StreamingMetric::FirstByteReceived);
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 100 });
validator.reset();
assert_eq!(validator.state(), StreamingState::Idle);
assert_eq!(validator.buffer_underruns(), 0);
assert_eq!(validator.dropped_frames(), 0);
assert!(validator.state_history().is_empty());
}
#[test]
fn test_streaming_validator_validate_all_with_error_state() {
let mut validator = StreamingUxValidator::new();
validator.error();
let errors = validator.validate_all();
assert!(errors
.iter()
.any(|e| matches!(e, StreamingValidationError::EndedInError)));
}
#[test]
fn test_streaming_validation_result_fields_all() {
let result = StreamingValidationResult {
buffer_underruns: 1,
dropped_frames: 2,
average_fps: 30.0,
max_latency_recorded: Duration::from_millis(50),
total_frames: 100,
};
assert_eq!(result.buffer_underruns, 1);
assert_eq!(result.dropped_frames, 2);
assert!((result.average_fps - 30.0).abs() < f64::EPSILON);
assert_eq!(result.max_latency_recorded, Duration::from_millis(50));
assert_eq!(result.total_frames, 100);
}
#[test]
fn test_state_transition_struct_fields_all() {
let transition = StateTransition {
from: "StateA".to_string(),
to: "StateB".to_string(),
timestamp_ms: 100.0,
duration_ms: 50.0,
};
assert_eq!(&transition.from, "StateA");
assert_eq!(&transition.to, "StateB");
assert!((transition.timestamp_ms - 100.0).abs() < f64::EPSILON);
assert!((transition.duration_ms - 50.0).abs() < f64::EPSILON);
}
#[test]
fn test_partial_result_struct_fields() {
let partial = PartialResult {
timestamp_ms: 200.0,
text: "partial text".to_string(),
is_final: false,
};
assert!((partial.timestamp_ms - 200.0).abs() < f64::EPSILON);
assert_eq!(&partial.text, "partial text");
assert!(!partial.is_final);
let final_result = PartialResult {
timestamp_ms: 300.0,
text: "final text".to_string(),
is_final: true,
};
assert!(final_result.is_final);
}
#[test]
fn test_vu_meter_sample_struct_fields() {
let sample = VuMeterSample {
timestamp_ms: 150.0,
level: 0.65,
};
assert!((sample.timestamp_ms - 150.0).abs() < f64::EPSILON);
assert!((sample.level - 0.65).abs() < f32::EPSILON);
}
#[test]
fn test_streaming_metric_record_struct() {
let now = Instant::now();
let record = StreamingMetricRecord {
metric: StreamingMetric::FrameDropped,
timestamp: now,
};
assert!(matches!(record.metric, StreamingMetric::FrameDropped));
assert_eq!(record.timestamp, now);
}
#[test]
fn test_streaming_metric_latency_variant() {
let metric = StreamingMetric::Latency(Duration::from_millis(123));
if let StreamingMetric::Latency(d) = metric {
assert_eq!(d, Duration::from_millis(123));
} else {
panic!("Expected Latency variant");
}
}
#[test]
fn test_streaming_metric_frame_rendered_variant() {
let metric = StreamingMetric::FrameRendered { timestamp: 999 };
if let StreamingMetric::FrameRendered { timestamp } = metric {
assert_eq!(timestamp, 999);
} else {
panic!("Expected FrameRendered variant");
}
}
#[test]
fn test_streaming_metric_buffer_level_variant() {
let metric = StreamingMetric::BufferLevel(0.42);
if let StreamingMetric::BufferLevel(level) = metric {
assert!((level - 0.42).abs() < f32::EPSILON);
} else {
panic!("Expected BufferLevel variant");
}
}
#[test]
fn test_streaming_metric_audio_chunk_variant() {
let metric = StreamingMetric::AudioChunk {
samples: 2048,
sample_rate: 44100,
};
if let StreamingMetric::AudioChunk {
samples,
sample_rate,
} = metric
{
assert_eq!(samples, 2048);
assert_eq!(sample_rate, 44100);
} else {
panic!("Expected AudioChunk variant");
}
}
#[test]
fn test_compression_algorithm_eq() {
assert_eq!(CompressionAlgorithm::Lz4, CompressionAlgorithm::Lz4);
assert_eq!(CompressionAlgorithm::Zstd, CompressionAlgorithm::Zstd);
assert_eq!(CompressionAlgorithm::Png, CompressionAlgorithm::Png);
assert_eq!(CompressionAlgorithm::Rle, CompressionAlgorithm::Rle);
}
#[test]
fn test_streaming_state_eq() {
assert_eq!(StreamingState::Idle, StreamingState::Idle);
assert_eq!(StreamingState::Buffering, StreamingState::Buffering);
assert_eq!(StreamingState::Streaming, StreamingState::Streaming);
assert_eq!(StreamingState::Stalled, StreamingState::Stalled);
assert_eq!(StreamingState::Error, StreamingState::Error);
assert_eq!(StreamingState::Completed, StreamingState::Completed);
}
#[test]
fn test_streaming_state_ne() {
assert_ne!(StreamingState::Idle, StreamingState::Buffering);
assert_ne!(StreamingState::Streaming, StreamingState::Stalled);
assert_ne!(StreamingState::Error, StreamingState::Completed);
}
#[test]
fn test_vu_meter_error_debug() {
let errors = vec![
VuMeterError::NegativeLevel(-1.0),
VuMeterError::Clipping(2.0),
VuMeterError::Stale {
last_update_ms: 100,
current_ms: 200,
},
VuMeterError::SlowUpdateRate {
measured_hz: 10.0,
expected_hz: 30.0,
},
VuMeterError::NotAnimating {
sample_count: 5,
value: 0.5,
},
];
for err in errors {
let debug = format!("{:?}", err);
assert!(!debug.is_empty());
}
}
#[test]
fn test_streaming_validation_error_debug() {
let errors: Vec<StreamingValidationError> = vec![
StreamingValidationError::LatencyExceeded {
measured: Duration::from_millis(100),
max: Duration::from_millis(50),
},
StreamingValidationError::BufferUnderrunThreshold {
count: 5,
threshold: 3,
},
StreamingValidationError::DroppedFrameThreshold { count: 10, max: 5 },
StreamingValidationError::FpsBelowMinimum {
measured: 15.0,
min: 30.0,
},
StreamingValidationError::TtfbExceeded {
measured: Duration::from_secs(5),
max: Duration::from_secs(2),
},
StreamingValidationError::InvalidStateTransition {
from: StreamingState::Idle,
to: StreamingState::Error,
},
StreamingValidationError::EndedInError,
];
for err in errors {
let debug = format!("{:?}", err);
assert!(!debug.is_empty());
}
}
#[test]
fn test_screenshot_content_classify_boundary_uniform() {
let mut pixels = vec![100u8; 96];
pixels.extend(vec![200u8; 4]);
let content = ScreenshotContent::classify(&pixels);
assert!(matches!(
content,
ScreenshotContent::Uniform { fill_value: 100 }
));
}
#[test]
fn test_screenshot_content_classify_just_under_uniform() {
let mut pixels = vec![100u8; 94];
pixels.extend(vec![200u8; 6]);
let content = ScreenshotContent::classify(&pixels);
assert!(!matches!(content, ScreenshotContent::Uniform { .. }));
}
#[test]
fn test_test_execution_stats_reset_clears_timing() {
let mut stats = TestExecutionStats::new();
stats.start();
stats.record_state_capture(1000, 100);
stats.stop();
assert!(stats.compress_throughput() > 0.0 || stats.bytes_raw > 0);
stats.reset();
assert!((stats.compress_throughput() - 0.0).abs() < f64::EPSILON);
assert_eq!(stats.states_captured, 0);
assert_eq!(stats.bytes_raw, 0);
assert_eq!(stats.bytes_compressed, 0);
assert_eq!(stats.same_fill_pages, 0);
}
#[test]
fn test_frame_times_cap_at_120() {
let mut validator = StreamingUxValidator::new();
for i in 0..200 {
validator.record_metric(StreamingMetric::FrameRendered { timestamp: i * 16 });
}
let fps = validator.average_fps();
assert!(fps > 0.0);
}
#[test]
fn test_latency_metric_triggers_buffering_to_streaming() {
let mut validator =
StreamingUxValidator::new().with_max_latency(Duration::from_millis(200));
validator.start();
assert_eq!(validator.state(), StreamingState::Buffering);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(50)));
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_latency_metric_high_latency_no_transition() {
let mut validator = StreamingUxValidator::new().with_max_latency(Duration::from_millis(50));
validator.start();
assert_eq!(validator.state(), StreamingState::Buffering);
validator.record_metric(StreamingMetric::Latency(Duration::from_millis(100)));
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_buffer_level_stall_only_when_streaming() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::BufferLevel(0.01));
assert_eq!(validator.state(), StreamingState::Idle);
validator.start();
validator.record_metric(StreamingMetric::BufferLevel(0.01));
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_buffer_level_recovery_only_when_stalled() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Streaming);
validator.record_metric(StreamingMetric::BufferLevel(0.9));
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_frame_rendered_recovery_from_stalled() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
validator.record_metric(StreamingMetric::BufferLevel(0.01));
assert_eq!(validator.state(), StreamingState::Stalled);
validator.record_metric(StreamingMetric::FrameRendered { timestamp: 100 });
assert_eq!(validator.state(), StreamingState::Streaming);
}
#[test]
fn test_audio_chunk_only_transitions_from_buffering() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::AudioChunk {
samples: 1024,
sample_rate: 16000,
});
assert_eq!(validator.state(), StreamingState::Idle);
}
#[test]
fn test_first_byte_received_only_transitions_from_idle() {
let mut validator = StreamingUxValidator::new();
validator.start();
validator.record_metric(StreamingMetric::FirstByteReceived);
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_buffer_underrun_only_stalls_when_streaming() {
let mut validator = StreamingUxValidator::new();
validator.record_metric(StreamingMetric::BufferUnderrun);
assert_eq!(validator.state(), StreamingState::Idle);
validator.start();
validator.record_metric(StreamingMetric::BufferUnderrun);
assert_eq!(validator.state(), StreamingState::Buffering);
}
#[test]
fn test_validate_all_fps_error() {
let mut validator = StreamingUxValidator::new().with_min_fps(60.0);
for i in 0..10 {
validator.record_metric(StreamingMetric::FrameRendered {
timestamp: i * 100, });
}
let errors = validator.validate_all();
assert!(errors
.iter()
.any(|e| matches!(e, StreamingValidationError::FpsBelowMinimum { .. })));
}
#[test]
fn test_validate_all_buffer_underrun_error() {
let mut validator = StreamingUxValidator::new().with_buffer_underrun_threshold(1);
validator.record_metric(StreamingMetric::BufferUnderrun);
validator.record_metric(StreamingMetric::BufferUnderrun);
let errors = validator.validate_all();
assert!(errors
.iter()
.any(|e| matches!(e, StreamingValidationError::BufferUnderrunThreshold { .. })));
}
#[test]
fn test_validate_all_dropped_frames_error() {
let mut validator = StreamingUxValidator::new().with_max_dropped_frames(1);
validator.record_metric(StreamingMetric::FrameDropped);
validator.record_metric(StreamingMetric::FrameDropped);
let errors = validator.validate_all();
assert!(errors
.iter()
.any(|e| matches!(e, StreamingValidationError::DroppedFrameThreshold { .. })));
}
#[test]
fn test_streaming_state_copy_clone() {
let state = StreamingState::Streaming;
let copied = state;
let cloned = state;
assert_eq!(copied, cloned);
assert_eq!(state, StreamingState::Streaming);
}
#[test]
fn test_compression_algorithm_copy_clone() {
let algo = CompressionAlgorithm::Zstd;
let copied = algo;
let cloned = algo;
assert_eq!(copied, cloned);
assert_eq!(algo, CompressionAlgorithm::Zstd);
}