use regex::Regex;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Instant;
fn skip_unless_integration() -> bool {
std::env::var("GCH_INTEGRATION").is_err()
}
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 {
if let Some(caps) = Regex::new(r"Corruption Index:\s*(\d+)")
.unwrap()
.captures_iter(output)
.last()
{
if let Some(m) = caps.get(1) {
if let Ok(n) = m.as_str().parse() {
return n;
}
}
}
if let Some(caps) = Regex::new(r"Anomalies Detected:\s*(\d+)")
.unwrap()
.captures(output)
{
if let Some(m) = caps.get(1) {
if let Ok(n) = m.as_str().parse() {
return n;
}
}
}
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!(&["analyze", ".", "--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 < 100000,
"Self-bootstrap should have reasonable issue count (<100000), got {}",
total
);
}
#[test]
fn test_self_bootstrap_performance() {
let start = Instant::now();
let (_stdout, _stderr, exit_code) = run_test!(&["analyze", ".", "--lang", "en-US"]);
let duration = start.elapsed();
assert_eq!(exit_code, 0, "Should complete successfully");
assert!(
duration.as_secs() < 30,
"Self-bootstrap should complete within 30 seconds, took {:?}",
duration
);
}
#[test]
fn test_system_alert_detection_stable() {
if skip_unless_integration() {
return;
}
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!(&["analyze", project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze system_alert successfully");
let total = extract_total_issues(&stdout);
assert!(
(50..=200).contains(&total),
"system_alert should have ~73 issues (near-dup removed), got {}",
total
);
}
#[test]
fn test_rechat_server_detection_stable() {
if skip_unless_integration() {
return;
}
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!(&["analyze", project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze system_alert successfully");
let total = extract_total_issues(&stdout);
assert!(
(50..=300).contains(&total),
"ReChat-server should have ~160 issues (near-dup removed), got {}",
total
);
}
#[test]
fn test_finance_project_improved_accuracy() {
if skip_unless_integration() {
return;
}
let project_path = "../Finance";
if !Path::new(project_path).exists() {
eprintln!("Skipping: {} not found", project_path);
return;
}
let (stdout, _stderr, exit_code) = run_test!(&["analyze", project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze Finance successfully");
let total = extract_total_issues(&stdout);
assert!(
(100..=60000).contains(&total),
"Finance should have ~500-60000 issues (near-dup removed), got {}",
total
);
}
#[test]
fn test_memscope_rs_best_in_class() {
if skip_unless_integration() {
return;
}
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!(&["analyze", project_path, "--lang", "en-US"]);
assert_eq!(exit_code, 0, "Should analyze memscope-rs successfully");
let total = extract_total_issues(&stdout);
assert!(
(1000..=1500000).contains(&total),
"memscope-rs should have ~1000-1500000 issues (near-dup removed), got {}",
total
);
}
#[test]
fn test_all_testable_projects_zero_crashes() {
if skip_unless_integration() {
return;
}
let projects: Vec<(&str, Option<std::ops::RangeInclusive<u32>>)> = vec![
("../algo", Some(0..=10)), ("../gpu-code", Some(5..=60)), ];
for (path, expected_range) in projects {
if !Path::new(path).exists() {
eprintln!("Skipping: {} not found", path);
continue;
}
let (stdout, stderr, exit_code) = run_test!(&["analyze", 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() {
if skip_unless_integration() {
return;
}
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!(&["analyze", project_path, "--lang", "en-US"]);
let duration = start.elapsed();
assert_eq!(exit_code, 0, "Should complete successfully");
assert!(
duration.as_millis() < 30000,
"Small project should complete under 30s, took {:?}",
duration
);
}
#[test]
fn test_medium_project_performance_under_20s() {
if skip_unless_integration() {
return;
}
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!(&["analyze", project_path, "--lang", "en-US"]);
let duration = start.elapsed();
assert_eq!(exit_code, 0, "Should complete successfully");
assert!(
duration.as_secs() < 60,
"Medium project should complete under 60s, took {:?}",
duration
);
}
#[test]
fn test_markdown_output_format_valid() {
let (stdout, _stderr, exit_code) =
run_test!(&["analyze", ".", "--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() {
if skip_unless_integration() {
return;
}
let (stdout, _stderr, exit_code) =
run_test!(&["analyze", "../system_alert", "--lang", "en-US", "--verbose"]);
assert_eq!(exit_code, 0, "Should generate verbose output");
assert!(
stdout.contains("Score") || stdout.contains("Category"),
"Verbose output should show code quality score or categories"
);
}
#[test]
fn test_ui_context_reduces_false_positives() {
if skip_unless_integration() {
return;
}
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!(&["analyze", 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() {
if skip_unless_integration() {
return;
}
let regression_data: Vec<(&str, std::ops::RangeInclusive<u32>)> = vec![
("../system_alert", 50..=200), ("../ReChat-server", 50..=300), ("../AlgoGpuRust", 30..=100), ("../memscope-rs", 1000..=1500000), ];
for (project_path, expected_range) in regression_data {
if !Path::new(project_path).exists() {
continue;
}
let (stdout, _stderr, exit_code) = run_test!(&["analyze", 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
);
}
}