#![cfg(feature = "derive")]
use verit::{encode, Dt, Message, Resolver, SchemaBuilder, SchemaMode, Value, Verit, VeritType};
#[derive(Verit, Debug, PartialEq, Clone)]
#[verit(mode = "dense")]
struct Point {
#[verit(id = 1)]
x: f64,
#[verit(id = 2)]
y: f64,
}
#[derive(Verit, Debug, PartialEq, Clone)]
struct Order {
#[verit(id = 1)]
id: u64,
#[verit(id = 2)]
item: String,
#[verit(id = 3)]
qty: u32,
#[verit(id = 4)]
tags: Vec<String>,
#[verit(id = 5)]
origin: Point,
#[verit(id = 6)]
note: Option<String>,
#[verit(id = 7)]
path: Vec<Point>,
#[verit(id = 8)]
blob: Vec<u8>,
}
fn sample() -> Order {
Order {
id: 42,
item: "widget".into(),
qty: 7,
tags: vec!["a".into(), "bb".into()],
origin: Point { x: 1.5, y: -2.5 },
note: Some("gift".into()),
path: vec![Point { x: 0.0, y: 0.0 }, Point { x: 1.0, y: 1.0 }],
blob: vec![0xde, 0xad, 0xbe, 0xef],
}
}
fn hand_schema() -> verit::Schema {
SchemaBuilder::new()
.add_dense_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
.add_struct(
"Order",
vec![
(1, "id", Dt::U64),
(2, "item", Dt::Str),
(3, "qty", Dt::U32),
(4, "tags", Dt::list(Dt::Str)),
(5, "origin", Dt::named("Point")),
(6, "note", Dt::Str),
(7, "path", Dt::list(Dt::named("Point"))),
(8, "blob", Dt::Bytes),
],
)
.build("Order")
.unwrap()
}
#[test]
fn derived_schema_id_matches_hand_built() {
assert_eq!(
Order::verit_schema_id(),
hand_schema().id(),
"the derive must build the same canonical schema as SchemaBuilder"
);
let point_only = SchemaBuilder::new()
.add_dense_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
.build("Point")
.unwrap();
assert_eq!(Point::verit_schema_id(), point_only.id());
}
#[test]
fn derived_bytes_are_identical_to_the_dynamic_encoder() {
let order = sample();
let derived = order.to_verit(SchemaMode::HashOnly).unwrap();
let value = Value::Struct(vec![
(1, Value::U64(42)),
(2, Value::str("widget")),
(3, Value::U32(7)),
(4, Value::List(vec![Value::str("a"), Value::str("bb")])),
(
5,
Value::Struct(vec![(1, Value::F64(1.5)), (2, Value::F64(-2.5))]),
),
(6, Value::str("gift")),
(
7,
Value::List(vec![
Value::Struct(vec![(1, Value::F64(0.0)), (2, Value::F64(0.0))]),
Value::Struct(vec![(1, Value::F64(1.0)), (2, Value::F64(1.0))]),
]),
),
(8, Value::Bytes(vec![0xde, 0xad, 0xbe, 0xef])),
]);
let dynamic = encode(&hand_schema(), &value, SchemaMode::HashOnly).unwrap();
assert_eq!(
derived, dynamic,
"derived to_verit must be byte-identical to the dynamic encoder"
);
}
#[test]
fn round_trips_through_from_verit() {
let order = sample();
for mode in [SchemaMode::HashOnly, SchemaMode::Inline] {
let bytes = order.to_verit(mode).unwrap();
let back = Order::from_verit(&bytes).unwrap();
assert_eq!(order, back, "round-trip under {mode:?}");
}
}
#[test]
fn absent_option_is_omitted_and_reads_back_none() {
let mut order = sample();
order.note = None;
let bytes = order.to_verit(SchemaMode::HashOnly).unwrap();
let schema = Order::verit_schema();
let resolver = Resolver::identity(schema).unwrap();
let msg = Message::parse(&bytes).unwrap();
let root = msg.root(&resolver).unwrap();
assert_eq!(root.get_str(6).unwrap(), None);
let back = Order::from_verit(&bytes).unwrap();
assert_eq!(back.note, None);
}
#[test]
fn inline_mode_is_self_describing() {
let bytes = sample().to_verit(SchemaMode::Inline).unwrap();
let json = verit::dump_json(&bytes).unwrap();
assert!(json.contains("\"item\":\"widget\""), "dump: {json}");
assert!(
json.contains("\"origin\":{\"x\":1.5,\"y\":-2.5}"),
"dump: {json}"
);
let msg = Message::parse(&bytes).unwrap();
assert_eq!(msg.schema_id(), Order::verit_schema_id());
}
#[test]
fn nested_list_of_structs_round_trips() {
let order = sample();
let back = Order::from_verit(&order.to_verit(SchemaMode::HashOnly).unwrap()).unwrap();
assert_eq!(back.path.len(), 2);
assert_eq!(back.path[1], Point { x: 1.0, y: 1.0 });
assert_eq!(back.blob, vec![0xde, 0xad, 0xbe, 0xef]);
}