#![cfg(feature = "geometric-backend")]
#[cfg(feature = "geometric-backend")]
mod tests {
use magellan::graph::geo_index::{scan_directory_with_progress, IndexingMode};
use magellan::graph::geometric_backend::GeometricBackend;
use std::path::Path;
use std::thread;
use std::time::Duration;
fn create_test_project(dir: &Path) -> std::io::Result<()> {
std::fs::create_dir_all(dir.join("src"))?;
std::fs::create_dir_all(dir.join("src/utils"))?;
std::fs::write(
dir.join("src/lib.rs"),
r#"pub mod utils;
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn process_data(input: &str) -> String {
format!("Processed: {}", input)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}
"#,
)?;
std::fs::write(
dir.join("src/utils/mod.rs"),
r#"pub fn helper(x: i32) -> i32 {
x * 2
}
pub struct DataProcessor {
value: i32,
}
impl DataProcessor {
pub fn new(value: i32) -> Self {
Self { value }
}
pub fn process(&self) -> i32 {
self.value * 3
}
}
"#,
)?;
std::fs::write(
dir.join("src/main.rs"),
r#"fn main() {
println!("Hello from main");
}
"#,
)?;
Ok(())
}
#[test]
fn indexing_completes_and_creates_valid_geo() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
let mut backend = GeometricBackend::create(&db_path).expect("Failed to create backend");
let result = scan_directory_with_progress(
&mut backend,
&src_path,
None, IndexingMode::CfgFirst,
);
assert!(
result.is_ok(),
"Indexing should succeed: {:?}",
result.err()
);
let save_result = backend.save_to_disk();
assert!(save_result.is_ok(), "Save should succeed");
assert!(db_path.exists(), "Database file should be created");
let reopened = GeometricBackend::open(&db_path);
assert!(reopened.is_ok(), "Should be able to reopen database");
let backend = reopened.unwrap();
let stats = backend.get_stats();
assert!(stats.is_ok(), "Should be able to get stats");
}
#[test]
fn repeated_index_same_src_tree_is_idempotent() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
{
let mut backend = GeometricBackend::create(&db_path).expect("Failed to create backend");
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst)
.expect("First index failed");
backend.save_to_disk().expect("First save failed");
}
let stats1 = {
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
backend.get_geometric_stats()
};
{
let mut backend =
GeometricBackend::open(&db_path).expect("Failed to reopen for reindex");
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst)
.expect("Second index failed");
backend.save_to_disk().expect("Second save failed");
}
let stats2 = {
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
backend.get_geometric_stats()
};
assert_eq!(
stats1.symbol_count, stats2.symbol_count,
"Symbol count should be stable after reindex. First: {}, Second: {}",
stats1.symbol_count, stats2.symbol_count
);
assert_eq!(
stats1.file_count, stats2.file_count,
"File count should be stable after reindex. First: {}, Second: {}",
stats1.file_count, stats2.file_count
);
}
#[test]
fn reopen_counts_match_after_save() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
{
let mut backend = GeometricBackend::create(&db_path).expect("Failed to create backend");
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst)
.expect("Index failed");
backend.save_to_disk().expect("Save failed");
}
let stats1 = {
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
backend.get_geometric_stats()
};
thread::sleep(Duration::from_millis(50));
let stats2 = {
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
backend.get_geometric_stats()
};
assert_eq!(
stats1.symbol_count, stats2.symbol_count,
"Symbol count should match after reopen"
);
assert_eq!(
stats1.file_count, stats2.file_count,
"File count should match after reopen"
);
assert_eq!(
stats1.node_count, stats2.node_count,
"Node count should match after reopen"
);
assert_eq!(
stats1.cfg_block_count, stats2.cfg_block_count,
"CFG block count should match after reopen"
);
}
#[test]
fn symbol_resolution_finds_functions() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
{
let mut backend = GeometricBackend::create(&db_path).expect("Failed to create backend");
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst)
.expect("Index failed");
backend.save_to_disk().expect("Save failed");
}
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
let add_results = backend.find_symbols_by_name_info("add");
assert!(!add_results.is_empty(), "Should find 'add' function");
let helper_results = backend.find_symbols_by_name_info("helper");
assert!(!helper_results.is_empty(), "Should find 'helper' function");
let struct_results = backend.find_symbols_by_name_info("DataProcessor");
assert!(
!struct_results.is_empty(),
"Should find 'DataProcessor' struct"
);
let method_results = backend.find_symbols_by_name_info("process");
assert!(!method_results.is_empty(), "Should find 'process' method");
}
#[test]
fn dead_code_analysis_runs_successfully() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
{
let mut backend = GeometricBackend::create(&db_path).expect("Failed to create backend");
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst)
.expect("Index failed");
backend.save_to_disk().expect("Save failed");
}
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
let entry_symbols = backend.find_symbols_by_name_info("main");
let entry_ids: Vec<u64> = entry_symbols.iter().map(|s| s.id).collect();
if !entry_ids.is_empty() {
let _dead_code = backend.dead_code_from_entries(&entry_ids);
}
}
#[test]
fn cfg_first_mode_creates_cfg_data() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
{
let mut backend = GeometricBackend::create(&db_path).expect("Failed to create backend");
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst)
.expect("Index failed");
backend.save_to_disk().expect("Save failed");
}
let backend = GeometricBackend::open(&db_path).expect("Failed to reopen");
let _stats = backend.get_geometric_stats();
}
#[test]
fn different_indexing_modes_work() {
let temp_dir = tempfile::tempdir().unwrap();
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
let db_path_cfg = temp_dir.path().join("test_cfg.geo");
{
let mut backend =
GeometricBackend::create(&db_path_cfg).expect("Failed to create backend");
let result =
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst);
assert!(result.is_ok(), "Indexing with CfgFirst should succeed");
backend.save_to_disk().expect("Save failed");
assert!(db_path_cfg.exists(), "Database should exist for CfgFirst");
}
let db_path_ast = temp_dir.path().join("test_ast.geo");
{
let mut backend =
GeometricBackend::create(&db_path_ast).expect("Failed to create backend");
let result =
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::FullAst);
assert!(result.is_ok(), "Indexing with FullAst should succeed");
backend.save_to_disk().expect("Save failed");
assert!(db_path_ast.exists(), "Database should exist for FullAst");
}
}
#[test]
fn end_to_end_smoke_test() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("test.geo");
let src_path = temp_dir.path().join("src");
create_test_project(temp_dir.path()).unwrap();
{
let mut backend =
GeometricBackend::create(&db_path).expect("Step 1: Failed to create backend");
let result =
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst);
assert!(result.is_ok(), "Step 1: Indexing failed");
let save_result = backend.save_to_disk();
assert!(save_result.is_ok(), "Step 1: Save failed");
}
{
let backend = GeometricBackend::open(&db_path).expect("Step 2: Failed to reopen");
let stats = backend.get_geometric_stats();
assert!(stats.symbol_count > 0, "Step 2: Should have symbols");
assert!(
stats.file_count >= 3,
"Step 2: Should have at least 3 files"
);
let results = backend.find_symbols_by_name_info("process_data");
assert!(!results.is_empty(), "Step 2: Should find 'process_data'");
}
{
let mut backend =
GeometricBackend::open(&db_path).expect("Step 3: Failed to reopen for reindex");
let reindex_result =
scan_directory_with_progress(&mut backend, &src_path, None, IndexingMode::CfgFirst);
assert!(reindex_result.is_ok(), "Step 3: Reindex failed");
backend
.save_to_disk()
.expect("Step 3: Save after reindex failed");
}
{
let backend = GeometricBackend::open(&db_path).expect("Step 4: Failed final reopen");
let stats = backend.get_geometric_stats();
assert!(stats.symbol_count > 0, "Step 4: Should still have symbols");
let files = backend.get_all_file_paths();
assert!(!files.is_empty(), "Step 4: Should have files");
}
}
}