#![cfg(any())]
use ai_code_buddy::{
args::Args,
core::{
ai_analyzer::{AnalysisRequest, GpuBackend, ProgressUpdate},
analysis::perform_analysis,
git::GitAnalyzer,
review::{CommitStatus, Issue, Review},
},
};
use std::path::Path;
use tempfile::TempDir;
use tokio;
#[cfg(test)]
mod core_ai_analyzer_tests {
use super::*;
#[test]
fn test_analysis_request_structure() {
let request = AnalysisRequest {
file_path: "src/test.rs".to_string(),
content: "fn main() { println!(\"Hello\"); }".to_string(),
language: "rust".to_string(),
commit_status: CommitStatus::Modified,
};
assert_eq!(request.file_path, "src/test.rs");
assert_eq!(request.language, "rust");
assert!(request.content.contains("Hello"));
assert!(matches!(request.commit_status, CommitStatus::Modified));
}
#[test]
fn test_analysis_request_serialization() {
let request = AnalysisRequest {
file_path: "test.rs".to_string(),
content: "test content".to_string(),
language: "rust".to_string(),
commit_status: CommitStatus::Modified,
};
let json = serde_json::to_string(&request).expect("Should serialize");
let deserialized: AnalysisRequest =
serde_json::from_str(&json).expect("Should deserialize");
assert_eq!(request.file_path, deserialized.file_path);
assert_eq!(request.content, deserialized.content);
assert_eq!(request.language, deserialized.language);
}
#[test]
fn test_progress_update_structure() {
let progress = ProgressUpdate {
current_file: "src/main.rs".to_string(),
progress: 0.5,
stage: "analyzing".to_string(),
};
assert_eq!(progress.current_file, "src/main.rs");
assert_eq!(progress.progress, 0.5);
assert_eq!(progress.stage, "analyzing");
}
#[test]
fn test_gpu_backend_variants() {
let backends = vec![
GpuBackend::Cpu,
GpuBackend::Cuda,
GpuBackend::Metal,
GpuBackend::Mkl,
];
for backend in backends {
let display_str = format!("{}", backend);
assert!(!display_str.is_empty());
let debug_str = format!("{:?}", backend);
assert!(!debug_str.is_empty());
}
}
#[test]
fn test_gpu_backend_display() {
assert_eq!(format!("{}", GpuBackend::Metal), "Metal");
assert_eq!(format!("{}", GpuBackend::Cuda), "CUDA");
assert_eq!(format!("{}", GpuBackend::Mkl), "MKL");
assert_eq!(format!("{}", GpuBackend::Cpu), "CPU");
}
#[test]
fn test_gpu_backend_equality() {
assert_eq!(GpuBackend::Cpu, GpuBackend::Cpu);
assert_eq!(GpuBackend::Cuda, GpuBackend::Cuda);
assert_ne!(GpuBackend::Cpu, GpuBackend::Cuda);
assert_ne!(GpuBackend::Metal, GpuBackend::Mkl);
}
#[test]
fn test_analysis_request_with_different_commit_statuses() {
let statuses = vec![
CommitStatus::Committed,
CommitStatus::Staged,
CommitStatus::Modified,
CommitStatus::Untracked,
];
for status in statuses {
let request = AnalysisRequest {
file_path: "test.rs".to_string(),
content: "test".to_string(),
language: "rust".to_string(),
commit_status: status.clone(),
};
assert_eq!(request.commit_status, status);
}
}
#[test]
fn test_analysis_request_with_different_languages() {
let languages = vec!["rust", "javascript", "python", "go", "typescript"];
for lang in languages {
let request = AnalysisRequest {
file_path: format!("test.{}", lang),
content: "test content".to_string(),
language: lang.to_string(),
commit_status: CommitStatus::Added,
};
assert_eq!(request.language, lang);
assert!(request.file_path.contains(lang));
}
}
#[test]
fn test_progress_update_bounds() {
let mut progress = ProgressUpdate {
current_file: "test.rs".to_string(),
progress: 0.0,
stage: "start".to_string(),
};
progress.progress = 0.0;
assert_eq!(progress.progress, 0.0);
progress.progress = 0.5;
assert_eq!(progress.progress, 0.5);
progress.progress = 1.0;
assert_eq!(progress.progress, 1.0);
progress.progress = -0.1; progress.progress = 1.1; }
#[test]
fn test_analysis_request_large_content() {
let large_content = "a".repeat(100_000);
let request = AnalysisRequest {
file_path: "large_file.txt".to_string(),
content: large_content.clone(),
language: "text".to_string(),
commit_status: CommitStatus::Added,
};
assert_eq!(request.content.len(), 100_000);
assert_eq!(request.content, large_content);
}
#[test]
fn test_analysis_request_unicode_content() {
let unicode_content = "Hello, 世界! 🚀 Rust is awesome!";
let request = AnalysisRequest {
file_path: "unicode_test.rs".to_string(),
content: unicode_content.to_string(),
language: "rust".to_string(),
commit_status: CommitStatus::Modified,
};
assert!(request.content.contains("世界"));
assert!(request.content.contains("🚀"));
assert!(request.content.contains("Rust"));
}
}
#[cfg(test)]
mod core_analysis_tests {
use super::*;
use clap::Parser;
#[tokio::test]
async fn test_perform_analysis_with_invalid_repo() {
let args = Args::parse_from(["test", "/non/existent/path"]);
let result = perform_analysis(&args).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_perform_analysis_with_valid_git_repo() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let repo_path = temp_dir.path();
std::process::Command::new("git")
.args(["init"])
.current_dir(repo_path)
.output()
.expect("Failed to init git repo");
std::process::Command::new("git")
.args(["config", "user.email", "test@example.com"])
.current_dir(repo_path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(repo_path)
.output()
.unwrap();
std::fs::write(
repo_path.join("test.rs"),
"fn main() { println!(\"Hello\"); }",
)
.unwrap();
std::process::Command::new("git")
.args(["add", "test.rs"])
.current_dir(repo_path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["commit", "-m", "Initial commit"])
.current_dir(repo_path)
.output()
.unwrap();
let args = Args::parse_from(["test", repo_path.to_str().unwrap()]);
let result = perform_analysis(&args).await;
println!("Analysis result: {:?}", result);
}
#[test]
fn test_args_parsing_variants() {
let args = Args::parse_from(["test", "."]);
assert_eq!(args.repo_path, ".");
let args = Args::parse_from(["test", ".", "--cpu"]);
assert!(args.force_cpu);
let args = Args::parse_from(["test", ".", "--format", "json"]);
assert!(matches!(
args.output_format,
ai_code_buddy::args::OutputFormat::Json
));
}
#[test]
fn test_args_default_values() {
let args = Args::parse_from(["test", "test_repo"]);
assert_eq!(args.repo_path, "test_repo");
assert_eq!(args.source_branch, "HEAD");
assert_eq!(args.target_branch, "main");
assert!(!args.force_cpu);
assert!(!args.show_credits);
}
}
#[cfg(test)]
mod core_git_tests {
use super::*;
#[test]
fn test_git_analyzer_with_invalid_repo() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let repo_path = temp_dir.path();
let result = GitAnalyzer::new(repo_path);
assert!(result.is_err());
}
#[test]
fn test_git_analyzer_with_valid_repo() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let repo_path = temp_dir.path();
std::process::Command::new("git")
.args(["init"])
.current_dir(repo_path)
.output()
.expect("Failed to init git repo");
let result = GitAnalyzer::new(repo_path);
assert!(result.is_ok());
}
#[test]
fn test_git_analyzer_file_operations() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let repo_path = temp_dir.path();
std::process::Command::new("git")
.args(["init"])
.current_dir(repo_path)
.output()
.expect("Failed to init git repo");
std::process::Command::new("git")
.args(["config", "user.email", "test@example.com"])
.current_dir(repo_path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(repo_path)
.output()
.unwrap();
let test_content = "Hello, Git!";
std::fs::write(repo_path.join("test.txt"), test_content).unwrap();
std::process::Command::new("git")
.args(["add", "test.txt"])
.current_dir(repo_path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["commit", "-m", "Add test file"])
.current_dir(repo_path)
.output()
.unwrap();
let analyzer = GitAnalyzer::new(repo_path).unwrap();
let result = analyzer.get_changed_files("HEAD", "HEAD");
assert!(result.is_ok());
}
#[test]
fn test_git_analyzer_error_handling() {
let result = GitAnalyzer::new(Path::new("/non/existent/path"));
assert!(result.is_err());
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("not_a_directory.txt");
std::fs::write(&file_path, "content").unwrap();
let result = GitAnalyzer::new(&file_path);
assert!(result.is_err());
}
#[test]
fn test_git_analyzer_branch_scenarios() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let repo_path = temp_dir.path();
std::process::Command::new("git")
.args(["init"])
.current_dir(repo_path)
.output()
.expect("Failed to init git repo");
std::process::Command::new("git")
.args(["config", "user.email", "test@example.com"])
.current_dir(repo_path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(repo_path)
.output()
.unwrap();
std::fs::write(repo_path.join("README.md"), "# Test Repo").unwrap();
std::process::Command::new("git")
.args(["add", "README.md"])
.current_dir(repo_path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["commit", "-m", "Initial commit"])
.current_dir(repo_path)
.output()
.unwrap();
let analyzer = GitAnalyzer::new(repo_path).unwrap();
let result = analyzer.get_changed_files("HEAD", "HEAD");
assert!(result.is_ok());
let result = analyzer.get_changed_files("non-existent-branch", "HEAD");
println!("Non-existent branch result: {:?}", result);
}
}
#[cfg(test)]
mod core_review_tests {
use super::*;
#[test]
fn test_review_structure() {
let review = Review {
files_count: 5,
issues_count: 10,
critical_issues: 1,
high_issues: 2,
medium_issues: 3,
low_issues: 4,
issues: Vec::new(),
};
assert_eq!(review.files_count, 5);
assert_eq!(review.issues_count, 10);
assert_eq!(
review.critical_issues + review.high_issues + review.medium_issues + review.low_issues,
10
);
}
#[test]
fn test_commit_status_variants() {
let statuses = vec![
CommitStatus::Added,
CommitStatus::Modified,
CommitStatus::Deleted,
CommitStatus::Renamed,
CommitStatus::Copied,
CommitStatus::Unmodified,
];
for status in statuses {
let cloned_status = status.clone();
assert_eq!(status, cloned_status);
let debug_str = format!("{:?}", status);
assert!(!debug_str.is_empty());
}
}
#[test]
fn test_issue_creation() {
let issue = Issue {
file_path: "src/main.rs".to_string(),
line_number: 42,
column: 10,
severity: "high".to_string(),
message: "Potential security vulnerability".to_string(),
suggestion: Some("Use secure alternative".to_string()),
rule_id: Some("SEC001".to_string()),
};
assert_eq!(issue.file_path, "src/main.rs");
assert_eq!(issue.line_number, 42);
assert_eq!(issue.severity, "high");
assert!(issue.suggestion.is_some());
assert!(issue.rule_id.is_some());
}
#[test]
fn test_review_with_issues() {
let issues = vec![
Issue {
file_path: "src/main.rs".to_string(),
line_number: 10,
column: 5,
severity: "critical".to_string(),
message: "Critical issue".to_string(),
suggestion: None,
rule_id: None,
},
Issue {
file_path: "src/lib.rs".to_string(),
line_number: 20,
column: 15,
severity: "medium".to_string(),
message: "Medium issue".to_string(),
suggestion: Some("Fix suggestion".to_string()),
rule_id: Some("RULE001".to_string()),
},
];
let review = Review {
files_count: 2,
issues_count: issues.len(),
critical_issues: 1,
high_issues: 0,
medium_issues: 1,
low_issues: 0,
issues,
};
assert_eq!(review.issues.len(), 2);
assert_eq!(review.issues[0].severity, "critical");
assert_eq!(review.issues[1].severity, "medium");
assert!(review.issues[1].suggestion.is_some());
}
#[test]
fn test_review_serialization() {
let review = Review {
files_count: 1,
issues_count: 1,
critical_issues: 0,
high_issues: 0,
medium_issues: 1,
low_issues: 0,
issues: vec![Issue {
file_path: "test.rs".to_string(),
line_number: 1,
column: 1,
severity: "medium".to_string(),
message: "Test issue".to_string(),
suggestion: None,
rule_id: None,
}],
};
let json = serde_json::to_string(&review).expect("Should serialize");
let deserialized: Review = serde_json::from_str(&json).expect("Should deserialize");
assert_eq!(review.files_count, deserialized.files_count);
assert_eq!(review.issues_count, deserialized.issues_count);
assert_eq!(review.issues.len(), deserialized.issues.len());
}
}
#[test]
fn legacy_core_comprehensive_placeholder() {
assert!(true);
}