#[test]
fn test_build_indices() {
let functions = vec![
FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "foo".to_string(),
signature: "fn foo()".to_string(),
doc_comment: None,
source: "fn foo() {}".to_string(),
start_line: 1,
end_line: 1,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "abc".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
},
FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "bar".to_string(),
signature: "fn bar()".to_string(),
doc_comment: None,
source: "fn bar() {}".to_string(),
start_line: 3,
end_line: 3,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "def".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
},
];
let indices = build_indices(&functions);
assert_eq!(indices.name_index["foo"], vec![0]);
assert_eq!(indices.name_index["bar"], vec![1]);
assert_eq!(indices.file_index["a.rs"], vec![0, 1]);
assert_eq!(indices.corpus.len(), 2);
}
#[test]
fn test_build_call_graph() {
let functions = vec![
FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "foo".to_string(),
signature: "fn foo()".to_string(),
doc_comment: None,
source: "fn foo() { bar(); }".to_string(),
start_line: 1,
end_line: 1,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "abc".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
},
FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "bar".to_string(),
signature: "fn bar()".to_string(),
doc_comment: None,
source: "fn bar() { println!(\"hello\"); }".to_string(),
start_line: 3,
end_line: 3,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "def".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
},
];
let indices = build_indices(&functions);
let (calls, called_by) = build_call_graph(&functions, &indices.name_index);
assert!(calls.get(&0).map_or(false, |v| v.contains(&1)));
assert!(called_by.get(&1).map_or(false, |v| v.contains(&0)));
assert!(!calls.get(&1).map_or(false, |v| v.contains(&0)));
}
#[test]
fn test_get_calls_and_called_by() {
let functions = vec![
FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "caller".to_string(),
signature: "fn caller()".to_string(),
doc_comment: None,
source: "fn caller() { callee(); }".to_string(),
start_line: 1,
end_line: 1,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "aaa".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
},
FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "callee".to_string(),
signature: "fn callee()".to_string(),
doc_comment: None,
source: "fn callee() { println!(\"hello\"); }".to_string(),
start_line: 3,
end_line: 3,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "bbb".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
},
];
let indices = build_indices(&functions);
let corpus_lower: Vec<String> = indices.corpus.iter().map(|c| c.to_lowercase()).collect();
let (calls, called_by) = build_call_graph(&functions, &indices.name_index);
let graph_metrics = compute_graph_metrics(functions.len(), &calls, &called_by);
let index = AgentContextIndex {
functions,
name_index: indices.name_index,
file_index: indices.file_index,
corpus: indices.corpus,
corpus_lower,
name_frequency: HashMap::new(),
calls,
called_by,
graph_metrics,
project_root: PathBuf::from("/test"),
manifest: IndexManifest {
version: "1.3.0".to_string(),
built_at: "2025-01-01T00:00:00Z".to_string(),
project_root: "/test".to_string(),
function_count: 2,
file_count: 1,
languages: vec!["Rust".to_string()],
avg_tdg_score: 0.0,
file_checksums: HashMap::new(),
last_incremental_changes: 0,
},
db_path: None,
coverage_off_files: HashSet::new(),
};
let calls_of_0 = index.get_calls(0);
assert!(calls_of_0.contains(&"callee"), "caller should call callee");
let called_by_1 = index.get_called_by(1);
assert!(
called_by_1.contains(&"caller"),
"callee should be called by caller"
);
assert!(index.get_calls(999).is_empty());
assert!(index.get_called_by(999).is_empty());
}
#[test]
fn test_find_function_index() {
let functions = vec![FunctionEntry {
file_path: "a.rs".to_string(),
function_name: "foo".to_string(),
signature: "fn foo()".to_string(),
doc_comment: None,
source: "fn foo() {}".to_string(),
start_line: 1,
end_line: 1,
language: "Rust".to_string(),
quality: QualityMetrics::default(),
checksum: "aaa".to_string(),
definition_type: DefinitionType::default(),
commit_count: 0,
churn_score: 0.0,
clone_count: 0,
pattern_diversity: 0.0,
fault_annotations: Vec::new(), linked_definition: None,
}];
let indices = build_indices(&functions);
let corpus_lower: Vec<String> = indices.corpus.iter().map(|c| c.to_lowercase()).collect();
let index = AgentContextIndex {
functions,
name_index: indices.name_index,
file_index: indices.file_index,
corpus: indices.corpus,
corpus_lower,
name_frequency: HashMap::new(),
calls: HashMap::new(),
called_by: HashMap::new(),
graph_metrics: vec![GraphMetrics::default()],
project_root: PathBuf::from("/test"),
manifest: IndexManifest {
version: "1.3.0".to_string(),
built_at: "2025-01-01T00:00:00Z".to_string(),
project_root: "/test".to_string(),
function_count: 1,
file_count: 1,
languages: vec!["Rust".to_string()],
avg_tdg_score: 0.0,
file_checksums: HashMap::new(),
last_incremental_changes: 0,
},
db_path: None,
coverage_off_files: HashSet::new(),
};
assert_eq!(index.find_function_index("a.rs", "foo"), Some(0));
assert_eq!(index.find_function_index("a.rs", "bar"), None);
assert_eq!(index.find_function_index("b.rs", "foo"), None);
}
#[test]
fn test_compute_graph_metrics_empty() {
let metrics = compute_graph_metrics(0, &HashMap::new(), &HashMap::new());
assert!(metrics.is_empty());
}
#[test]
fn test_compute_graph_metrics_isolated_nodes() {
let metrics = compute_graph_metrics(3, &HashMap::new(), &HashMap::new());
assert_eq!(metrics.len(), 3);
for m in &metrics {
assert!(
m.pagerank > 0.0,
"isolated node should have positive pagerank"
);
assert_eq!(m.in_degree, 0);
assert_eq!(m.out_degree, 0);
}
let diff = (metrics[0].pagerank - metrics[1].pagerank).abs();
assert!(
diff < 0.001,
"isolated nodes should have near-equal pagerank"
);
}
#[test]
fn test_compute_graph_metrics_chain() {
let mut calls = HashMap::new();
calls.insert(0, vec![1]);
calls.insert(1, vec![2]);
let mut called_by = HashMap::new();
called_by.insert(1, vec![0]);
called_by.insert(2, vec![1]);
let metrics = compute_graph_metrics(3, &calls, &called_by);
assert_eq!(metrics.len(), 3);
assert!(
metrics[2].pagerank > metrics[0].pagerank,
"end of chain should have higher pagerank: {} vs {}",
metrics[2].pagerank,
metrics[0].pagerank
);
assert_eq!(metrics[0].out_degree, 1);
assert_eq!(metrics[0].in_degree, 0);
assert_eq!(metrics[1].in_degree, 1);
assert_eq!(metrics[1].out_degree, 1);
assert_eq!(metrics[2].in_degree, 1);
assert_eq!(metrics[2].out_degree, 0);
}