#[cfg(test)]
use crate::core::cache::FileCache;
use crate::core::semantic::parallel_analyzer::{AnalysisOptions, ParallelAnalyzer};
use std::collections::HashSet;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tempfile::TempDir;
fn create_test_file(dir: &Path, name: &str, content: &str) -> PathBuf {
let path = dir.join(name);
fs::write(&path, content).unwrap();
path
}
fn create_test_environment() -> (TempDir, Vec<PathBuf>) {
let temp_dir = TempDir::new().unwrap();
let dir = temp_dir.path();
let files = vec![
create_test_file(
dir,
"main.rs",
r#"
use crate::utils::helper;
use std::collections::HashMap;
fn main() {
let data: HashMap<String, i32> = HashMap::new();
helper::process(&data);
}
"#,
),
create_test_file(
dir,
"utils.rs",
r#"
pub mod helper {
use std::collections::HashMap;
pub fn process(data: &HashMap<String, i32>) {
println!("Processing: {:?}", data);
}
}
"#,
),
create_test_file(
dir,
"lib.rs",
r#"
pub mod utils;
pub fn init() {
println!("Library initialized");
}
"#,
),
];
(temp_dir, files)
}
#[test]
fn test_parallel_file_analysis() {
let (_temp_dir, files) = create_test_environment();
let cache = Arc::new(FileCache::new());
let project_root = files[0].parent().unwrap().to_path_buf();
let analyzer = ParallelAnalyzer::new(&cache);
let options = AnalysisOptions {
semantic_depth: 3,
trace_imports: true,
include_types: true,
include_functions: true,
};
let valid_files: HashSet<PathBuf> = files.iter().cloned().collect();
let results = analyzer
.analyze_files(&files, &project_root, &options, &valid_files)
.unwrap();
assert_eq!(results.len(), files.len());
for (i, result) in results.iter().enumerate() {
assert_eq!(result.file_index, i);
assert!(result.content_hash.is_some());
assert!(result.error.is_none());
}
let main_result = &results[0];
assert!(main_result.content_hash.is_some());
}
#[test]
fn test_thread_pool_management() {
let (_temp_dir, files) = create_test_environment();
let cache = Arc::new(FileCache::new());
let project_root = files[0].parent().unwrap().to_path_buf();
let analyzer = ParallelAnalyzer::with_thread_count(&cache, 2);
let options = AnalysisOptions {
semantic_depth: 3,
trace_imports: true,
include_types: true,
include_functions: true,
};
let valid_files: HashSet<PathBuf> = files.iter().cloned().collect();
let results = analyzer
.analyze_files(&files, &project_root, &options, &valid_files)
.unwrap();
assert_eq!(results.len(), files.len());
}
#[test]
fn test_analysis_error_handling() {
let temp_dir = TempDir::new().unwrap();
let dir = temp_dir.path();
let bad_file = create_test_file(
dir,
"bad.rs",
r#"
use std::collections::HashMap
// Missing semicolon above
fn main() {
let x =
// Incomplete statement
"#,
);
let cache = Arc::new(FileCache::new());
let analyzer = ParallelAnalyzer::new(&cache);
let options = AnalysisOptions {
semantic_depth: 3,
trace_imports: true,
include_types: true,
include_functions: true,
};
let valid_files: HashSet<PathBuf> = [bad_file.clone()].iter().cloned().collect();
let results = analyzer
.analyze_files(&[bad_file.clone()], dir, &options, &valid_files)
.unwrap();
assert_eq!(results.len(), 1);
let result = &results[0];
assert!(result.content_hash.is_some());
}
#[test]
fn test_empty_file_list() {
let cache = Arc::new(FileCache::new());
let analyzer = ParallelAnalyzer::new(&cache);
let options = AnalysisOptions::default();
let project_root = PathBuf::from("/tmp");
let valid_files: HashSet<PathBuf> = HashSet::new();
let results = analyzer
.analyze_files(&[], &project_root, &options, &valid_files)
.unwrap();
assert_eq!(results.len(), 0);
}
#[test]
fn test_large_file_set() {
let temp_dir = TempDir::new().unwrap();
let dir = temp_dir.path();
let mut files = Vec::new();
for i in 0..20 {
let content = format!(
r#"
pub mod module_{i} {{
pub fn function_{i}() -> i32 {{
{i}
}}
}}
"#
);
files.push(create_test_file(dir, &format!("mod_{i}.rs"), &content));
}
let cache = Arc::new(FileCache::new());
let analyzer = ParallelAnalyzer::new(&cache);
let options = AnalysisOptions {
semantic_depth: 2,
trace_imports: false,
include_types: false,
include_functions: true,
};
let start = std::time::Instant::now();
let valid_files: HashSet<PathBuf> = files.iter().cloned().collect();
let results = analyzer
.analyze_files(&files, dir, &options, &valid_files)
.unwrap();
let duration = start.elapsed();
assert_eq!(results.len(), 20);
assert!(
duration.as_secs() < 5,
"Analysis took too long: {duration:?}"
);
for result in &results {
assert!(result.content_hash.is_some() || result.error.is_some());
}
}
#[test]
fn test_non_code_files_handled() {
let temp_dir = TempDir::new().unwrap();
let dir = temp_dir.path();
let files = vec![
create_test_file(dir, "README.md", "# Project README"),
create_test_file(dir, "data.json", r#"{"key": "value"}"#),
create_test_file(dir, "main.rs", "fn main() {}"),
];
let cache = Arc::new(FileCache::new());
let analyzer = ParallelAnalyzer::new(&cache);
let options = AnalysisOptions::default();
let valid_files: HashSet<PathBuf> = files.iter().cloned().collect();
let results = analyzer
.analyze_files(&files, dir, &options, &valid_files)
.unwrap();
assert_eq!(results.len(), 3);
assert!(results[0].imports.is_empty()); assert!(results[1].imports.is_empty());
assert!(results[2].content_hash.is_some()); }
#[test]
fn test_cache_utilization() {
let (_temp_dir, files) = create_test_environment();
let cache = Arc::new(FileCache::new());
let project_root = files[0].parent().unwrap().to_path_buf();
let analyzer = ParallelAnalyzer::new(&cache);
let options = AnalysisOptions::default();
let valid_files: HashSet<PathBuf> = files.iter().cloned().collect();
let results1 = analyzer
.analyze_files(&files, &project_root, &options, &valid_files)
.unwrap();
let start = std::time::Instant::now();
let results2 = analyzer
.analyze_files(&files, &project_root, &options, &valid_files)
.unwrap();
let duration = start.elapsed();
assert_eq!(results1.len(), results2.len());
for (r1, r2) in results1.iter().zip(results2.iter()) {
assert_eq!(r1.content_hash, r2.content_hash);
}
assert!(
duration.as_millis() < 500,
"Cache not being utilized effectively: {duration:?}"
);
}
#[test]
fn test_selective_analysis_options() {
let (_temp_dir, files) = create_test_environment();
let cache = Arc::new(FileCache::new());
let project_root = files[0].parent().unwrap().to_path_buf();
let analyzer = ParallelAnalyzer::new(&cache);
let import_only_options = AnalysisOptions {
semantic_depth: 3,
trace_imports: true,
include_types: false,
include_functions: false,
};
let valid_files: HashSet<PathBuf> = files.iter().cloned().collect();
let results = analyzer
.analyze_files(&files, &project_root, &import_only_options, &valid_files)
.unwrap();
let main_result = &results[0];
assert!(main_result.content_hash.is_some());
assert!(main_result.type_references.is_empty());
assert!(main_result.function_calls.is_empty());
}