use smallvec::smallvec;
use super::*;
use crate::{ExtensionTypeId, Value};
fn dbs(name: &str) -> DbString {
crate::db_string(name).unwrap()
}
#[test]
fn graph_type_id_rejects_zero() {
assert!(matches!(
GraphTypeId::new(0),
Err(CoreError::ZeroIdentifier)
));
assert_eq!(GraphTypeId::new(1).unwrap().get(), 1);
}
#[test]
fn node_type_def_constructed_with_labels() {
let label = dbs("schema.node");
let def = NodeTypeDef::new(LabelSet::single(label.clone()));
assert!(def.labels.contains(&label));
assert!(def.properties.is_empty());
assert!(def.key.is_none());
}
#[test]
fn edge_type_def_constructed_with_endpoints() {
let edge = dbs("schema.edge");
let source = NodeTypeRef(dbs("schema.source"));
let target = NodeTypeRef(dbs("schema.target"));
let def = EdgeTypeDef::new(edge.clone(), source.clone(), target.clone());
assert_eq!(def.label, edge);
assert_eq!(def.source_node_type, EdgeEndpointDef::NodeType(source));
assert_eq!(def.target_node_type, EdgeEndpointDef::NodeType(target));
}
#[test]
fn property_def_with_default_carries_value() {
let property = PropertyDef {
name: dbs("schema.prop"),
value_type: ValueType::predefined(PredefinedValueType::Int),
nullable: false,
default: Some(Value::Int(7)),
immutable: false,
unique: false,
record_fields: None,
};
assert_eq!(property.default, Some(Value::Int(7)));
}
#[test]
fn value_type_predefined_string() {
let value_type = ValueType::predefined(PredefinedValueType::String);
assert_eq!(value_type.predefined, Some(PredefinedValueType::String));
assert!(value_type.list_of.is_none());
}
#[test]
fn value_type_list_of_int() {
let value_type = ValueType::list_of(ValueType::predefined(PredefinedValueType::Int));
let item = value_type.list_of.as_ref().unwrap();
assert_eq!(item.predefined, Some(PredefinedValueType::Int));
}
#[test]
fn predefined_value_type_extended_carries_type_id() {
let predefined = PredefinedValueType::Extended(ExtensionTypeId(0x100));
assert_eq!(
predefined,
PredefinedValueType::Extended(ExtensionTypeId(0x100))
);
}
#[test]
fn key_label_set_policy_default_is_containment() {
assert_eq!(KeyLabelSetPolicy::default(), KeyLabelSetPolicy::Containment);
}
#[test]
fn record_type_def_with_multiple_fields() {
let field_a = PropertyDef {
name: dbs("schema.field.a"),
value_type: ValueType::predefined(PredefinedValueType::String),
nullable: false,
default: None,
immutable: false,
unique: false,
record_fields: None,
};
let field_b = PropertyDef {
name: dbs("schema.field.b"),
value_type: ValueType::predefined(PredefinedValueType::Bool),
nullable: true,
default: Some(Value::Bool(false)),
immutable: false,
unique: false,
record_fields: None,
};
let def = RecordTypeDef {
id: RecordTypeId::new(1),
name: dbs("schema.record"),
fields: smallvec![field_a, field_b],
};
assert_eq!(def.fields.len(), 2);
}
#[test]
fn graph_type_starts_with_empty_type_maps() {
let graph_type = GraphType::new(GraphTypeId::new(1).unwrap(), dbs("schema.graph"));
assert!(graph_type.node_types.is_empty());
assert!(graph_type.edge_types.is_empty());
assert!(graph_type.record_types.is_empty());
}
#[test]
fn property_def_with_no_default_is_valid() {
let property = PropertyDef {
name: dbs("schema.no.default"),
value_type: ValueType::predefined(PredefinedValueType::Bytes),
nullable: true,
default: None,
immutable: false,
unique: false,
record_fields: None,
};
assert!(property.default.is_none());
}
#[test]
fn value_type_list_of_takes_precedence_when_multiple_fields_set() {
let mut value_type = ValueType::list_of(ValueType::predefined(PredefinedValueType::Int));
value_type.predefined = Some(PredefinedValueType::String);
assert!(value_type.list_of.is_some());
assert_eq!(value_type.predefined, Some(PredefinedValueType::String));
}
#[test]
fn graph_type_id_deserialize_round_trips_non_zero() {
let id = GraphTypeId::new(7).unwrap();
let bytes = postcard::to_allocvec(&id).unwrap();
let round: GraphTypeId = postcard::from_bytes(&bytes).unwrap();
assert_eq!(round, id);
}
#[test]
fn graph_type_id_deserialize_rejects_zero() {
let bytes = postcard::to_allocvec::<u64>(&0_u64).unwrap();
let result: Result<GraphTypeId, _> = postcard::from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn wal_one_of_canonicalizes_singleton_to_node_type() {
let source = NodeTypeRef(dbs("schema.solo"));
assert_eq!(
EdgeEndpointDef::one_of([source.clone()]),
EdgeEndpointDef::NodeType(source)
);
}
#[test]
fn wal_one_of_dedupes() {
let a = NodeTypeRef(dbs("schema.aaa"));
let b = NodeTypeRef(dbs("schema.bbb"));
let endpoint = EdgeEndpointDef::one_of([a.clone(), b, a]);
match endpoint {
EdgeEndpointDef::OneOf(refs) => assert_eq!(refs.len(), 2),
other => panic!("expected OneOf, got {other:?}"),
}
}
#[test]
fn postcard_round_trips_oneof_endpoint() {
let two = EdgeEndpointDef::one_of([
NodeTypeRef(dbs("schema.alpha")),
NodeTypeRef(dbs("schema.beta")),
]);
let bytes = postcard::to_allocvec(&two).unwrap();
let decoded: EdgeEndpointDef = postcard::from_bytes(&bytes).unwrap();
assert_eq!(decoded, two);
let five = EdgeEndpointDef::one_of([
NodeTypeRef(dbs("schema.a")),
NodeTypeRef(dbs("schema.b")),
NodeTypeRef(dbs("schema.c")),
NodeTypeRef(dbs("schema.d")),
NodeTypeRef(dbs("schema.e")),
]);
let bytes = postcard::to_allocvec(&five).unwrap();
let decoded: EdgeEndpointDef = postcard::from_bytes(&bytes).unwrap();
assert_eq!(decoded, five);
assert!(matches!(decoded, EdgeEndpointDef::OneOf(_)));
}
#[test]
fn postcard_round_trips_any_and_node_type_after_oneof_variant_addition() {
let any_bytes = postcard::to_allocvec(&EdgeEndpointDef::Any).unwrap();
let any: EdgeEndpointDef = postcard::from_bytes(&any_bytes).unwrap();
assert_eq!(any, EdgeEndpointDef::Any);
let nt = EdgeEndpointDef::NodeType(NodeTypeRef(dbs("schema.legacy")));
let nt_bytes = postcard::to_allocvec(&nt).unwrap();
let decoded: EdgeEndpointDef = postcard::from_bytes(&nt_bytes).unwrap();
assert_eq!(decoded, nt);
}
#[test]
#[should_panic(expected = "called with empty NodeTypeRef set")]
fn wal_one_of_panics_on_empty_input() {
let _ = EdgeEndpointDef::one_of(std::iter::empty::<NodeTypeRef>());
}