use magellan::{delete_file_facts_with_injection, CodeGraph, FailPoint};
use tempfile::TempDir;
fn create_file_with_data(graph: &mut CodeGraph, path: &str) -> TestSetup {
let source = br#"
// Test file with multiple symbols
fn test_function() -> i32 {
42
}
struct TestStruct {
field: i32,
}
enum TestEnum {
VariantA,
VariantB,
}
impl TestStruct {
fn method(&self) -> i32 {
self.field
}
}
"#;
let symbol_count = graph.index_file(path, source).unwrap();
assert!(symbol_count > 0, "Should have created symbols");
let reference_count = graph.index_references(path, source).unwrap();
let call_count = graph.index_calls(path, source).unwrap();
let chunks = graph.get_code_chunks(path).unwrap();
let chunk_count = chunks.len();
let symbols = graph.symbols_in_file(path).unwrap();
let global_refs_before = graph.count_references().unwrap();
let global_calls_before = graph.count_calls().unwrap();
TestSetup {
_path: path.to_string(),
symbols_count: symbols.len(),
references_count: reference_count,
calls_count: call_count,
chunks_count: chunk_count,
_global_refs_before: global_refs_before,
_global_calls_before: global_calls_before,
}
}
#[allow(dead_code)] struct TestSetup {
_path: String,
symbols_count: usize,
references_count: usize,
calls_count: usize,
chunks_count: usize,
_global_refs_before: usize,
_global_calls_before: usize,
}
#[test]
fn test_verify_after_symbols_deleted() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_verify_symbols.rs";
let setup = create_file_with_data(&mut graph, path);
let result =
delete_file_facts_with_injection(&mut graph, path, Some(FailPoint::AfterSymbolsDeleted))
.expect("Delete should succeed");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"Should report symbol deletion count"
);
let file_node = graph.get_file_node(path).unwrap();
assert!(
file_node.is_some(),
"File node should still exist (stopped before deletion)"
);
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 0, "Symbols should be deleted (no rollback)");
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(
chunks.len(),
setup.chunks_count,
"Chunks should remain (deleted after file)"
);
let _result2 = delete_file_facts_with_injection(&mut graph, path, None)
.expect("Complete delete should succeed");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 0, "Symbols should be deleted");
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(chunks.len(), 0, "Chunks should be deleted");
}
#[test]
fn test_verify_after_references_deleted() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_verify_references.rs";
let setup = create_file_with_data(&mut graph, path);
let result =
delete_file_facts_with_injection(&mut graph, path, Some(FailPoint::AfterReferencesDeleted))
.expect("Delete should succeed");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"Should report symbol deletion count"
);
assert_eq!(
result.references_deleted, setup.references_count,
"Should report reference deletion count"
);
assert_eq!(result.chunks_deleted, 0, "Chunks not deleted yet");
let file_node = graph.get_file_node(path).unwrap();
assert!(
file_node.is_none(),
"File node should be deleted (deleted before references)"
);
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(
chunks.len(),
setup.chunks_count,
"Chunks should remain (deleted after file)"
);
let _result2 = delete_file_facts_with_injection(&mut graph, path, None)
.expect("Complete delete should succeed");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
}
#[test]
fn test_verify_after_calls_deleted() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_verify_calls.rs";
let setup = create_file_with_data(&mut graph, path);
let result =
delete_file_facts_with_injection(&mut graph, path, Some(FailPoint::AfterCallsDeleted))
.expect("Delete should succeed");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"Should report symbol deletion count"
);
assert_eq!(
result.references_deleted, setup.references_count,
"Should report reference deletion count"
);
assert_eq!(
result.calls_deleted, setup.calls_count,
"Should report call deletion count"
);
assert_eq!(result.chunks_deleted, 0, "Chunks not deleted yet");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(
chunks.len(),
setup.chunks_count,
"Chunks should remain (deleted after file)"
);
let _result2 = delete_file_facts_with_injection(&mut graph, path, None)
.expect("Complete delete should succeed");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
}
#[test]
fn test_verify_after_chunks_deleted() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_verify_chunks.rs";
let setup = create_file_with_data(&mut graph, path);
let result =
delete_file_facts_with_injection(&mut graph, path, Some(FailPoint::AfterChunksDeleted))
.expect("Delete should succeed");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"Should delete all symbols"
);
assert_eq!(
result.chunks_deleted, setup.chunks_count,
"Should delete all chunks"
);
assert_eq!(
result.references_deleted, setup.references_count,
"Should delete all references"
);
assert_eq!(
result.calls_deleted, setup.calls_count,
"Should delete all calls"
);
let file_node = graph.get_file_node(path).unwrap();
assert!(
file_node.is_none(),
"File node should be deleted after commit"
);
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 0, "Symbols should be deleted");
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(chunks.len(), 0, "Chunks should be deleted");
}
#[test]
fn test_verify_before_file_deleted() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_verify_before_file.rs";
let setup = create_file_with_data(&mut graph, path);
let result =
delete_file_facts_with_injection(&mut graph, path, Some(FailPoint::BeforeFileDeleted))
.expect("Delete should succeed");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"Should report symbol deletion count"
);
assert_eq!(
result.references_deleted, setup.references_count,
"Should report reference deletion count"
);
assert_eq!(
result.calls_deleted, setup.calls_count,
"Should report call deletion count"
);
assert_eq!(result.chunks_deleted, 0, "Chunks not deleted yet");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(
chunks.len(),
setup.chunks_count,
"Chunks should remain (deleted at end)"
);
let _result2 = delete_file_facts_with_injection(&mut graph, path, None)
.expect("Complete delete should succeed");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
}
#[test]
fn test_successful_delete_with_injection() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_successful_delete.rs";
let setup = create_file_with_data(&mut graph, path);
let result =
delete_file_facts_with_injection(&mut graph, path, None).expect("Delete should succeed");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"Should delete all symbols"
);
assert_eq!(
result.chunks_deleted, setup.chunks_count,
"Should delete all chunks"
);
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File node should be deleted");
let symbols = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols.len(), 0, "No symbols should remain");
let chunks = graph.get_code_chunks(path).unwrap();
assert_eq!(chunks.len(), 0, "No chunks should remain");
}
#[test]
fn test_delete_same_file_twice() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_double_delete.rs";
let _setup = create_file_with_data(&mut graph, path);
let result1 = delete_file_facts_with_injection(&mut graph, path, None)
.expect("First delete should succeed");
assert!(
result1.symbols_deleted > 0,
"First delete should remove symbols"
);
let result2 = delete_file_facts_with_injection(&mut graph, path, None)
.expect("Second delete should succeed");
assert_eq!(
result2.symbols_deleted, 0,
"Second delete should find no symbols"
);
let file_node = graph.get_file_node(path).unwrap();
assert!(
file_node.is_none(),
"File should not exist after double delete"
);
}
#[test]
fn test_delete_with_in_memory_index() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_in_memory_index.rs";
let _setup = create_file_with_data(&mut graph, path);
let file_node_before = graph.get_file_node(path).unwrap();
assert!(
file_node_before.is_some(),
"File should be in index before delete"
);
let _result =
delete_file_facts_with_injection(&mut graph, path, None).expect("Delete should succeed");
let file_node_after = graph.get_file_node(path).unwrap();
assert!(
file_node_after.is_none(),
"File should not be in index after delete"
);
}
#[test]
fn test_delete_one_file_doesnt_affect_another() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path1 = "test_file1.rs";
let path2 = "test_file2.rs";
let _setup1 = create_file_with_data(&mut graph, path1);
let setup2 = create_file_with_data(&mut graph, path2);
let _result =
delete_file_facts_with_injection(&mut graph, path1, None).expect("Delete should succeed");
let file_node1 = graph.get_file_node(path1).unwrap();
assert!(file_node1.is_none(), "File1 should be deleted");
let symbols2 = graph.symbols_in_file(path2).unwrap();
assert_eq!(
symbols2.len(),
setup2.symbols_count,
"File2 should have all its symbols"
);
let chunks2 = graph.get_code_chunks(path2).unwrap();
assert_eq!(
chunks2.len(),
setup2.chunks_count,
"File2 should have all its chunks"
);
}
#[test]
fn test_delete_removes_code_chunks() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_chunks.rs";
let setup = create_file_with_data(&mut graph, path);
let chunks_before = graph.get_code_chunks(path).unwrap().len();
assert_eq!(chunks_before, setup.chunks_count);
let result =
delete_file_facts_with_injection(&mut graph, path, None).expect("Delete should succeed");
let chunks_after = graph.get_code_chunks(path).unwrap();
assert_eq!(chunks_after.len(), 0, "Code chunks should be deleted");
assert_eq!(
result.chunks_deleted, setup.chunks_count,
"Should delete all chunks"
);
}
#[test]
fn test_delete_removes_all_symbols() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.db");
let mut graph = CodeGraph::open(&db_path).unwrap();
let path = "test_symbols.rs";
let setup = create_file_with_data(&mut graph, path);
let initial_symbols = graph.symbols_in_file(path).unwrap().len();
assert!(initial_symbols > 0);
let result =
delete_file_facts_with_injection(&mut graph, path, None).expect("Delete should succeed");
let file_node = graph.get_file_node(path).unwrap();
assert!(file_node.is_none(), "File should not exist");
let symbols_after = graph.symbols_in_file(path).unwrap();
assert_eq!(symbols_after.len(), 0, "Symbols should be deleted");
assert_eq!(
result.symbols_deleted, setup.symbols_count,
"All original symbols should be deleted"
);
}
#[test]
fn test_failpoint_enum_coverage() {
let all_variants = vec![
FailPoint::AfterSymbolsDeleted,
FailPoint::AfterReferencesDeleted,
FailPoint::AfterCallsDeleted,
FailPoint::AfterChunksDeleted,
FailPoint::BeforeFileDeleted,
];
assert_eq!(all_variants.len(), 5, "Should have 5 fail point variants");
for variant in all_variants {
match variant {
FailPoint::AfterSymbolsDeleted => {}
FailPoint::AfterReferencesDeleted => {}
FailPoint::AfterCallsDeleted => {}
FailPoint::AfterChunksDeleted => {}
FailPoint::BeforeFileDeleted => {}
}
}
}