use verit::{encode, Dt, Error, Message, Ref, Resolver, SchemaBuilder, SchemaMode, Value};
fn dense_point() -> verit::Schema {
SchemaBuilder::new()
.add_dense_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
.add_struct("Shape", vec![(1, "pts", Dt::list(Dt::named("Point")))])
.build("Shape")
.unwrap()
}
#[test]
fn dense_struct_roundtrips() {
let schema = dense_point();
let bytes = encode(
&schema,
&Value::Struct(vec![(
1,
Value::List(vec![
Value::Struct(vec![(1, Value::F64(1.0)), (2, Value::F64(2.0))]),
Value::Struct(vec![(1, Value::F64(3.0)), (2, Value::F64(4.0))]),
]),
)]),
SchemaMode::HashOnly,
)
.unwrap();
let resolver = Resolver::identity(&schema).unwrap();
let msg = Message::parse(&bytes).unwrap();
let root = msg.root(&resolver).unwrap();
let pts = root.get_list(1).unwrap().unwrap();
match pts.get(1).unwrap() {
Ref::Struct(p) => {
assert_eq!(p.get_f64(1).unwrap(), Some(3.0));
assert_eq!(p.get_f64(2).unwrap(), Some(4.0));
}
other => panic!("expected struct, got {}", other.kind()),
}
}
#[test]
fn dense_struct_is_16_not_24_bytes_per_element() {
let dense = dense_point();
let sparse = SchemaBuilder::new()
.add_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
.add_struct("Shape", vec![(1, "pts", Dt::list(Dt::named("Point")))])
.build("Shape")
.unwrap();
let value = |n: usize| {
Value::Struct(vec![(
1,
Value::List(
(0..n)
.map(|i| {
Value::Struct(vec![
(1, Value::F64(i as f64)),
(2, Value::F64(-(i as f64))),
])
})
.collect(),
),
)])
};
let d = encode(&dense, &value(10), SchemaMode::HashOnly).unwrap();
let s = encode(&sparse, &value(10), SchemaMode::HashOnly).unwrap();
assert_eq!(s.len() - d.len(), 80);
}
#[test]
fn dense_struct_missing_field_fails_loudly() {
let schema = dense_point();
let result = encode(
&schema,
&Value::Struct(vec![(
1,
Value::List(vec![Value::Struct(vec![(1, Value::F64(1.0))])]), )]),
SchemaMode::HashOnly,
);
assert!(matches!(result, Err(Error::MissingField(2))));
}
#[test]
fn dense_and_sparse_schemas_have_different_ids() {
let dense = dense_point();
let sparse = SchemaBuilder::new()
.add_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
.add_struct("Shape", vec![(1, "pts", Dt::list(Dt::named("Point")))])
.build("Shape")
.unwrap();
assert_ne!(dense.id(), sparse.id());
}
#[test]
fn dense_writer_evolves_into_wider_reader() {
let writer = dense_point();
let reader = SchemaBuilder::new()
.add_struct(
"Point",
vec![(1, "x", Dt::F64), (2, "y", Dt::F64), (3, "z", Dt::F64)],
)
.add_struct("Shape", vec![(1, "pts", Dt::list(Dt::named("Point")))])
.build("Shape")
.unwrap();
let bytes = encode(
&writer,
&Value::Struct(vec![(
1,
Value::List(vec![Value::Struct(vec![
(1, Value::F64(7.0)),
(2, Value::F64(8.0)),
])]),
)]),
SchemaMode::HashOnly,
)
.unwrap();
let resolver = Resolver::new(&writer, &reader).unwrap();
let msg = Message::parse(&bytes).unwrap();
let root = msg.root(&resolver).unwrap();
let pts = root.get_list(1).unwrap().unwrap();
match pts.get(0).unwrap() {
Ref::Struct(p) => {
assert_eq!(p.get_f64(1).unwrap(), Some(7.0));
assert_eq!(p.get_f64(2).unwrap(), Some(8.0));
assert_eq!(p.get_f64(3).unwrap(), None);
}
other => panic!("expected struct, got {}", other.kind()),
}
}
#[test]
fn dense_survives_canonical_roundtrip() {
let schema = dense_point();
let recovered = verit::Schema::from_canonical(schema.canonical_bytes()).unwrap();
assert_eq!(recovered.id(), schema.id());
let bytes = encode(
&schema,
&Value::Struct(vec![(
1,
Value::List(vec![Value::Struct(vec![
(1, Value::F64(1.0)),
(2, Value::F64(2.0)),
])]),
)]),
SchemaMode::Inline,
)
.unwrap();
let json = verit::dump_json(&bytes).unwrap();
assert_eq!(json, r#"{"pts":[{"x":1,"y":2}]}"#);
}