use regex::Regex;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Instant;
fn find_binary_path() -> Option<PathBuf> {
let possible_paths = [
PathBuf::from("./target/release/garbage-code-hunter"),
PathBuf::from("./target/debug/garbage-code-hunter"),
];
for path in &possible_paths {
if path.exists() {
return Some(path.clone());
}
}
None
}
fn run_garbage_hunter(args: &[&str]) -> Option<(String, String, i32)> {
let binary_path = find_binary_path()?;
let output = Command::new(&binary_path)
.args(args)
.output()
.expect("Failed to execute garbage-code-hunter");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
Some((stdout, stderr, exit_code))
}
macro_rules! run_test {
($args:expr) => {
match run_garbage_hunter($args) {
Some(result) => result,
None => return,
}
};
}
fn extract_total_issues(output: &str) -> u32 {
output
.lines()
.find(|line| line.contains("📝 Total") || line.contains("Total"))
.and_then(|line| line.split_whitespace().next())
.and_then(|num| num.parse().ok())
.unwrap_or_else(|| {
let re = Regex::new(r"(\d+)\s*(?:📝\s*)?Total").unwrap();
re.captures(output)
.and_then(|caps| caps.get(1).and_then(|m| m.as_str().parse().ok()))
.unwrap_or(0)
})
}
#[test]
fn test_self_bootstrap_completes_successfully() {
let (stdout, stderr, exit_code) = run_test!(&[".", "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should exit with code 0\nstderr: {}", stderr);
let total = extract_total_issues(&stdout);
assert!(
total > 0,
"Self-bootstrap should detect some issues in itself, got {}",
total
);
assert!(
total < 300,
"Self-bootstrap should have reasonable issue count (<300), got {}",
total
);
}
#[test]
fn test_self_bootstrap_performance() {
let start = Instant::now();
let (_stdout, _stderr, exit_code) = run_test!(&[".", "--lang", "en-US"]);
let duration = start.elapsed();
assert_eq!(exit_code, 0, "Should complete successfully");
assert!(
duration.as_secs() < 10,
"Self-bootstrap should complete within 10 seconds, took {:?}",
duration
);
}
#[test]
fn test_system_alert_detection_stable() {
let project_path = "../system_alert";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let (stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze system_alert successfully");
let total = extract_total_issues(&stdout);
assert!(
(100..=150).contains(&total),
"system_alert should have ~122 issues (±25%), got {}",
total
);
}
#[test]
fn test_rechat_server_detection_stable() {
let project_path = "../ReChat-server";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let (stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze ReChat-server successfully");
let total = extract_total_issues(&stdout);
assert!(
(40..=70).contains(&total),
"ReChat-server should have ~52 issues (±20%), got {}",
total
);
}
#[test]
fn test_finance_project_improved_accuracy() {
let project_path = "../Finance";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let (stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze Finance successfully");
let total = extract_total_issues(&stdout);
assert!(
(200..=350).contains(&total),
"Finance should have ~266 issues after Web context detection (±30%), got {}",
total
);
assert!(
total < 500,
"Finance should show improvement from 772 baseline, got {}",
total
);
}
#[test]
fn test_memscope_rs_best_in_class() {
let project_path = "../memscope-rs";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let (stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze memscope-rs successfully");
let total = extract_total_issues(&stdout);
assert!(
(50..=100).contains(&total),
"memscope-rs should have ~72 issues (±30%), got {}",
total
);
let files_count = 208; let avg_issues_per_file = total as f64 / files_count as f64;
assert!(
avg_issues_per_file < 1.0,
"memscope-rs should have <1.0 issues/file on average, got {:.2}",
avg_issues_per_file
);
}
#[test]
fn test_all_testable_projects_zero_crashes() {
let projects: Vec<(&str, Option<std::ops::RangeInclusive<u32>>)> = vec![
("../algo", Some(0..=0)), ("../gpu-code", Some(20..=50)), ];
for (path, expected_range) in projects {
if !Path::new(path).exists() {
eprintln!("Skipping: {} not found", path);
continue;
}
let (stdout, stderr, exit_code) = run_test!(&[path, "--lang", "en-US"]);
assert_eq!(
exit_code, 0,
"{} should complete without crash\nstderr: {}",
path, stderr
);
if let Some(range) = expected_range {
let total = extract_total_issues(&stdout);
assert!(
range.contains(&total),
"{} should have issues in range {:?}, got {}",
path,
range,
total
);
}
}
}
#[test]
fn test_small_project_performance_under_1s() {
let project_path = "../AlgoGpuRust";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let start = Instant::now();
let (_stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
let duration = start.elapsed();
assert_eq!(exit_code, 0, "Should complete successfully");
assert!(
duration.as_millis() < 1000,
"Small-medium project (21 files) should complete under 1s, took {:?}",
duration
);
}
#[test]
fn test_medium_project_performance_under_5s() {
let project_path = "../Finance";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let start = Instant::now();
let (_stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
let duration = start.elapsed();
assert_eq!(exit_code, 0, "Should complete successfully");
assert!(
duration.as_secs() < 5,
"Medium-large project (66 files) should complete under 5s, took {:?}",
duration
);
}
#[test]
fn test_markdown_output_format_valid() {
let (stdout, _stderr, exit_code) = run_test!(&[".", "--lang", "en-US", "--markdown"]);
assert_eq!(exit_code, 0, "Should generate markdown output");
assert!(
stdout.contains("# 🗑️") || stdout.contains("# Garbage"),
"Markdown output should contain header"
);
assert!(
stdout.contains("## 📈")
|| stdout.contains("Issue Statistics")
|| stdout.contains("Issues by File"),
"Markdown output should contain issues section"
);
assert!(
stdout.contains("|") || stdout.contains("- **"),
"Markdown output should contain formatted issues (table or list)"
);
}
#[test]
fn test_verbose_output_contains_rule_weights() {
let (stdout, _stderr, exit_code) =
run_test!(&["../system_alert", "--lang", "en-US", "--verbose"]);
assert_eq!(exit_code, 0, "Should generate verbose output");
assert!(
stdout.contains("⚡") || stdout.contains("rule_weight"),
"Verbose output should show performance metrics or rule weights"
);
}
#[test]
fn test_ui_context_reduces_false_positives() {
let project_path = "../system_alert";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let (stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US", "--verbose"]);
assert_eq!(exit_code, 0, "Should complete successfully");
let naming_issues: Vec<&str> = stdout
.lines()
.filter(|line| line.contains("meaningless-naming"))
.collect();
assert!(
naming_issues.len() <= 15,
"UI context should reduce meaningless-naming to ≤15, got {}",
naming_issues.len()
);
println!(
"✅ system_alert UI context test passed: {} naming issues",
naming_issues.len()
);
}
#[test]
fn test_no_regression_from_round4_to_round5() {
let regression_data: Vec<(&str, std::ops::RangeInclusive<u32>)> = vec![
("../system_alert", 100..=150), ("../ReChat-server", 40..=70), ("../AlgoGpuRust", 20..=40), ("../memscope-rs", 60..=90), ];
for (project_path, expected_range) in regression_data {
if !Path::new(project_path).exists() {
continue;
}
let (stdout, _stderr, exit_code) = run_test!(&[project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "{} should succeed", project_path);
let total = extract_total_issues(&stdout);
assert!(
expected_range.contains(&total),
"REGRESSION DETECTED!\n\
Project: {}\n\
Expected range: {:?}\n\
Actual: {}\n\
This suggests a regression from the validated Round 5 baseline.",
project_path,
expected_range,
total
);
}
}