use ai_code_buddy::core::analysis::perform_analysis_with_progress;
use ai_code_buddy::{Args, OutputFormat};
use std::process::Command;
use std::{
fs,
sync::{Arc, Mutex},
};
use tempfile::TempDir;
fn git(repo: &str, args: &[&str]) {
let status = Command::new("git")
.args(args)
.current_dir(repo)
.status()
.expect("failed to run git");
assert!(status.success(), "git {args:?} failed");
}
fn setup_repo_with_branches() -> (TempDir, String) {
let temp = TempDir::new().unwrap();
let repo = temp.path().to_str().unwrap().to_string();
git(&repo, &["init"]);
git(&repo, &["checkout", "-b", "main"]);
git(&repo, &["config", "user.name", "Test User"]);
git(&repo, &["config", "user.email", "test@example.com"]);
fs::write(
format!("{repo}/file.rs"),
"fn main() { println!(\"hello\"); }\n",
)
.unwrap();
fs::write(
format!("{repo}/shared.rs"),
"pub fn shared() { println!(\"base\"); }\n",
)
.unwrap();
git(&repo, &["add", "."]);
git(&repo, &["commit", "-m", "init"]);
git(&repo, &["checkout", "-b", "feature"]);
fs::write(
format!("{repo}/file.rs"),
"fn main() { let password = \"x\"; println!(\"changed\"); }\n",
)
.unwrap();
git(&repo, &["add", "file.rs"]);
git(
&repo,
&["commit", "-m", "change file to include security issue"],
);
fs::write(
format!("{repo}/staged.rs"),
"pub fn staged() { unsafe { /* risky */ } }\n",
)
.unwrap();
git(&repo, &["add", "staged.rs"]);
fs::write(
format!("{repo}/untracked.rs"),
"pub fn untracked() { eval(\"2+2\"); }\n",
)
.unwrap();
fs::write(
format!("{repo}/shared.rs"),
"pub fn shared() { let _x = 1; unwrap_me().unwrap(); }\n",
)
.unwrap();
(temp, repo)
}
#[test]
fn test_perform_analysis_with_progress_covers_paths() {
let (_temp, repo) = setup_repo_with_branches();
let args = Args {
repo_path: repo.clone(),
source_branch: "main".to_string(),
target_branch: "HEAD".to_string(), cli_mode: true,
verbose: false,
show_credits: false,
output_format: OutputFormat::Summary,
exclude_patterns: vec![],
include_patterns: vec!["*.rs".to_string()], use_gpu: false,
force_cpu: true,
parallel: false,
disable_ai: false,
};
let progress: Arc<Mutex<Vec<(f64, String)>>> = Arc::new(Mutex::new(Vec::new()));
let progress_clone = progress.clone();
let rt = tokio::runtime::Runtime::new().unwrap();
let review = rt
.block_on(perform_analysis_with_progress(
&args,
Some(Box::new(move |p, s| {
progress_clone.lock().unwrap().push((p, s));
})),
))
.expect("analysis should succeed on prepared repo");
assert!(review.issues_count >= 1, "expected at least one issue");
assert_eq!(
review.issues_count,
review.critical_issues + review.high_issues + review.medium_issues + review.low_issues
);
let calls = progress.lock().unwrap();
assert!(!calls.is_empty(), "expected progress updates");
}