use grafeo_common::types::Value;
use grafeo_engine::GrafeoDB;
#[test]
fn test_create_edge_with_props() {
let db = GrafeoDB::new_in_memory();
let alix = db.create_node(&["Person"]);
let gus = db.create_node(&["Person"]);
let eid = db.create_edge_with_props(
alix,
gus,
"KNOWS",
[
("since", Value::Int64(2020)),
("weight", Value::Float64(0.9)),
],
);
let edge = db.get_edge(eid).expect("edge should exist");
assert_eq!(edge.edge_type.as_str(), "KNOWS");
assert_eq!(edge.src, alix);
assert_eq!(edge.dst, gus);
}
#[test]
fn test_get_edge_returns_none_for_invalid_id() {
let db = GrafeoDB::new_in_memory();
assert!(
db.get_edge(grafeo_common::types::EdgeId::new(999))
.is_none()
);
}
#[test]
fn test_set_and_remove_edge_property() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["N"]);
let b = db.create_node(&["N"]);
let eid = db.create_edge(a, b, "R");
db.set_edge_property(eid, "weight", Value::Float64(1.5));
let edge = db.get_edge(eid).unwrap();
assert_eq!(
edge.properties
.get(&grafeo_common::types::PropertyKey::new("weight")),
Some(&Value::Float64(1.5))
);
assert!(db.remove_edge_property(eid, "weight"));
let edge = db.get_edge(eid).unwrap();
assert!(
!edge
.properties
.contains_key(&grafeo_common::types::PropertyKey::new("weight"))
);
assert!(!db.remove_edge_property(eid, "weight"));
}
#[test]
fn test_delete_edge() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["N"]);
let b = db.create_node(&["N"]);
let eid = db.create_edge(a, b, "R");
assert_eq!(db.edge_count(), 1);
assert!(db.delete_edge(eid));
assert_eq!(db.edge_count(), 0);
assert!(!db.delete_edge(eid)); }
#[test]
fn test_add_and_remove_node_label() {
let db = GrafeoDB::new_in_memory();
let n = db.create_node(&["Person"]);
assert!(db.add_node_label(n, "Employee"));
let labels = db.get_node_labels(n).unwrap();
assert!(labels.contains(&"Person".to_string()));
assert!(labels.contains(&"Employee".to_string()));
assert!(!db.add_node_label(n, "Employee"));
assert!(db.remove_node_label(n, "Employee"));
let labels = db.get_node_labels(n).unwrap();
assert!(!labels.contains(&"Employee".to_string()));
assert!(labels.contains(&"Person".to_string()));
assert!(!db.remove_node_label(n, "Employee"));
}
#[test]
fn test_get_node_labels_returns_none_for_invalid_id() {
let db = GrafeoDB::new_in_memory();
assert!(
db.get_node_labels(grafeo_common::types::NodeId::new(999))
.is_none()
);
}
#[test]
fn test_remove_node_property() {
let db = GrafeoDB::new_in_memory();
let n = db.create_node(&["Person"]);
db.set_node_property(n, "name", Value::String("Alix".into()));
assert!(db.remove_node_property(n, "name"));
let node = db.get_node(n).unwrap();
assert!(
!node
.properties
.contains_key(&grafeo_common::types::PropertyKey::new("name"))
);
assert!(!db.remove_node_property(n, "name"));
}
#[test]
fn test_property_index_lifecycle() {
let db = GrafeoDB::new_in_memory();
assert!(!db.has_property_index("name"));
db.create_property_index("name");
assert!(db.has_property_index("name"));
let n1 = db.create_node(&["Person"]);
db.set_node_property(n1, "name", Value::String("Alix".into()));
let n2 = db.create_node(&["Person"]);
db.set_node_property(n2, "name", Value::String("Gus".into()));
let n3 = db.create_node(&["Person"]);
db.set_node_property(n3, "name", Value::String("Alix".into()));
let results = db.find_nodes_by_property("name", &Value::String("Alix".into()));
assert_eq!(results.len(), 2);
assert!(results.contains(&n1));
assert!(results.contains(&n3));
let results = db.find_nodes_by_property("name", &Value::String("Gus".into()));
assert_eq!(results.len(), 1);
assert!(results.contains(&n2));
let results = db.find_nodes_by_property("name", &Value::String("Harm".into()));
assert!(results.is_empty());
assert!(db.drop_property_index("name"));
assert!(!db.has_property_index("name"));
assert!(!db.drop_property_index("name")); }
#[test]
fn test_iter_nodes() {
let db = GrafeoDB::new_in_memory();
let _n1 = db.create_node(&["Person"]);
let _n2 = db.create_node(&["Company"]);
let _n3 = db.create_node(&["Person"]);
let nodes: Vec<_> = db.iter_nodes().collect();
assert_eq!(nodes.len(), 3);
}
#[test]
fn test_iter_edges() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["N"]);
let b = db.create_node(&["N"]);
let c = db.create_node(&["N"]);
let _e1 = db.create_edge(a, b, "R");
let _e2 = db.create_edge(b, c, "S");
let edges: Vec<_> = db.iter_edges().collect();
assert_eq!(edges.len(), 2);
}
#[test]
fn test_iter_empty_database() {
let db = GrafeoDB::new_in_memory();
assert_eq!(db.iter_nodes().count(), 0);
assert_eq!(db.iter_edges().count(), 0);
}
#[test]
fn test_validate_healthy_database() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["Person"]);
let b = db.create_node(&["Person"]);
db.create_edge(a, b, "KNOWS");
let result = db.validate();
assert!(result.is_valid(), "healthy database should validate");
}
#[test]
fn test_validate_empty_database() {
let db = GrafeoDB::new_in_memory();
let result = db.validate();
assert!(result.is_valid());
}
#[test]
fn test_info() {
let db = GrafeoDB::new_in_memory();
let _n = db.create_node(&["Person"]);
db.set_node_property(_n, "name", Value::String("Alix".into()));
let info = db.info();
assert_eq!(info.node_count, 1);
assert_eq!(info.edge_count, 0);
assert!(!info.is_persistent);
assert!(info.path.is_none());
}
#[test]
fn test_detailed_stats() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["Person"]);
db.set_node_property(a, "name", Value::String("Alix".into()));
let b = db.create_node(&["Company"]);
db.set_node_property(b, "name", Value::String("Acme".into()));
db.create_edge(a, b, "WORKS_AT");
let stats = db.detailed_stats();
assert_eq!(stats.node_count, 2);
assert_eq!(stats.edge_count, 1);
assert_eq!(stats.label_count, 2); assert_eq!(stats.edge_type_count, 1); assert!(stats.property_key_count >= 1); assert!(stats.disk_bytes.is_none()); }
#[test]
fn test_graph_model_default() {
let db = GrafeoDB::new_in_memory();
let model = db.graph_model();
assert_eq!(
format!("{model}"),
"LPG",
"default graph model should be LPG"
);
}
#[test]
fn test_to_memory_clones_data() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["Person"]);
db.set_node_property(a, "name", Value::String("Alix".into()));
let b = db.create_node(&["Person"]);
db.set_node_property(b, "name", Value::String("Gus".into()));
db.create_edge(a, b, "KNOWS");
let clone = db.to_memory().expect("to_memory should succeed");
assert_eq!(clone.node_count(), 2);
assert_eq!(clone.edge_count(), 1);
clone.create_node(&["Extra"]);
assert_eq!(db.node_count(), 2); assert_eq!(clone.node_count(), 3);
}
#[test]
fn test_snapshot_export_import_roundtrip() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["Person"]);
db.set_node_property(a, "name", Value::String("Alix".into()));
db.set_node_property(a, "age", Value::Int64(30));
let b = db.create_node(&["Person"]);
db.set_node_property(b, "name", Value::String("Gus".into()));
db.create_edge(a, b, "KNOWS");
let snapshot = db.export_snapshot().expect("export should succeed");
assert!(!snapshot.is_empty(), "snapshot should not be empty");
let restored = GrafeoDB::import_snapshot(&snapshot).expect("import should succeed");
assert_eq!(restored.node_count(), 2);
assert_eq!(restored.edge_count(), 1);
let session = restored.session();
let result = session
.execute("MATCH (n:Person {name: 'Alix'}) RETURN n.age")
.unwrap();
assert_eq!(result.rows().len(), 1);
assert_eq!(result.rows()[0][0], Value::Int64(30));
}
#[test]
fn test_snapshot_import_invalid_data() {
let result = GrafeoDB::import_snapshot(b"not a valid snapshot");
assert!(result.is_err(), "invalid snapshot data should return error");
}
#[test]
fn test_schema_returns_labels_and_edge_types() {
use grafeo_engine::SchemaInfo;
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["Person"]);
db.set_node_property(a, "name", Value::String("Alix".into()));
db.set_node_property(a, "age", Value::Int64(30));
let b = db.create_node(&["Company"]);
db.set_node_property(b, "name", Value::String("Acme".into()));
db.create_edge(a, b, "WORKS_AT");
db.create_edge(a, b, "LIKES");
let schema = db.schema();
match schema {
SchemaInfo::Lpg(lpg) => {
assert!(
lpg.labels.len() >= 2,
"schema should have at least 2 labels, got {:?}",
lpg.labels
);
assert!(
lpg.edge_types.len() >= 2,
"schema should have at least 2 edge types, got {:?}",
lpg.edge_types
);
}
_ => panic!("expected LPG schema for in-memory database"),
}
}
#[test]
fn test_label_and_type_counts() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["Person"]);
let b = db.create_node(&["Company"]);
db.create_edge(a, b, "WORKS_AT");
assert!(db.label_count() >= 2);
assert!(db.edge_type_count() >= 1);
assert_eq!(db.node_count(), 2);
assert_eq!(db.edge_count(), 1);
}
#[test]
fn test_is_persistent_in_memory() {
let db = GrafeoDB::new_in_memory();
assert!(!db.is_persistent(), "in-memory db should not be persistent");
}
#[test]
fn test_wal_status_in_memory() {
let db = GrafeoDB::new_in_memory();
let status = db.wal_status();
assert!(!status.enabled);
}
#[test]
fn test_close_in_memory_database() {
let db = GrafeoDB::new_in_memory();
let a = db.create_node(&["N"]);
db.set_node_property(a, "x", Value::Int64(1));
db.close().expect("close should succeed for in-memory db");
}
#[test]
fn test_execute_with_params() {
let db = GrafeoDB::new_in_memory();
let session = db.session();
session
.create_node_with_props(
&["Person"],
[
("name", Value::String("Alix".into())),
("age", Value::Int64(30)),
],
)
.unwrap();
session
.create_node_with_props(
&["Person"],
[
("name", Value::String("Gus".into())),
("age", Value::Int64(25)),
],
)
.unwrap();
let params =
std::collections::HashMap::from([("name".to_string(), Value::String("Alix".into()))]);
let result = session
.execute_with_params("MATCH (n:Person) WHERE n.name = $name RETURN n.age", params)
.unwrap();
assert_eq!(result.rows().len(), 1);
assert_eq!(result.rows()[0][0], Value::Int64(30));
}
#[test]
fn test_info_updates_after_operations() {
let db = GrafeoDB::new_in_memory();
let info0 = db.info();
assert_eq!(info0.node_count, 0);
assert_eq!(info0.edge_count, 0);
let a = db.create_node(&["Person"]);
let b = db.create_node(&["Company"]);
db.create_edge(a, b, "WORKS_AT");
let info1 = db.info();
assert_eq!(info1.node_count, 2);
assert_eq!(info1.edge_count, 1);
}
#[test]
fn test_complex_graph_with_multiple_edge_types() {
let db = GrafeoDB::new_in_memory();
let alix = db.create_node(&["Person"]);
db.set_node_property(alix, "name", Value::String("Alix".into()));
let gus = db.create_node(&["Person"]);
db.set_node_property(gus, "name", Value::String("Gus".into()));
let acme = db.create_node(&["Company"]);
db.set_node_property(acme, "name", Value::String("Acme".into()));
db.create_edge(alix, gus, "KNOWS");
db.create_edge(alix, acme, "WORKS_AT");
db.create_edge(gus, acme, "WORKS_AT");
assert_eq!(db.node_count(), 3);
assert_eq!(db.edge_count(), 3);
let result = db.validate();
assert!(result.is_valid());
let stats = db.detailed_stats();
assert_eq!(stats.label_count, 2);
assert_eq!(stats.edge_type_count, 2);
}