#[test]
fn test_new_graph_is_empty() {
let graph = ProjectContextGraph::new();
assert_eq!(graph.num_nodes(), 0);
assert_eq!(graph.num_edges(), 0);
assert!(graph.hot_symbols().is_empty());
}
#[test]
fn test_default_creates_empty_graph() {
let graph = ProjectContextGraph::default();
assert_eq!(graph.num_nodes(), 0);
assert_eq!(graph.num_edges(), 0);
}
#[test]
fn test_new_equals_default() {
let new = ProjectContextGraph::new();
let default = ProjectContextGraph::default();
assert_eq!(new.num_nodes(), default.num_nodes());
assert_eq!(new.num_edges(), default.num_edges());
}
#[test]
fn test_add_single_function() {
let mut graph = ProjectContextGraph::new();
let result = graph.add_item("test_fn".to_string(), create_function("test_fn", 1));
assert!(result.is_ok());
assert_eq!(graph.num_nodes(), 1);
}
#[test]
fn test_add_multiple_items() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("fn1".to_string(), create_function("fn1", 1))
.unwrap();
graph
.add_item("fn2".to_string(), create_function("fn2", 10))
.unwrap();
graph
.add_item("fn3".to_string(), create_function("fn3", 20))
.unwrap();
assert_eq!(graph.num_nodes(), 3);
}
#[test]
fn test_add_duplicate_fails() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("dup".to_string(), create_function("dup", 1))
.unwrap();
let result = graph.add_item("dup".to_string(), create_function("dup", 2));
assert!(result.is_err());
let err_msg = result.err().unwrap().to_string();
assert!(err_msg.contains("Duplicate"));
assert!(err_msg.contains("dup"));
}
#[test]
fn test_add_different_item_types() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("my_fn".to_string(), create_function("my_fn", 1))
.unwrap();
graph
.add_item("my_struct".to_string(), create_struct("my_struct", 10))
.unwrap();
graph
.add_item(
"async_fn".to_string(),
create_async_function("async_fn", 20),
)
.unwrap();
graph
.add_item(
"private_fn".to_string(),
create_private_function("private_fn", 30),
)
.unwrap();
assert_eq!(graph.num_nodes(), 4);
}
#[test]
fn test_get_item_exists() {
let mut graph = ProjectContextGraph::new();
let item = create_function("test", 1);
graph.add_item("test".to_string(), item.clone()).unwrap();
let retrieved = graph.get_item("test");
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap(), &item);
}
#[test]
fn test_get_item_not_found() {
let graph = ProjectContextGraph::new();
assert!(graph.get_item("nonexistent").is_none());
}
#[test]
fn test_get_item_after_adding_multiple() {
let mut graph = ProjectContextGraph::new();
for i in 0..10 {
let name = format!("func_{}", i);
graph
.add_item(name.clone(), create_function(&name, i * 10))
.unwrap();
}
for i in 0..10 {
let name = format!("func_{}", i);
assert!(graph.get_item(&name).is_some());
}
assert!(graph.get_item("func_99").is_none());
}
#[test]
fn test_add_edge_between_existing_nodes() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("caller".to_string(), create_function("caller", 1))
.unwrap();
graph
.add_item("callee".to_string(), create_function("callee", 10))
.unwrap();
let result = graph.add_edge("caller", "callee");
assert!(result.is_ok());
assert_eq!(graph.num_edges(), 1);
}
#[test]
fn test_add_edge_from_nonexistent_node() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("callee".to_string(), create_function("callee", 10))
.unwrap();
let result = graph.add_edge("nonexistent", "callee");
assert!(result.is_ok());
assert_eq!(graph.num_edges(), 0); }
#[test]
fn test_add_edge_to_nonexistent_node() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("caller".to_string(), create_function("caller", 1))
.unwrap();
let result = graph.add_edge("caller", "nonexistent");
assert!(result.is_ok());
assert_eq!(graph.num_edges(), 0); }
#[test]
fn test_add_multiple_edges() {
let graph = build_simple_call_graph();
assert_eq!(graph.num_edges(), 3);
}
#[test]
fn test_add_self_loop_edge() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("recursive".to_string(), create_function("recursive", 1))
.unwrap();
let result = graph.add_edge("recursive", "recursive");
assert!(result.is_ok());
assert_eq!(graph.num_edges(), 1);
}
#[test]
fn test_update_hotness_empty_graph() {
let mut graph = ProjectContextGraph::new();
let result = graph.update_hotness();
assert!(result.is_ok());
assert!(graph.hot_symbols().is_empty());
}
#[test]
fn test_update_hotness_single_node_no_edges() {
let mut graph = ProjectContextGraph::new();
graph
.add_item("lonely".to_string(), create_function("lonely", 1))
.unwrap();
let result = graph.update_hotness();
assert!(result.is_ok());
}
#[test]
fn test_update_hotness_simple_graph() {
let mut graph = build_simple_call_graph();
let result = graph.update_hotness();
assert!(result.is_ok());
let hot = graph.hot_symbols();
assert!(!hot.is_empty());
assert_eq!(hot[0].0, "utility");
}
#[test]
fn test_update_hotness_complex_graph() {
let mut graph = build_complex_graph();
let result = graph.update_hotness();
assert!(result.is_ok());
let hot = graph.hot_symbols();
assert!(!hot.is_empty());
assert_eq!(hot[0].0, "util_shared");
}
#[test]
fn test_update_hotness_updates_cache() {
let mut graph = build_simple_call_graph();
graph.update_hotness().unwrap();
let hot1 = graph.hot_symbols();
graph.update_hotness().unwrap();
let hot2 = graph.hot_symbols();
assert_eq!(hot1.len(), hot2.len());
for (a, b) in hot1.iter().zip(hot2.iter()) {
assert_eq!(a.0, b.0);
}
}
#[test]
fn test_hot_symbols_empty_before_update() {
let graph = build_simple_call_graph();
assert!(graph.hot_symbols().is_empty());
}
#[test]
fn test_hot_symbols_sorted_descending() {
let mut graph = build_simple_call_graph();
graph.update_hotness().unwrap();
let hot = graph.hot_symbols();
for i in 1..hot.len() {
assert!(
hot[i - 1].1 >= hot[i].1,
"hot_symbols should be sorted by score descending"
);
}
}
#[test]
fn test_hot_symbols_contains_all_nodes_with_edges() {
let mut graph = build_simple_call_graph();
graph.update_hotness().unwrap();
let hot = graph.hot_symbols();
let names: Vec<&str> = hot.iter().map(|(n, _)| n.as_str()).collect();
assert!(names.contains(&"main"));
assert!(names.contains(&"helper"));
assert!(names.contains(&"utility"));
}