use debtmap::risk::lcov::parse_lcov_file;
use std::io::Write;
use std::path::PathBuf;
use std::time::Instant;
use tempfile::NamedTempFile;
fn create_test_lcov_file(num_files: usize, funcs_per_file: usize) -> NamedTempFile {
let mut temp_file = NamedTempFile::new().unwrap();
for file_idx in 0..num_files {
let file_path = format!("src/module_{}/file_{}.rs", file_idx / 10, file_idx);
writeln!(temp_file, "TN:").unwrap();
writeln!(temp_file, "SF:{}", file_path).unwrap();
for func_idx in 0..funcs_per_file {
let line_start = func_idx * 15 + 10;
let func_name = format!("function_{}_{}", file_idx, func_idx);
writeln!(temp_file, "FN:{},{}", line_start, func_name).unwrap();
writeln!(temp_file, "FNDA:5,{}", func_name).unwrap();
for line_offset in 0..10 {
let line_num = line_start + line_offset;
let count = if line_offset < 7 { 5 } else { 0 };
writeln!(temp_file, "DA:{},{}", line_num, count).unwrap();
}
}
writeln!(temp_file, "LF:{}", funcs_per_file * 10).unwrap();
writeln!(temp_file, "LH:{}", funcs_per_file * 7).unwrap();
writeln!(temp_file, "end_of_record").unwrap();
}
temp_file
}
#[test]
fn test_coverage_lookup_performance_overhead() {
const NUM_FILES: usize = 100;
const FUNCS_PER_FILE: usize = 20;
const MAX_COVERAGE_TIME_MS: u128 = 200;
let temp_file = create_test_lcov_file(NUM_FILES, FUNCS_PER_FILE);
let data = parse_lcov_file(temp_file.path()).expect("Failed to parse LCOV file");
let coverage_start = Instant::now();
for file_idx in 0..NUM_FILES {
for func_idx in 0..FUNCS_PER_FILE {
let file = PathBuf::from(format!("src/module_{}/file_{}.rs", file_idx / 10, file_idx));
let func_name = format!("function_{}_{}", file_idx, func_idx);
let _coverage = data.get_function_coverage(&file, &func_name);
}
}
let coverage_duration = coverage_start.elapsed();
let coverage_ms = coverage_duration.as_millis();
println!(
"Coverage lookup duration: {:?} for {} lookups",
coverage_duration,
NUM_FILES * FUNCS_PER_FILE
);
println!(
"Average per lookup: {:.2}μs",
coverage_duration.as_micros() as f64 / (NUM_FILES * FUNCS_PER_FILE) as f64
);
assert!(
coverage_ms <= MAX_COVERAGE_TIME_MS,
"Coverage lookup took {}ms for {} lookups, exceeds maximum {}ms",
coverage_ms,
NUM_FILES * FUNCS_PER_FILE,
MAX_COVERAGE_TIME_MS
);
}
#[test]
fn test_indexed_lookup_is_fast() {
const NUM_FILES: usize = 100;
const FUNCS_PER_FILE: usize = 20;
const MAX_LOOKUP_TIME_MS: u128 = 100;
let temp_file = create_test_lcov_file(NUM_FILES, FUNCS_PER_FILE);
let data = parse_lcov_file(temp_file.path()).expect("Failed to parse LCOV file");
let start = Instant::now();
let mut lookup_count = 0;
for file_idx in 0..NUM_FILES {
for func_idx in 0..FUNCS_PER_FILE {
let file = PathBuf::from(format!("src/module_{}/file_{}.rs", file_idx / 10, file_idx));
let func_name = format!("function_{}_{}", file_idx, func_idx);
let coverage = data.get_function_coverage(&file, &func_name);
assert!(
coverage.is_some(),
"Coverage should be found for existing function"
);
lookup_count += 1;
}
}
let duration = start.elapsed();
let duration_ms = duration.as_millis();
println!(
"Performed {} lookups in {:?} ({:.2}μs per lookup)",
lookup_count,
duration,
duration.as_micros() as f64 / lookup_count as f64
);
assert!(
duration_ms <= MAX_LOOKUP_TIME_MS,
"Indexed lookup took {}ms for {} lookups, exceeds maximum {}ms",
duration_ms,
lookup_count,
MAX_LOOKUP_TIME_MS
);
}
#[test]
fn test_line_based_lookup_with_tolerance() {
const NUM_FILES: usize = 100;
const FUNCS_PER_FILE: usize = 20;
const MAX_LOOKUP_TIME_MS: u128 = 3500;
let temp_file = create_test_lcov_file(NUM_FILES, FUNCS_PER_FILE);
let data = parse_lcov_file(temp_file.path()).expect("Failed to parse LCOV file");
let start = Instant::now();
let mut lookup_count = 0;
for file_idx in 0..NUM_FILES {
for func_idx in 0..FUNCS_PER_FILE {
let file = PathBuf::from(format!("src/module_{}/file_{}.rs", file_idx / 10, file_idx));
let line = func_idx * 15 + 10;
let coverage = data.get_function_coverage_with_line(&file, "unknown_function", line);
assert!(
coverage.is_some(),
"Coverage should be found by line number"
);
lookup_count += 1;
}
}
let duration = start.elapsed();
let duration_ms = duration.as_millis();
println!(
"Performed {} line-based lookups in {:?} ({:.2}μs per lookup)",
lookup_count,
duration,
duration.as_micros() as f64 / lookup_count as f64
);
assert!(
duration_ms <= MAX_LOOKUP_TIME_MS,
"Line-based lookup took {}ms for {} lookups, exceeds maximum {}ms",
duration_ms,
lookup_count,
MAX_LOOKUP_TIME_MS
);
}
#[test]
fn test_batch_parallel_lookup_performance() {
const NUM_FILES: usize = 100;
const FUNCS_PER_FILE: usize = 20;
const MAX_BATCH_TIME_MS: u128 = 150;
let temp_file = create_test_lcov_file(NUM_FILES, FUNCS_PER_FILE);
let data = parse_lcov_file(temp_file.path()).expect("Failed to parse LCOV file");
let queries: Vec<(PathBuf, String, usize)> = (0..NUM_FILES)
.flat_map(|file_idx| {
(0..FUNCS_PER_FILE).map(move |func_idx| {
(
PathBuf::from(format!("src/module_{}/file_{}.rs", file_idx / 10, file_idx)),
format!("function_{}_{}", file_idx, func_idx),
func_idx * 15 + 10,
)
})
})
.collect();
let start = Instant::now();
let results = data.batch_get_function_coverage(&queries);
let duration = start.elapsed();
let duration_ms = duration.as_millis();
println!(
"Batch processed {} queries in {:?} ({:.2}μs per lookup)",
queries.len(),
duration,
duration.as_micros() as f64 / queries.len() as f64
);
let successful_lookups = results.iter().filter(|r| r.is_some()).count();
assert_eq!(
successful_lookups,
queries.len(),
"All batch lookups should succeed"
);
assert!(
duration_ms <= MAX_BATCH_TIME_MS,
"Batch lookup took {}ms for {} queries, exceeds maximum {}ms",
duration_ms,
queries.len(),
MAX_BATCH_TIME_MS
);
}