use cs::trace::{CallExtractor, FunctionFinder};
use cs::trace::{CallGraphBuilder, TraceDirection};
use std::env;
use std::path::PathBuf;
fn setup_finder_and_extractor() -> (FunctionFinder, CallExtractor) {
let base_dir = env::current_dir()
.unwrap()
.join("tests/fixtures/call-trace");
let finder = FunctionFinder::new(base_dir.clone());
let extractor = CallExtractor::new(base_dir);
(finder, extractor)
}
#[test]
fn test_build_simple_trace_tree() {
let (mut finder, extractor) = setup_finder_and_extractor();
let start_fn_name = "checkout";
if let Some(start_fn) = finder.find_function(start_fn_name) {
let mut builder =
CallGraphBuilder::new(TraceDirection::Forward, 3, &mut finder, &extractor);
let result = builder.build_trace(&start_fn);
assert!(result.is_ok());
if let Ok(Some(tree)) = result {
assert_eq!(tree.root.def.name, start_fn_name);
let child_names: Vec<_> = tree
.root
.children
.iter()
.map(|c| c.def.name.clone())
.collect();
println!("Found {} children: {:?}", child_names.len(), child_names);
}
} else {
println!(
"Function '{}' not found, which is expected in test environment",
start_fn_name
);
}
}
#[test]
fn test_backward_trace_tree() {
let (mut finder, extractor) = setup_finder_and_extractor();
let start_fn_name = "calculateTotal";
if let Some(start_fn) = finder.find_function(start_fn_name) {
let mut builder =
CallGraphBuilder::new(TraceDirection::Backward, 2, &mut finder, &extractor);
let result = builder.build_trace(&start_fn);
assert!(result.is_ok());
if let Ok(Some(tree)) = result {
assert_eq!(tree.root.def.name, start_fn_name);
println!("Backward trace found {} callers", tree.root.children.len());
}
} else {
println!("Function '{}' not found in test environment", start_fn_name);
}
}
#[test]
fn test_depth_limit() {
let (mut finder, extractor) = setup_finder_and_extractor();
use cs::trace::FunctionDef;
let test_fn = FunctionDef {
name: "testFunction".to_string(),
file: PathBuf::from("test.js"),
line: 1,
body: "function testFunction() { return 42; }".to_string(),
};
let mut builder = CallGraphBuilder::new(TraceDirection::Forward, 1, &mut finder, &extractor);
let result = builder.build_trace(&test_fn);
assert!(result.is_ok());
if let Ok(Some(tree)) = result {
assert_eq!(tree.root.def.name, "testFunction");
assert!(tree.max_depth() <= 1);
}
}
#[test]
fn test_cycle_detection() {
let (mut finder, extractor) = setup_finder_and_extractor();
use cs::trace::FunctionDef;
let recursive_fn = FunctionDef {
name: "recursiveFunction".to_string(),
file: PathBuf::from("recursive.js"),
line: 1,
body: "function recursiveFunction() { return recursiveFunction(); }".to_string(),
};
let mut builder = CallGraphBuilder::new(TraceDirection::Forward, 10, &mut finder, &extractor);
let result = builder.build_trace(&recursive_fn);
assert!(result.is_ok());
if let Ok(Some(tree)) = result {
assert_eq!(tree.root.def.name, "recursiveFunction");
assert!(tree.node_count() < 100); }
}
#[test]
fn test_empty_function_handling() {
let (mut finder, extractor) = setup_finder_and_extractor();
use cs::trace::FunctionDef;
let empty_fn = FunctionDef {
name: "emptyFunction".to_string(),
file: PathBuf::from("empty.js"),
line: 1,
body: "function emptyFunction() {}".to_string(),
};
let mut builder = CallGraphBuilder::new(TraceDirection::Forward, 5, &mut finder, &extractor);
let result = builder.build_trace(&empty_fn);
assert!(result.is_ok());
if let Ok(Some(tree)) = result {
assert_eq!(tree.root.def.name, "emptyFunction");
assert_eq!(tree.root.children.len(), 0);
assert_eq!(tree.node_count(), 1);
assert_eq!(tree.max_depth(), 0);
}
}