use debtmap::{builders::call_graph, priority::call_graph::CallGraph};
use tempfile::TempDir;
fn create_test_project() -> TempDir {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).unwrap();
let builder_content = r#"
use std::path::Path;
use std::collections::HashMap;
pub type CallGraph = HashMap<String, Vec<String>>;
/// This function builds a call graph by analyzing all Rust files.
/// It should have callers from command.rs and unified.rs
pub fn build_project_call_graph(
project_path: &Path,
graph: &mut CallGraph,
) -> Result<(), String> {
// Simulate call graph building
// This function calls some helpers
analyze_rust_files(project_path)?;
resolve_cross_file_calls(graph)?;
Ok(())
}
fn analyze_rust_files(_path: &Path) -> Result<(), String> {
Ok(())
}
fn resolve_cross_file_calls(_graph: &mut CallGraph) -> Result<(), String> {
Ok(())
}
"#;
std::fs::write(src_dir.join("builder.rs"), builder_content).unwrap();
let command_content = r#"
use std::path::Path;
use crate::builder::{CallGraph, build_project_call_graph};
pub fn execute_validate_command(project_path: &Path) -> Result<(), String> {
let mut call_graph = CallGraph::new();
// This is a call to build_project_call_graph - should be detected
build_project_call_graph(project_path, &mut call_graph)?;
println!("Validation complete");
Ok(())
}
"#;
std::fs::write(src_dir.join("command.rs"), command_content).unwrap();
let unified_content = r#"
use std::path::Path;
use crate::builder::{CallGraph, build_project_call_graph};
pub fn perform_unified_analysis(project_path: &Path) -> Result<(), String> {
let mut call_graph = CallGraph::new();
// This is another call to build_project_call_graph - should be detected
build_project_call_graph(project_path, &mut call_graph)?;
Ok(())
}
pub fn perform_analysis_with_cache(project_path: &Path) -> Result<(), String> {
let mut call_graph = CallGraph::new();
// Third call to build_project_call_graph - should be detected
build_project_call_graph(project_path, &mut call_graph)?;
Ok(())
}
"#;
std::fs::write(src_dir.join("unified.rs"), unified_content).unwrap();
let lib_content = r#"
pub mod builder;
pub mod command;
pub mod unified;
"#;
std::fs::write(src_dir.join("lib.rs"), lib_content).unwrap();
temp_dir
}
#[test]
fn test_cross_file_call_resolution_detects_callers() {
let test_project = create_test_project();
let project_path = test_project.path();
let mut call_graph = CallGraph::new();
let result = call_graph::process_rust_files_for_call_graph(
project_path,
&mut call_graph,
false, false, |_| {}, );
assert!(
result.is_ok(),
"Call graph construction failed: {:?}",
result.err()
);
let caller_names = call_graph.get_callers_by_name("build_project_call_graph");
println!("Found callers: {:?}", caller_names);
assert!(
caller_names.len() >= 3,
"Expected at least 3 callers for build_project_call_graph, found {}: {:?}",
caller_names.len(),
caller_names
);
assert!(
caller_names
.iter()
.any(|name| name.contains("execute_validate_command")),
"Should find caller from command module"
);
assert!(
caller_names
.iter()
.any(|name| name.contains("perform_unified_analysis")),
"Should find caller from unified module"
);
}
#[test]
fn test_qualified_call_resolution() {
let test_project = create_test_project();
let project_path = test_project.path();
let mut call_graph = CallGraph::new();
let result = call_graph::process_rust_files_for_call_graph(
project_path,
&mut call_graph,
false,
false,
|_| {}, );
assert!(result.is_ok());
let caller_names = call_graph.get_callers_by_name("build_project_call_graph");
assert!(
!caller_names.is_empty(),
"Qualified calls should be resolved. Found 0 callers for build_project_call_graph"
);
}
#[test]
fn test_namespace_resolution_with_use_statements() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).unwrap();
let module_a = r#"
pub fn target_function() {
println!("target");
}
"#;
std::fs::write(src_dir.join("module_a.rs"), module_a).unwrap();
let module_b = r#"
use crate::module_a::target_function;
use crate::module_a;
pub fn caller_with_direct_import() {
// Direct call via use statement
target_function();
}
pub fn caller_with_qualified_name() {
// Qualified call
module_a::target_function();
}
pub fn caller_with_full_path() {
// Fully qualified call
crate::module_a::target_function();
}
"#;
std::fs::write(src_dir.join("module_b.rs"), module_b).unwrap();
let lib_content = r#"
pub mod module_a;
pub mod module_b;
"#;
std::fs::write(src_dir.join("lib.rs"), lib_content).unwrap();
let mut call_graph = CallGraph::new();
let result = call_graph::process_rust_files_for_call_graph(
temp_dir.path(),
&mut call_graph,
false,
false,
|_| {}, );
assert!(result.is_ok());
let caller_names = call_graph.get_callers_by_name("target_function");
println!("Found {} callers for target_function", caller_names.len());
println!("Callers: {:?}", caller_names);
let all_functions = call_graph.find_all_functions();
println!("\nAll functions:");
for func in &all_functions {
println!(" {} ({})", func.name, func.file.display());
let callees = call_graph.get_callees(func);
if !callees.is_empty() {
for callee in callees {
println!(" -> {}", callee.name);
}
}
}
assert!(
caller_names.len() >= 3,
"Expected 3 callers (direct import, qualified, full path), found {}: {:?}",
caller_names.len(),
caller_names
);
}
#[test]
fn test_module_path_resolution() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).unwrap();
let builders_dir = src_dir.join("builders");
std::fs::create_dir_all(&builders_dir).unwrap();
let call_graph_module = r#"
pub fn process_files() {
helper_function();
}
fn helper_function() {
println!("helper");
}
"#;
std::fs::write(builders_dir.join("call_graph.rs"), call_graph_module).unwrap();
let commands_dir = src_dir.join("commands");
std::fs::create_dir_all(&commands_dir).unwrap();
let validate_module = r#"
use crate::builders::call_graph;
pub fn validate() {
// Should be detected as a call to builders::call_graph::process_files
call_graph::process_files();
}
"#;
std::fs::write(commands_dir.join("validate.rs"), validate_module).unwrap();
std::fs::write(builders_dir.join("mod.rs"), "pub mod call_graph;").unwrap();
std::fs::write(commands_dir.join("mod.rs"), "pub mod validate;").unwrap();
let lib_content = r#"
pub mod builders;
pub mod commands;
"#;
std::fs::write(src_dir.join("lib.rs"), lib_content).unwrap();
let mut call_graph = CallGraph::new();
let result = call_graph::process_rust_files_for_call_graph(
temp_dir.path(),
&mut call_graph,
false,
false,
|_| {}, );
assert!(result.is_ok());
let caller_names = call_graph.get_callers_by_name("process_files");
println!(
"Found {} callers for builders::call_graph::process_files",
caller_names.len()
);
assert!(
!caller_names.is_empty(),
"Should find call from commands::validate, found {}",
caller_names.len()
);
}