#[cfg(feature = "v2_experimental")]
use sqlitegraph::{
BackendDirection, EdgeSpec, NeighborQuery, NodeSpec, backend::native::GraphFile,
backend::native::v2, config::GraphConfig, open_graph,
};
use tempfile::TempDir;
#[cfg(feature = "v2_experimental")]
#[test]
fn test_graphfile_single_write_read_roundtrip_mmap() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("test.db");
let mut graph_file = GraphFile::create(&db_path).expect("Failed to create graph file");
let test_pattern = b"CLUSTER_HEADER\x01\x00\x00\x00\x0C";
let write_offset = 2048;
graph_file
.write_bytes(write_offset, test_pattern)
.expect("Failed to write bytes");
graph_file.flush().expect("Failed to flush");
let mut read_buffer = vec![0u8; test_pattern.len()];
graph_file
.mmap_read_bytes(write_offset, &mut read_buffer)
.expect("Failed to mmap read");
assert_eq!(
read_buffer, test_pattern,
"Mmap read must match written data exactly"
);
let mut std_read_buffer = vec![0u8; test_pattern.len()];
graph_file
.read_bytes(write_offset, &mut std_read_buffer)
.expect("Failed to standard read");
assert_eq!(
std_read_buffer, test_pattern,
"Standard read must match written data"
);
}
#[cfg(feature = "v2_experimental")]
#[test]
fn test_graphfile_multiple_writes_preserve_all_bytes() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("test.db");
let mut graph_file = GraphFile::create(&db_path).expect("Failed to create graph file");
let pattern1 = b"PATTERN_001_DATA";
let offset1 = 2048;
graph_file
.write_bytes(offset1, pattern1)
.expect("Failed to write pattern 1");
let pattern2 = b"PATTERN_002_DATA";
let offset2 = 3072;
graph_file
.write_bytes(offset2, pattern2)
.expect("Failed to write pattern 2");
graph_file.flush().expect("Failed to flush");
let mut read1 = vec![0u8; pattern1.len()];
graph_file
.mmap_read_bytes(offset1, &mut read1)
.expect("Failed to read pattern 1");
assert_eq!(read1, pattern1, "First pattern should be intact");
let mut read2 = vec![0u8; pattern2.len()];
graph_file
.mmap_read_bytes(offset2, &mut read2)
.expect("Failed to read pattern 2");
assert_eq!(read2, pattern2, "Second pattern should be correct");
}
#[cfg(feature = "v2_experimental")]
#[test]
fn test_graphfile_reopen_preserves_data_mmap() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("test.db");
{
let mut graph_file = GraphFile::create(&db_path).expect("Failed to create graph file");
let test_data = b"PRESERVE_TEST_DATA_AFTER_REOPEN";
let write_offset = 4096;
graph_file
.write_bytes(write_offset, test_data)
.expect("Failed to write data");
graph_file.flush().expect("Failed to flush");
drop(graph_file);
}
{
let mut graph_file = GraphFile::open(&db_path).expect("Failed to reopen graph file");
let test_data = b"PRESERVE_TEST_DATA_AFTER_REOPEN";
let read_offset = 4096;
let mut read_buffer = vec![0u8; test_data.len()];
graph_file
.mmap_read_bytes(read_offset, &mut read_buffer)
.expect("Failed to read after reopen");
assert_eq!(read_buffer, test_data, "Data should persist after reopen");
}
}
#[cfg(feature = "v2_experimental")]
#[test]
fn test_graphfile_v2_cluster_roundtrip_via_edges() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("test.db");
let config = GraphConfig::native();
let mut graph = open_graph(&db_path, &config).expect("Failed to create graph");
let node1_id = graph
.insert_node(NodeSpec {
kind: "Node".to_string(),
name: "node1".to_string(),
file_path: None,
data: serde_json::json!({"id": 1}),
})
.expect("Failed to insert node1");
let node2_id = graph
.insert_node(NodeSpec {
kind: "Node".to_string(),
name: "node2".to_string(),
file_path: None,
data: serde_json::json!({"id": 2}),
})
.expect("Failed to insert node2");
let node3_id = graph
.insert_node(NodeSpec {
kind: "Node".to_string(),
name: "node3".to_string(),
file_path: None,
data: serde_json::json!({"id": 3}),
})
.expect("Failed to insert node3");
let _edge1 = graph
.insert_edge(EdgeSpec {
from: node1_id,
to: node2_id,
edge_type: "connects".to_string(),
data: serde_json::json!({"weight": 1.0}),
})
.expect("Failed to insert edge 1");
let _edge2 = graph
.insert_edge(EdgeSpec {
from: node1_id,
to: node3_id,
edge_type: "connects".to_string(),
data: serde_json::json!({"weight": 2.0}),
})
.expect("Failed to insert edge 2");
let neighbors = graph
.neighbors(
node1_id,
NeighborQuery {
direction: BackendDirection::Outgoing,
edge_type: None,
},
)
.expect("Failed to get neighbors");
assert_eq!(neighbors.len(), 2, "Should have exactly 2 neighbors");
let mut neighbor_set: std::collections::HashSet<_> = neighbors.iter().cloned().collect();
assert!(neighbor_set.contains(&node2_id), "Should contain node2");
assert!(neighbor_set.contains(&node3_id), "Should contain node3");
}
#[cfg(feature = "v2_experimental")]
#[test]
fn test_internal_corruption_detection() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("test.db");
let config = GraphConfig::native();
let mut graph = open_graph(&db_path, &config).expect("Failed to create graph");
let node1_id = graph
.insert_node(NodeSpec {
kind: "Node".to_string(),
name: "node1".to_string(),
file_path: None,
data: serde_json::json!({"id": 1}),
})
.expect("Failed to insert node1");
let node2_id = graph
.insert_node(NodeSpec {
kind: "Node".to_string(),
name: "node2".to_string(),
file_path: None,
data: serde_json::json!({"id": 2}),
})
.expect("Failed to insert node2");
let _edge = graph
.insert_edge(EdgeSpec {
from: node1_id,
to: node2_id,
edge_type: "test".to_string(),
data: serde_json::json!({"weight": 1.0}),
})
.expect("Failed to insert edge");
drop(graph);
let graph_file_result = GraphFile::open(&db_path);
assert!(
graph_file_result.is_ok(),
"GraphFile should reopen without magic number corruption"
);
let graph_file = graph_file_result.unwrap();
let header = graph_file.header();
assert_eq!(
header.magic,
v2::V2_MAGIC,
"Magic number should be preserved"
);
}
#[cfg(feature = "v2_experimental")]
#[test]
fn test_large_write_behavior() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("test.db");
let mut graph_file = GraphFile::create(&db_path).expect("Failed to create graph file");
let large_data = vec![0x42; 5000]; let large_offset = 8192;
graph_file
.write_bytes(large_offset, &large_data)
.expect("Failed to write large data");
graph_file.flush().expect("Failed to flush");
let mut read_buffer = vec![0u8; large_data.len()];
graph_file
.mmap_read_bytes(large_offset, &mut read_buffer)
.expect("Failed to read large data via mmap");
assert_eq!(
read_buffer, large_data,
"Large data should be readable via mmap"
);
let mut std_read_buffer = vec![0u8; large_data.len()];
graph_file
.read_bytes(large_offset, &mut std_read_buffer)
.expect("Failed to read large data via standard read");
assert_eq!(
std_read_buffer, large_data,
"Large data should be readable via standard read"
);
}