use debtmap::analyzers::rust_call_graph::extract_call_graph;
use std::path::PathBuf;
#[test]
fn test_struct_literal_field_function_call() {
let code = r#"
struct Config {
value: String,
}
fn create_value() -> String {
"test".to_string()
}
fn main() {
let config = Config {
value: create_value(),
};
}
"#;
let syntax = syn::parse_file(code).expect("Failed to parse code");
let path = PathBuf::from("test.rs");
let call_graph = extract_call_graph(&syntax, &path);
let all_functions = call_graph.find_all_functions();
let main_fn = all_functions
.iter()
.find(|f| f.name == "main")
.expect("main function should exist");
let create_value_fn = all_functions
.iter()
.find(|f| f.name == "create_value")
.expect("create_value function should exist");
let calls_from_main = call_graph.get_callees(main_fn);
assert!(
calls_from_main.contains(create_value_fn),
"main should call create_value through struct literal field"
);
}
#[test]
fn test_nested_struct_literal_calls() {
let code = r#"
struct Inner {
data: i32,
}
struct Outer {
inner: Inner,
}
fn get_data() -> i32 {
42
}
fn build_structure() -> Outer {
Outer {
inner: Inner {
data: get_data(),
},
}
}
"#;
let syntax = syn::parse_file(code).expect("Failed to parse code");
let path = PathBuf::from("test.rs");
let call_graph = extract_call_graph(&syntax, &path);
let all_functions = call_graph.find_all_functions();
let build_fn = all_functions
.iter()
.find(|f| f.name == "build_structure")
.expect("build_structure function should exist");
let get_data_fn = all_functions
.iter()
.find(|f| f.name == "get_data")
.expect("get_data function should exist");
let calls_from_build = call_graph.get_callees(build_fn);
assert!(
calls_from_build.contains(get_data_fn),
"build_structure should call get_data through nested struct literal"
);
}
#[test]
fn test_struct_literal_in_vec_macro() {
let code = r#"
struct Item {
name: String,
value: i32,
}
fn generate_name() -> String {
"item".to_string()
}
fn compute_value() -> i32 {
100
}
fn create_items() -> Vec<Item> {
vec![Item {
name: generate_name(),
value: compute_value(),
}]
}
"#;
let syntax = syn::parse_file(code).expect("Failed to parse code");
let path = PathBuf::from("test.rs");
let call_graph = extract_call_graph(&syntax, &path);
let all_functions = call_graph.find_all_functions();
let create_items_fn = all_functions
.iter()
.find(|f| f.name == "create_items")
.expect("create_items function should exist");
let generate_name_fn = all_functions
.iter()
.find(|f| f.name == "generate_name")
.expect("generate_name function should exist");
let compute_value_fn = all_functions
.iter()
.find(|f| f.name == "compute_value")
.expect("compute_value function should exist");
let calls_from_create = call_graph.get_callees(create_items_fn);
assert!(
calls_from_create.contains(generate_name_fn),
"create_items should call generate_name through vec! macro struct literal"
);
assert!(
calls_from_create.contains(compute_value_fn),
"create_items should call compute_value through vec! macro struct literal"
);
}
#[test]
fn test_method_call_with_struct_literal_receiver() {
let code = r#"
struct Calculator {
value: i32,
}
impl Calculator {
fn compute(&self) -> i32 {
self.value * 2
}
}
fn get_initial_value() -> i32 {
10
}
fn calculate() -> i32 {
let calc = Calculator {
value: get_initial_value(),
};
calc.compute()
}
"#;
let syntax = syn::parse_file(code).expect("Failed to parse code");
let path = PathBuf::from("test.rs");
let call_graph = extract_call_graph(&syntax, &path);
let all_functions = call_graph.find_all_functions();
let calculate_fn = all_functions
.iter()
.find(|f| f.name == "calculate")
.expect("calculate function should exist");
let get_initial_fn = all_functions
.iter()
.find(|f| f.name == "get_initial_value")
.expect("get_initial_value function should exist");
let compute_method = all_functions
.iter()
.find(|f| f.name == "Calculator::compute")
.expect("Calculator::compute method should exist");
let calls_from_calculate = call_graph.get_callees(calculate_fn);
assert!(
calls_from_calculate.contains(get_initial_fn),
"calculate should call get_initial_value through struct literal"
);
assert!(
calls_from_calculate.contains(compute_method),
"calculate should call Calculator::compute method"
);
}