#[test]
#[cfg(feature = "v3-forensics")]
fn test_v3_page_ownership_tracking() {
let temp = TempDir::new().unwrap();
let db_path = temp.path().join("v3_ownership_test.db");
sqlitegraph::backend::native::v3::forensics::reset_page_ownership();
println!("\n=== Testing page ownership tracking with 1K nodes ===\n");
{
let backend = V3Backend::create(&db_path).unwrap();
println!("Inserting 1K nodes...");
for i in 0..1_000 {
backend
.insert_node(NodeSpec {
kind: "TestNode".to_string(),
name: format!("node_{}", i),
file_path: None,
data: serde_json::json!({"id": i}),
})
.unwrap();
}
println!("Inserting 5K edges...");
for i in 0..5_000 {
let from = (i % 1_000) as i64 + 1;
let to = ((i * 7) % 1_000) as i64 + 1;
if from != to {
backend
.insert_edge(EdgeSpec {
from,
to,
edge_type: "TestEdge".to_string(),
data: serde_json::json!({}),
})
.unwrap();
}
}
println!("Flushing...");
backend.flush().unwrap();
}
println!("\n=== Page Ownership Report ===\n");
sqlitegraph::backend::native::v3::forensics::print_page_ownership_report();
println!("\n=== Page Ownership Map ===\n");
sqlitegraph::backend::native::v3::forensics::print_page_ownership_map();
let has_conflicts = sqlitegraph::backend::native::v3::forensics::has_page_conflicts();
println!("\n=== Result ===");
if has_conflicts {
println!("❌ PAGE OWNERSHIP CONFLICTS DETECTED!");
if let Some(conflict_page) =
sqlitegraph::backend::native::v3::forensics::get_first_conflict_page()
{
println!(" First conflicting page: {}", conflict_page);
}
} else {
println!("✓ No page ownership conflicts detected");
}
println!("\n=== Attempting to reopen ===\n");
match V3Backend::open(&db_path) {
Ok(_) => {
println!("✓ Database reopened successfully");
}
Err(e) => {
println!("❌ Reopen failed: {}", e);
if let Ok(scan_report) =
sqlitegraph::backend::native::v3::forensics::scan_database_pages(&db_path)
{
scan_report.print();
}
}
}
}
#[test]
#[cfg(feature = "v3-forensics")]
fn test_v3_page_type_detection() {
use sqlitegraph::backend::native::v3::forensics::PageType;
println!("\n=== Testing page type detection ===\n");
let mut node_page_bytes = vec![0u8; 4096];
node_page_bytes[0..8].copy_from_slice(&1u64.to_be_bytes());
node_page_bytes[8..16].copy_from_slice(&0u64.to_be_bytes());
node_page_bytes[16..18].copy_from_slice(&10u16.to_be_bytes());
node_page_bytes[18..20].copy_from_slice(&512u16.to_be_bytes());
let detected = PageType::detect_from_bytes(&node_page_bytes);
println!("NodePage detection: {:?}", detected);
assert_eq!(detected, PageType::Node);
let mut btree_bytes = vec![0u8; 4096];
btree_bytes[0..8].copy_from_slice(&2u64.to_be_bytes());
btree_bytes[8] = 1; btree_bytes[9] = 0;
let detected = PageType::detect_from_bytes(&btree_bytes);
println!("B+Tree Leaf detection: {:?}", detected);
assert_eq!(detected, PageType::BTree);
let mut btree_internal = vec![0u8; 4096];
btree_internal[0..8].copy_from_slice(&3u64.to_be_bytes());
btree_internal[8] = 0; btree_internal[9] = 0;
let detected = PageType::detect_from_bytes(&btree_internal);
println!("B+Tree Internal detection: {:?}", detected);
assert_eq!(detected, PageType::BTree);
}