use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
#[test]
fn test_progress_throttling_every_10_files() {
let total_files = 25;
let update_count = Arc::new(AtomicUsize::new(0));
let update_count_clone = update_count.clone();
let mut last_update = Instant::now();
for idx in 0..total_files {
std::thread::sleep(Duration::from_micros(10));
if (idx + 1) % 10 == 0 || last_update.elapsed() > Duration::from_millis(100) {
update_count_clone.fetch_add(1, Ordering::Relaxed);
last_update = Instant::now();
}
}
let final_count = update_count.load(Ordering::Relaxed);
assert!(
(2..=10).contains(&final_count),
"Expected 2-10 updates with throttling, got {}",
final_count
);
assert!(
final_count < total_files,
"Throttling should reduce updates from {} to {}",
total_files,
final_count
);
}
#[test]
fn test_progress_values_are_monotonic() {
let total_files = 15;
let mut progress_values = Vec::new();
for idx in 0..total_files {
if (idx + 1) % 10 == 0 {
progress_values.push((idx + 1, total_files));
}
}
progress_values.push((total_files, total_files));
for (current, total) in &progress_values {
assert_eq!(
*total, total_files,
"Total should always be {}",
total_files
);
assert!(*current <= total_files, "Current should never exceed total");
assert!(*current > 0, "Current should be positive");
}
for i in 1..progress_values.len() {
assert!(
progress_values[i].0 >= progress_values[i - 1].0,
"Progress should be monotonically increasing"
);
}
}
#[test]
fn test_throttling_with_time_based_updates() {
let total_files = 50;
let update_count = Arc::new(AtomicUsize::new(0));
let update_count_clone = update_count.clone();
let mut last_update = Instant::now();
for idx in 0..total_files {
if idx % 5 == 0 {
std::thread::sleep(Duration::from_millis(25));
}
if (idx + 1) % 10 == 0 || last_update.elapsed() > Duration::from_millis(100) {
update_count_clone.fetch_add(1, Ordering::Relaxed);
last_update = Instant::now();
}
}
let final_count = update_count.load(Ordering::Relaxed);
assert!(
final_count >= 5,
"Expected at least 5 updates, got {}",
final_count
);
assert!(
final_count < total_files,
"Throttling should limit updates to less than total files"
);
}
#[test]
fn test_progress_callback_invocation_pattern() {
let total_files = 25;
let mut progress_calls = Vec::new();
let mut last_update = Instant::now();
for idx in 0..total_files {
if (idx + 1) % 10 == 0 || last_update.elapsed() > Duration::from_millis(100) {
progress_calls.push((idx + 1, total_files));
last_update = Instant::now();
}
}
progress_calls.push((total_files, total_files));
assert!(!progress_calls.is_empty(), "Should have progress updates");
let final_call = progress_calls.last().unwrap();
assert_eq!(final_call.0, total_files, "Final current should be total");
assert_eq!(final_call.1, total_files, "Final total should be total");
for (current, total) in &progress_calls {
assert_eq!(*total, total_files);
assert!(*current > 0 && *current <= total_files);
}
}
#[test]
fn test_throttling_prevents_excessive_updates() {
let total_files = 100;
let update_count = AtomicUsize::new(0);
let mut last_update = Instant::now();
for idx in 0..total_files {
if (idx + 1) % 10 == 0 || last_update.elapsed() > Duration::from_millis(100) {
update_count.fetch_add(1, Ordering::Relaxed);
last_update = Instant::now();
}
}
let final_count = update_count.load(Ordering::Relaxed);
assert!(
(10..=20).contains(&final_count),
"Expected 10-20 updates for 100 files, got {}",
final_count
);
let throttle_percentage = (1.0 - (final_count as f64 / total_files as f64)) * 100.0;
assert!(
throttle_percentage >= 80.0,
"Should throttle by at least 80%, got {}%",
throttle_percentage
);
}
#[test]
fn test_time_based_throttling_100ms() {
let mut update_times = Vec::new();
let mut last_update = Instant::now();
for _ in 0..5 {
std::thread::sleep(Duration::from_millis(30));
if last_update.elapsed() > Duration::from_millis(100) {
update_times.push(last_update.elapsed());
last_update = Instant::now();
}
}
assert!(
!update_times.is_empty(),
"Should have time-based updates after 150ms"
);
for elapsed in &update_times {
assert!(
*elapsed >= Duration::from_millis(100),
"Update interval should be >= 100ms, got {:?}",
elapsed
);
}
}