use magellan::{CodeGraph, Parser};
use tempfile::TempDir;
#[test]
fn test_extract_reference_to_function() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let source = b"
fn foo() {}
fn bar() {
foo();
}
";
let path = "test.rs";
let symbol_count = graph.index_file(path, source).unwrap();
assert_eq!(symbol_count, 2, "Should index 2 symbols: foo and bar");
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 2);
let foo_symbol = symbols
.iter()
.find(|s| s.name.as_ref().map(|n| n == "foo").unwrap_or(false))
.unwrap();
let mut parser = Parser::new().unwrap();
let normalized_path = std::env::current_dir().unwrap().join(path);
let references = parser.extract_references(normalized_path, source, &symbols);
let foo_refs: Vec<_> = references
.iter()
.filter(|r| r.referenced_symbol == "foo")
.collect();
assert_eq!(foo_refs.len(), 1, "Should find exactly 1 reference to foo");
let foo_ref = &foo_refs[0];
assert_eq!(foo_ref.referenced_symbol, "foo");
assert!(
foo_ref.byte_start >= foo_symbol.byte_end,
"Reference should be after foo's definition"
);
}
#[test]
fn test_exclude_references_within_defining_span() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let source = b"
fn foo() {
foo(); // This should NOT be counted as a reference
}
";
let path = "test.rs";
let symbol_count = graph.index_file(path, source).unwrap();
assert_eq!(symbol_count, 1, "Should index 1 symbol: foo");
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 1);
let mut parser = Parser::new().unwrap();
let normalized_path = std::env::current_dir().unwrap().join(path);
let references = parser.extract_references(normalized_path, source, &symbols);
let foo_refs: Vec<_> = references
.iter()
.filter(|r| r.referenced_symbol == "foo")
.collect();
assert_eq!(
foo_refs.len(),
0,
"Should find zero references to foo (call is within defining span)"
);
}
#[test]
fn test_persist_and_query_references() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let source = b"
fn foo() {}
fn bar() {
foo();
}
";
let path = "test.rs";
graph.index_file(path, source).unwrap();
let reference_count = graph.index_references(path, source).unwrap();
assert_eq!(reference_count, 1, "Should index 1 reference");
assert_eq!(reference_count, 1);
}
#[test]
fn test_scoped_identifier_reference() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let source = b"
mod a {
pub fn foo() {}
}
fn bar() {
a::foo();
}
";
let path = "test.rs";
let symbol_count = graph.index_file(path, source).unwrap();
assert_eq!(
symbol_count, 3,
"Should index 3 symbols from nested modules (mod a, fn foo, fn bar)"
);
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 3);
let foo_symbol = symbols
.iter()
.find(|s| s.name.as_ref().map(|n| n == "foo").unwrap_or(false))
.unwrap();
let mut parser = Parser::new().unwrap();
let normalized_path = std::env::current_dir().unwrap().join(path);
let references = parser.extract_references(normalized_path, source, &symbols);
for ref_fact in &references {
println!(
"Reference: {} at {}-{}",
ref_fact.referenced_symbol, ref_fact.byte_start, ref_fact.byte_end
);
}
let foo_refs: Vec<_> = references
.iter()
.filter(|r| r.referenced_symbol == "foo")
.collect();
assert_eq!(
foo_refs.len(),
1,
"Should find exactly 1 reference to foo via scoped identifier a::foo(), got {}",
foo_refs.len()
);
let foo_ref = &foo_refs[0];
assert_eq!(foo_ref.referenced_symbol, "foo");
assert!(
foo_ref.byte_start >= foo_symbol.byte_end,
"Reference should be after foo's definition"
);
}