Files
wifi-densepose/crates/ruvector-graph/tests/edge_tests.rs
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

372 lines
9.7 KiB
Rust

//! Edge (relationship) operation tests
//!
//! Tests for creating edges, querying relationships, and graph traversals.
use ruvector_graph::{Edge, EdgeBuilder, GraphDB, Label, Node, Properties, PropertyValue};
#[test]
fn test_create_edge_basic() {
let db = GraphDB::new();
// Create nodes first
let node1 = Node::new(
"person1".to_string(),
vec![Label {
name: "Person".to_string(),
}],
Properties::new(),
);
let node2 = Node::new(
"person2".to_string(),
vec![Label {
name: "Person".to_string(),
}],
Properties::new(),
);
db.create_node(node1).unwrap();
db.create_node(node2).unwrap();
// Create edge
let edge = Edge::new(
"edge1".to_string(),
"person1".to_string(),
"person2".to_string(),
"KNOWS".to_string(),
Properties::new(),
);
let edge_id = db.create_edge(edge).unwrap();
assert_eq!(edge_id, "edge1");
}
#[test]
fn test_get_edge_existing() {
let db = GraphDB::new();
// Setup nodes
let node1 = Node::new("n1".to_string(), vec![], Properties::new());
let node2 = Node::new("n2".to_string(), vec![], Properties::new());
db.create_node(node1).unwrap();
db.create_node(node2).unwrap();
// Create edge with properties
let mut properties = Properties::new();
properties.insert("since".to_string(), PropertyValue::Integer(2020));
let edge = Edge::new(
"e1".to_string(),
"n1".to_string(),
"n2".to_string(),
"FRIEND_OF".to_string(),
properties,
);
db.create_edge(edge).unwrap();
let retrieved = db.get_edge("e1").unwrap();
assert_eq!(retrieved.id, "e1");
assert_eq!(retrieved.from, "n1");
assert_eq!(retrieved.to, "n2");
assert_eq!(retrieved.edge_type, "FRIEND_OF");
}
#[test]
fn test_edge_with_properties() {
let db = GraphDB::new();
// Setup
db.create_node(Node::new("a".to_string(), vec![], Properties::new()))
.unwrap();
db.create_node(Node::new("b".to_string(), vec![], Properties::new()))
.unwrap();
let mut properties = Properties::new();
properties.insert("weight".to_string(), PropertyValue::Float(0.85));
properties.insert(
"type".to_string(),
PropertyValue::String("strong".to_string()),
);
properties.insert("verified".to_string(), PropertyValue::Boolean(true));
let edge = Edge::new(
"weighted_edge".to_string(),
"a".to_string(),
"b".to_string(),
"CONNECTED_TO".to_string(),
properties,
);
db.create_edge(edge).unwrap();
let retrieved = db.get_edge("weighted_edge").unwrap();
assert_eq!(
retrieved.properties.get("weight"),
Some(&PropertyValue::Float(0.85))
);
assert_eq!(
retrieved.properties.get("verified"),
Some(&PropertyValue::Boolean(true))
);
}
#[test]
fn test_bidirectional_edges() {
let db = GraphDB::new();
db.create_node(Node::new("alice".to_string(), vec![], Properties::new()))
.unwrap();
db.create_node(Node::new("bob".to_string(), vec![], Properties::new()))
.unwrap();
// Alice -> Bob
let edge1 = Edge::new(
"e1".to_string(),
"alice".to_string(),
"bob".to_string(),
"FOLLOWS".to_string(),
Properties::new(),
);
// Bob -> Alice
let edge2 = Edge::new(
"e2".to_string(),
"bob".to_string(),
"alice".to_string(),
"FOLLOWS".to_string(),
Properties::new(),
);
db.create_edge(edge1).unwrap();
db.create_edge(edge2).unwrap();
let e1 = db.get_edge("e1").unwrap();
let e2 = db.get_edge("e2").unwrap();
assert_eq!(e1.from, "alice");
assert_eq!(e1.to, "bob");
assert_eq!(e2.from, "bob");
assert_eq!(e2.to, "alice");
}
#[test]
fn test_self_loop_edge() {
let db = GraphDB::new();
db.create_node(Node::new("node".to_string(), vec![], Properties::new()))
.unwrap();
let edge = Edge::new(
"self_loop".to_string(),
"node".to_string(),
"node".to_string(),
"REFERENCES".to_string(),
Properties::new(),
);
db.create_edge(edge).unwrap();
let retrieved = db.get_edge("self_loop").unwrap();
assert_eq!(retrieved.from, retrieved.to);
}
#[test]
fn test_multiple_edges_same_nodes() {
let db = GraphDB::new();
db.create_node(Node::new("x".to_string(), vec![], Properties::new()))
.unwrap();
db.create_node(Node::new("y".to_string(), vec![], Properties::new()))
.unwrap();
// Multiple relationship types between same nodes
let edge1 = Edge::new(
"e1".to_string(),
"x".to_string(),
"y".to_string(),
"WORKS_WITH".to_string(),
Properties::new(),
);
let edge2 = Edge::new(
"e2".to_string(),
"x".to_string(),
"y".to_string(),
"FRIENDS_WITH".to_string(),
Properties::new(),
);
db.create_edge(edge1).unwrap();
db.create_edge(edge2).unwrap();
assert!(db.get_edge("e1").is_some());
assert!(db.get_edge("e2").is_some());
}
#[test]
fn test_edge_timestamp_property() {
let db = GraphDB::new();
db.create_node(Node::new("user1".to_string(), vec![], Properties::new()))
.unwrap();
db.create_node(Node::new("post1".to_string(), vec![], Properties::new()))
.unwrap();
let mut properties = Properties::new();
properties.insert("timestamp".to_string(), PropertyValue::Integer(1699564800));
properties.insert(
"action".to_string(),
PropertyValue::String("liked".to_string()),
);
let edge = Edge::new(
"interaction".to_string(),
"user1".to_string(),
"post1".to_string(),
"INTERACTED".to_string(),
properties,
);
db.create_edge(edge).unwrap();
let retrieved = db.get_edge("interaction").unwrap();
assert!(retrieved.properties.contains_key("timestamp"));
}
#[test]
fn test_get_nonexistent_edge() {
let db = GraphDB::new();
let result = db.get_edge("does_not_exist");
assert!(result.is_none());
}
#[test]
fn test_create_many_edges() {
let db = GraphDB::new();
// Create hub node
db.create_node(Node::new("hub".to_string(), vec![], Properties::new()))
.unwrap();
// Create 100 spoke nodes
for i in 0..100 {
let node_id = format!("spoke_{}", i);
db.create_node(Node::new(node_id.clone(), vec![], Properties::new()))
.unwrap();
let edge = Edge::new(
format!("edge_{}", i),
"hub".to_string(),
node_id,
"CONNECTS".to_string(),
Properties::new(),
);
db.create_edge(edge).unwrap();
}
// Verify all edges exist
for i in 0..100 {
assert!(db.get_edge(&format!("edge_{}", i)).is_some());
}
}
#[test]
fn test_edge_builder() {
let db = GraphDB::new();
db.create_node(Node::new("a".to_string(), vec![], Properties::new()))
.unwrap();
db.create_node(Node::new("b".to_string(), vec![], Properties::new()))
.unwrap();
let edge = EdgeBuilder::new("a".to_string(), "b".to_string(), "KNOWS")
.id("e1")
.property("since", 2020i64)
.property("weight", 0.95f64)
.build();
db.create_edge(edge).unwrap();
let retrieved = db.get_edge("e1").unwrap();
assert_eq!(retrieved.from, "a");
assert_eq!(retrieved.to, "b");
assert_eq!(retrieved.edge_type, "KNOWS");
assert_eq!(
retrieved.get_property("since"),
Some(&PropertyValue::Integer(2020))
);
}
// ============================================================================
// Property-based tests
// ============================================================================
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
fn edge_id_strategy() -> impl Strategy<Value = String> {
"[a-z][a-z0-9_]{0,20}".prop_map(|s| s.to_string())
}
fn edge_type_strategy() -> impl Strategy<Value = String> {
"[A-Z_]{2,15}".prop_map(|s| s.to_string())
}
proptest! {
#[test]
fn test_edge_roundtrip(
edge_id in edge_id_strategy(),
edge_type in edge_type_strategy()
) {
let db = GraphDB::new();
// Setup nodes
db.create_node(Node::new("from".to_string(), vec![], Properties::new())).unwrap();
db.create_node(Node::new("to".to_string(), vec![], Properties::new())).unwrap();
let edge = Edge::new(
edge_id.clone(),
"from".to_string(),
"to".to_string(),
edge_type.clone(),
Properties::new(),
);
db.create_edge(edge).unwrap();
let retrieved = db.get_edge(&edge_id).unwrap();
assert_eq!(retrieved.id, edge_id);
assert_eq!(retrieved.edge_type, edge_type);
}
#[test]
fn test_many_edges_unique(
edge_ids in prop::collection::hash_set(edge_id_strategy(), 10..50)
) {
let db = GraphDB::new();
// Create source and target nodes
db.create_node(Node::new("source".to_string(), vec![], Properties::new())).unwrap();
db.create_node(Node::new("target".to_string(), vec![], Properties::new())).unwrap();
for edge_id in &edge_ids {
let edge = Edge::new(
edge_id.clone(),
"source".to_string(),
"target".to_string(),
"TEST".to_string(),
Properties::new(),
);
db.create_edge(edge).unwrap();
}
for edge_id in &edge_ids {
assert!(db.get_edge(edge_id).is_some());
}
}
}
}