use crate::backend::native::v3::{V3Backend, PersistentHeaderV3, V3_HEADER_SIZE, V3_FORMAT_VERSION};
#[test]
fn test_v3_module_exports() {
let _header = PersistentHeaderV3::new_v3();
assert_eq!(V3_HEADER_SIZE, 112);
assert_eq!(V3_FORMAT_VERSION, 4);
}
use crate::backend::sqlite::types::{BackendDirection, EdgeSpec, NeighborQuery, NodeSpec};
use crate::backend::GraphBackend;
use tempfile::TempDir;
#[test]
fn test_v3_entity_ids_basic() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let ids = backend.entity_ids().unwrap();
assert!(ids.is_empty(), "New database should have no entities");
let node1 = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "A".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node2 = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "B".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let ids = backend.entity_ids().unwrap();
assert_eq!(ids.len(), 2, "Should have 2 entities");
assert!(ids.contains(&node1), "Should contain node1");
assert!(ids.contains(&node2), "Should contain node2");
}
#[test]
fn test_v3_outgoing_edges() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let node_a = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "A".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_b = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "B".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_c = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "C".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_a,
to: node_b,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_b,
to: node_c,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
let snapshot = crate::snapshot::SnapshotId::current();
let outgoing_a = backend.neighbors(
snapshot,
node_a,
NeighborQuery { direction: BackendDirection::Outgoing, edge_type: None }
).unwrap();
assert_eq!(outgoing_a.len(), 1, "A should have 1 outgoing edge");
assert!(outgoing_a.contains(&node_b), "A should point to B");
let outgoing_b = backend.neighbors(
snapshot,
node_b,
NeighborQuery { direction: BackendDirection::Outgoing, edge_type: None }
).unwrap();
assert_eq!(outgoing_b.len(), 1, "B should have 1 outgoing edge");
assert!(outgoing_b.contains(&node_c), "B should point to C");
let outgoing_c = backend.neighbors(
snapshot,
node_c,
NeighborQuery { direction: BackendDirection::Outgoing, edge_type: None }
).unwrap();
assert!(outgoing_c.is_empty(), "C should have no outgoing edges");
}
#[test]
fn test_v3_incoming_edges() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let node_a = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "A".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_b = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "B".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_c = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "C".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_d = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "D".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
for target in [node_b, node_c, node_d] {
backend.insert_edge(EdgeSpec {
from: node_a,
to: target,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
}
let snapshot = crate::snapshot::SnapshotId::current();
let incoming_b = backend.neighbors(
snapshot,
node_b,
NeighborQuery { direction: BackendDirection::Incoming, edge_type: None }
).unwrap();
assert_eq!(incoming_b.len(), 1, "B should have 1 incoming edge");
assert!(incoming_b.contains(&node_a), "B should be pointed to by A");
let incoming_c = backend.neighbors(
snapshot,
node_c,
NeighborQuery { direction: BackendDirection::Incoming, edge_type: None }
).unwrap();
assert_eq!(incoming_c.len(), 1, "C should have 1 incoming edge");
assert!(incoming_c.contains(&node_a), "C should be pointed to by A");
let incoming_a = backend.neighbors(
snapshot,
node_a,
NeighborQuery { direction: BackendDirection::Incoming, edge_type: None }
).unwrap();
assert!(incoming_a.is_empty(), "A should have no incoming edges");
}
#[test]
fn test_v3_k_hop_traversal() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let node_a = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "A".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_b = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "B".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_c = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "C".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_d = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "D".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_e = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "E".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_a,
to: node_b,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_a,
to: node_c,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_b,
to: node_d,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_b,
to: node_e,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
let snapshot = crate::snapshot::SnapshotId::current();
let hop1 = backend.k_hop(snapshot, node_a, 1, BackendDirection::Outgoing).unwrap();
assert_eq!(hop1.len(), 2, "A should have 2 nodes within 1 hop");
assert!(hop1.contains(&node_b), "B should be within 1 hop from A");
assert!(hop1.contains(&node_c), "C should be within 1 hop from A");
let hop2 = backend.k_hop(snapshot, node_a, 2, BackendDirection::Outgoing).unwrap();
assert_eq!(hop2.len(), 4, "A should have 4 nodes within 2 hops");
assert!(hop2.contains(&node_b), "B should be within 2 hops from A");
assert!(hop2.contains(&node_c), "C should be within 2 hops from A");
assert!(hop2.contains(&node_d), "D should be within 2 hops from A");
assert!(hop2.contains(&node_e), "E should be within 2 hops from A");
}
#[test]
fn test_v3_node_degree() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let node_a = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "A".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
let node_b = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "B".to_string(),
file_path: None,
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_a,
to: node_b,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
backend.insert_edge(EdgeSpec {
from: node_b,
to: node_a,
edge_type: "links_to".to_string(),
data: serde_json::json!({}),
}).unwrap();
let snapshot = crate::snapshot::SnapshotId::current();
let (out_a, in_a) = backend.node_degree(snapshot, node_a).unwrap();
assert_eq!(out_a, 1, "A should have 1 outgoing edge");
assert_eq!(in_a, 1, "A should have 1 incoming edge");
let (out_b, in_b) = backend.node_degree(snapshot, node_b).unwrap();
assert_eq!(out_b, 1, "B should have 1 outgoing edge");
assert_eq!(in_b, 1, "B should have 1 incoming edge");
}
#[test]
fn test_v3_persistence() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
{
let backend = V3Backend::create(&db_path).unwrap();
let id = backend.insert_node(NodeSpec {
kind: "Test".to_string(),
name: "Persistent".to_string(),
file_path: None,
data: serde_json::json!({"key": "value"}),
}).unwrap();
let snapshot = crate::snapshot::SnapshotId::current();
let node = backend.get_node(snapshot, id).unwrap();
assert_eq!(node.id, id, "Node ID should match");
}
assert!(db_path.exists(), "Database file should exist after create");
let backend = V3Backend::open(&db_path).unwrap();
let header = backend.header();
assert_eq!(header.magic, crate::backend::native::v3::V3_MAGIC, "Header magic should be valid");
assert_eq!(header.version, crate::backend::native::v3::V3_FORMAT_VERSION, "Header version should be valid");
}