use crate::*;
use std::f64::consts::PI;
#[test]
fn test_bool_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.bool(true)?;
enc.bool(false)?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.bool()?, true);
assert_eq!(dec.bool()?, false);
assert_eq!(dec.remaining(), 0);
Ok(())
}
#[test]
fn test_u8_s8_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.u8(0)?;
enc.u8(255)?;
enc.s8(127)?;
enc.s8(-128)?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.u8()?, 0);
assert_eq!(dec.u8()?, 255);
assert_eq!(dec.s8()?, 127);
assert_eq!(dec.s8()?, -128);
Ok(())
}
#[test]
fn test_u16_s16_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.u16(0)?;
enc.u16(u16::MAX)?;
enc.s16(i16::MAX)?;
enc.s16(i16::MIN)?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.u16()?, 0);
assert_eq!(dec.u16()?, u16::MAX);
assert_eq!(dec.s16()?, i16::MAX);
assert_eq!(dec.s16()?, i16::MIN);
Ok(())
}
#[test]
fn test_u32_s32_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.u32(0)?;
enc.u32(u32::MAX)?;
enc.s32(i32::MAX)?;
enc.s32(i32::MIN)?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.u32()?, 0);
assert_eq!(dec.u32()?, u32::MAX);
assert_eq!(dec.s32()?, i32::MAX);
assert_eq!(dec.s32()?, i32::MIN);
Ok(())
}
#[test]
fn test_u64_s64_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.u64(0)?;
enc.u64(u64::MAX)?;
enc.s64(i64::MAX)?;
enc.s64(i64::MIN)?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.u64()?, 0);
assert_eq!(dec.u64()?, u64::MAX);
assert_eq!(dec.s64()?, i64::MAX);
assert_eq!(dec.s64()?, i64::MIN);
Ok(())
}
#[test]
fn test_floats_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.f32(0.0)?;
enc.f32(3.14159)?;
enc.f64(0.0)?;
enc.f64(PI)?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.f32()?, 0.0);
assert_eq!(dec.f32()?, 3.14159);
assert_eq!(dec.f64()?, 0.0);
assert_eq!(dec.f64()?, PI);
Ok(())
}
#[test]
fn test_char_roundtrip() -> Result<()> {
let mut enc = Encoder::new();
enc.char('a')?;
enc.char('🦀')?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.char()?, 'a');
assert_eq!(dec.char()?, '🦀');
Ok(())
}
#[test]
fn test_unit_and_none() -> Result<()> {
let mut enc = Encoder::new();
enc.unit()?;
enc.option_none()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
dec.unit()?;
dec.option_none()?;
assert_eq!(dec.remaining(), 0);
Ok(())
}
#[test]
fn test_strings() -> Result<()> {
let mut enc = Encoder::new();
enc.str("hello")?;
enc.str("")?;
enc.str("❤️")?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.str()?, "hello");
assert_eq!(dec.str()?, "");
assert_eq!(dec.str()?, "❤️");
Ok(())
}
#[test]
fn test_bytes() -> Result<()> {
let mut enc = Encoder::new();
enc.bytes(&[1, 2, 3])?;
enc.bytes(&[])?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
assert_eq!(dec.bytes()?, &[1, 2, 3]);
assert_eq!(dec.bytes()?, &[]);
Ok(())
}
#[test]
fn test_list_simple() -> Result<()> {
let mut enc = Encoder::new();
enc.list_begin()?;
enc.u32(1)?;
enc.u32(2)?;
enc.list_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut list = dec.list()?;
assert_eq!(list.next().unwrap().u32()?, 1);
assert_eq!(list.next().unwrap().u32()?, 2);
assert!(list.next().is_none());
Ok(())
}
#[test]
fn test_list_nested() -> Result<()> {
let mut enc = Encoder::new();
enc.list_begin()?;
enc.list_begin()?;
enc.u32(10)?;
enc.list_end()?;
enc.u32(20)?;
enc.list_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut outer = dec.list()?;
let mut inner = outer.next().unwrap().list()?;
assert_eq!(inner.next().unwrap().u32()?, 10);
assert_eq!(outer.next().unwrap().u32()?, 20);
Ok(())
}
#[test]
fn test_map_logic() -> Result<()> {
let mut enc = Encoder::new();
enc.map_begin()?;
enc.variant_begin("a")?;
enc.u32(1)?;
enc.variant_end()?;
enc.variant_begin("b")?;
enc.str("two")?;
enc.variant_end()?;
enc.map_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut map = dec.map()?;
let (k1, mut v1) = map.next()?.unwrap();
assert_eq!(k1, "a");
assert_eq!(v1.u32()?, 1);
let (k2, mut v2) = map.next()?.unwrap();
assert_eq!(k2, "b");
assert_eq!(v2.str()?, "two");
assert!(map.next()?.is_none());
Ok(())
}
#[test]
fn test_map_empty() -> Result<()> {
let mut enc = Encoder::new();
enc.map_begin()?;
enc.map_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut map = dec.map()?;
assert!(map.next()?.is_none());
Ok(())
}
#[test]
fn test_option_some_workflow() -> Result<()> {
let mut enc = Encoder::new();
enc.option_some_begin()?;
enc.u32(100)?;
enc.option_some_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let opt = dec.option()?;
assert!(opt.is_some());
assert_eq!(opt.unwrap().u32()?, 100);
Ok(())
}
#[test]
fn test_result_ok_workflow() -> Result<()> {
let mut enc = Encoder::new();
enc.result_ok_begin()?;
enc.str("ok")?;
enc.result_ok_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
match dec.result()? {
Ok(mut d) => assert_eq!(d.str()?, "ok"),
Err(_) => panic!("Expected Ok"),
}
Ok(())
}
#[test]
fn test_result_err_workflow() -> Result<()> {
let mut enc = Encoder::new();
enc.result_err_begin()?;
enc.u32(500)?;
enc.result_err_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
match dec.result()? {
Ok(_) => panic!("Expected Err"),
Err(mut d) => assert_eq!(d.u32()?, 500),
}
Ok(())
}
#[test]
fn test_variant_workflow() -> Result<()> {
let mut enc = Encoder::new();
enc.variant_begin("MyEnum")?;
enc.u32(123)?;
enc.variant_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let (name, mut val) = dec.variant()?;
assert_eq!(name, "MyEnum");
assert_eq!(val.u32()?, 123);
Ok(())
}
#[test]
fn test_skip_logic() -> Result<()> {
let mut enc = Encoder::new();
enc.list_begin()?;
enc.u32(1)?;
enc.map_begin()?;
enc.variant_begin("key")?;
enc.u32(99)?;
enc.variant_end()?;
enc.map_end()?;
enc.u32(2)?;
enc.list_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut list = dec.list()?;
assert_eq!(list.next().unwrap().u32()?, 1);
let mut map_decoder = list.next().unwrap();
map_decoder.skip()?;
assert_eq!(list.next().unwrap().u32()?, 2);
Ok(())
}
#[test]
fn test_deeply_nested_mixed() -> Result<()> {
let mut enc = Encoder::new();
enc.list_begin()?;
enc.result_ok_begin()?;
enc.option_some_begin()?;
enc.variant_begin("Deep")?;
enc.u32(42)?;
enc.variant_end()?;
enc.option_some_end()?;
enc.result_ok_end()?;
enc.list_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut list = dec.list()?;
match list.next().unwrap().result()? {
Ok(mut ok_dec) => {
let mut opt_dec = ok_dec.option()?.unwrap();
let (name, mut val) = opt_dec.variant()?;
assert_eq!(name, "Deep");
assert_eq!(val.u32()?, 42);
},
Err(_) => panic!("Expected Ok"),
}
Ok(())
}
#[test]
fn test_strict_result_empty() {
let mut enc = Encoder::new();
enc.result_ok_begin().unwrap();
match enc.result_ok_end() {
Err(Error::EmptyAdt(Scope::Result)) => {},
_ => panic!("Expected EmptyAdt error"),
}
}
#[test]
fn test_strict_result_too_many() {
let mut enc = Encoder::new();
enc.result_ok_begin().unwrap();
enc.u32(1).unwrap();
match enc.u32(2) {
Err(Error::TooManyItems(Scope::Result)) => {},
_ => panic!("Expected TooManyItems error"),
}
}
#[test]
fn test_strict_option_empty() {
let mut enc = Encoder::new();
enc.option_some_begin().unwrap();
match enc.option_some_end() {
Err(Error::EmptyAdt(Scope::Option)) => {},
_ => panic!("Expected EmptyAdt"),
}
}
#[test]
fn test_strict_option_too_many() {
let mut enc = Encoder::new();
enc.option_some_begin().unwrap();
enc.u32(1).unwrap();
match enc.str("no") {
Err(Error::TooManyItems(Scope::Option)) => {},
_ => panic!("Expected TooManyItems"),
}
}
#[test]
fn test_strict_variant_empty() {
let mut enc = Encoder::new();
enc.variant_begin("V").unwrap();
match enc.variant_end() {
Err(Error::EmptyAdt(Scope::Variant)) => {},
_ => panic!("Expected EmptyAdt"),
}
}
#[test]
fn test_strict_variant_too_many() {
let mut enc = Encoder::new();
enc.variant_begin("V").unwrap();
enc.u32(1).unwrap();
match enc.u32(2) {
Err(Error::TooManyItems(Scope::Variant)) => {},
_ => panic!("Expected TooManyItems"),
}
}
#[test]
fn test_strict_map_entry_invalid_scalar() {
let mut enc = Encoder::new();
enc.map_begin().unwrap();
match enc.u32(10) {
Err(Error::InvalidMapEntry) => {},
_ => panic!("Expected InvalidMapEntry"),
}
}
#[test]
fn test_strict_map_entry_invalid_container() {
let mut enc = Encoder::new();
enc.map_begin().unwrap();
match enc.list_begin() {
Err(Error::InvalidMapEntry) => {},
_ => panic!("Expected InvalidMapEntry"),
}
}
#[test]
fn test_scope_mismatch() {
let mut enc = Encoder::new();
enc.list_begin().unwrap();
match enc.map_end() {
Err(Error::ScopeMismatch { expected, actual }) => {
assert_eq!(expected, Scope::Map);
assert_eq!(actual, Scope::List);
},
_ => panic!("Expected ScopeMismatch"),
}
}
#[test]
fn test_scope_underflow() {
let mut enc = Encoder::new();
match enc.list_end() {
Err(Error::ScopeUnderflow) => {},
_ => panic!("Expected ScopeUnderflow"),
}
}
#[test]
fn test_scope_still_open() {
let mut enc = Encoder::new();
enc.list_begin().unwrap();
match enc.into_bytes() {
Err(Error::ScopeStillOpen) => {},
_ => panic!("Expected ScopeStillOpen"),
}
}
#[test]
fn test_fail_truncated_header() {
let data = [0x10, 0x01]; let mut dec = Decoder::new(&data);
match dec.str() {
Err(Error::UnexpectedEnd) => {},
_ => panic!("Expected UnexpectedEnd"),
}
}
#[test]
fn test_fail_truncated_body() {
let mut data = Vec::new();
data.push(0x10); data.extend_from_slice(&100u32.to_le_bytes()); data.push(0x01);
let mut dec = Decoder::new(&data);
match dec.str() {
Err(Error::UnexpectedEnd) => {},
_ => panic!("Expected UnexpectedEnd"),
}
}
#[test]
fn test_fail_invalid_utf8_string() {
let mut enc = Encoder::new();
enc.bytes(&[0xFF, 0xFF]).unwrap();
let mut raw = enc.into_bytes().unwrap();
raw[0] = 0x10;
let mut dec = Decoder::new(&raw);
match dec.str() {
Err(Error::InvalidUtf8) => {},
_ => panic!("Expected InvalidUtf8"),
}
}
#[test]
fn test_fail_invalid_utf8_variant_name() {
let mut packet = Vec::new();
packet.push(0x33);
packet.extend_from_slice(&7u32.to_le_bytes());
packet.push(0x10); packet.extend_from_slice(&1u32.to_le_bytes()); packet.push(0xFF); packet.push(0x0E);
let mut dec = Decoder::new(&packet);
match dec.variant() {
Err(Error::InvalidUtf8) => {},
res => panic!("Expected InvalidUtf8, got {:?}", res),
}
}
#[test]
fn test_fail_invalid_tag() {
let data = [0xFF, 0x00];
let dec = Decoder::new(&data);
match dec.peek_tag() {
Err(Error::InvalidTag(0xFF)) => {},
_ => panic!("Expected InvalidTag"),
}
}
#[test]
fn test_fail_map_non_variant_tag() {
let mut enc = Encoder::new();
enc.list_begin().unwrap();
enc.u32(10).unwrap();
enc.list_end().unwrap();
let mut raw = enc.into_bytes().unwrap();
raw[0] = 0x21;
let mut dec = Decoder::new(&raw);
let mut map = dec.map().unwrap();
match map.next() {
Err(Error::InvalidTag(_)) => {},
res => panic!("Expected InvalidTag error (maps require variants), got {:?}", res),
}
}
#[test]
fn test_trailing_data_in_item_decoder() -> Result<()> {
let mut enc = Encoder::new();
enc.list_begin()?;
enc.u32(10)?;
enc.list_end()?;
let bytes = enc.into_bytes()?;
let mut dec = Decoder::new(&bytes);
let mut list = dec.list()?;
let mut item_dec = list.next().unwrap();
assert_eq!(item_dec.u32()?, 10);
assert!(item_dec.u32().is_err());
Ok(())
}
#[cfg(feature = "derive")]
mod derive_tests {
use super::*;
#[derive(Debug, PartialEq, Pack, Unpack)]
#[cfg_attr(feature = "schema", derive(Schema))]
pub(super) struct Point { pub x: f64, pub y: f64 }
#[test]
fn derive_struct_roundtrip() -> Result<()> {
let p = Point { x: 1.5, y: -3.0 };
let bytes = p.pack_to_vec()?;
let p2 = Point::unpack_from_bytes(&bytes)?;
assert_eq!(p, p2);
Ok(())
}
#[derive(Debug, PartialEq, Pack, Unpack)]
#[cfg_attr(feature = "schema", derive(Schema))]
pub(super) enum Shape {
Empty,
Circle(f64),
Rect { w: f64, h: f64 },
Triangle(f64, f64, f64),
}
#[test]
fn derive_enum_unit() -> Result<()> {
let s = Shape::Empty;
let bytes = s.pack_to_vec()?;
let s2 = Shape::unpack_from_bytes(&bytes)?;
assert_eq!(s, s2);
Ok(())
}
#[test]
fn derive_enum_single_field() -> Result<()> {
let s = Shape::Circle(5.0);
let bytes = s.pack_to_vec()?;
let s2 = Shape::unpack_from_bytes(&bytes)?;
assert_eq!(s, s2);
Ok(())
}
#[test]
fn derive_enum_named_fields() -> Result<()> {
let s = Shape::Rect { w: 3.0, h: 4.0 };
let bytes = s.pack_to_vec()?;
let s2 = Shape::unpack_from_bytes(&bytes)?;
assert_eq!(s, s2);
Ok(())
}
#[test]
fn derive_enum_multi_unnamed() -> Result<()> {
let s = Shape::Triangle(3.0, 4.0, 5.0);
let bytes = s.pack_to_vec()?;
let s2 = Shape::unpack_from_bytes(&bytes)?;
assert_eq!(s, s2);
Ok(())
}
#[test]
fn derive_enum_unknown_variant() {
let mut enc = Encoder::new();
enc.variant_begin("Hexagon").unwrap();
enc.unit().unwrap();
enc.variant_end().unwrap();
let bytes = enc.into_bytes().unwrap();
assert!(Shape::unpack_from_bytes(&bytes).is_err());
}
#[derive(Debug, PartialEq, Pack, Unpack)]
#[cfg_attr(feature = "schema", derive(Schema))]
pub(super) struct Wrapper(pub u32);
#[test]
fn derive_newtype_struct() -> Result<()> {
let w = Wrapper(42);
let bytes = w.pack_to_vec()?;
let w2 = Wrapper::unpack_from_bytes(&bytes)?;
assert_eq!(w, w2);
Ok(())
}
#[derive(Debug, PartialEq, Pack, Unpack)]
#[cfg_attr(feature = "schema", derive(Schema))]
pub(super) struct Nested {
pub label: String,
pub point: Point,
}
#[test]
fn derive_nested_struct() -> Result<()> {
let n = Nested { label: "origin".to_string(), point: Point { x: 0.0, y: 0.0 } };
let bytes = n.pack_to_vec()?;
let n2 = Nested::unpack_from_bytes(&bytes)?;
assert_eq!(n, n2);
Ok(())
}
#[test]
fn test_char_pack_unpack() -> Result<()> {
let chars = ['a', 'Z', '0', '🦀', '\n', '\0'];
for c in chars {
let bytes = c.pack_to_vec()?;
let c2 = char::unpack_from_bytes(&bytes)?;
assert_eq!(c, c2);
}
Ok(())
}
#[test]
fn test_box_pack_unpack() -> Result<()> {
let b: Box<u32> = Box::new(42);
let bytes = b.pack_to_vec()?;
let b2 = Box::<u32>::unpack_from_bytes(&bytes)?;
assert_eq!(b, b2);
Ok(())
}
#[test]
fn test_box_transparent_encoding() -> Result<()> {
let val: u32 = 99;
let boxed: Box<u32> = Box::new(99);
assert_eq!(val.pack_to_vec()?, boxed.pack_to_vec()?);
Ok(())
}
#[test]
fn test_box_string_roundtrip() -> Result<()> {
let b: Box<String> = Box::new("hello".to_string());
let bytes = b.pack_to_vec()?;
let b2 = Box::<String>::unpack_from_bytes(&bytes)?;
assert_eq!(b, b2);
Ok(())
}
#[test]
fn test_box_nested_in_struct() -> Result<()> {
#[derive(Debug, PartialEq, Pack, Unpack)]
struct Tree {
value: u32,
children: Vec<Box<Tree>>,
}
let tree = Tree {
value: 1,
children: vec![
Box::new(Tree { value: 2, children: vec![] }),
Box::new(Tree { value: 3, children: vec![
Box::new(Tree { value: 4, children: vec![] }),
]}),
],
};
let bytes = tree.pack_to_vec()?;
let tree2 = Tree::unpack_from_bytes(&bytes)?;
assert_eq!(tree, tree2);
Ok(())
}
}
#[cfg(feature = "schema")]
mod schema_tests {
use super::derive_tests::*;
use super::*;
#[test]
fn schema_scalar_roundtrip() -> Result<()> {
use crate::SchemaType;
let scalars = [
SchemaType::Bool, SchemaType::U8, SchemaType::U16, SchemaType::U32, SchemaType::U64,
SchemaType::S8, SchemaType::S16, SchemaType::S32, SchemaType::S64,
SchemaType::F32, SchemaType::F64, SchemaType::Char, SchemaType::Unit,
SchemaType::String, SchemaType::Bytes, SchemaType::Any,
];
for s in &scalars {
let bytes = s.pack_to_vec()?;
let s2 = SchemaType::unpack_from_bytes(&bytes)?;
assert_eq!(s, &s2);
}
Ok(())
}
#[test]
fn schema_list_roundtrip() -> Result<()> {
use crate::SchemaType;
let s = SchemaType::List(Box::new(SchemaType::U32));
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_option_roundtrip() -> Result<()> {
use crate::SchemaType;
let s = SchemaType::Option(Box::new(SchemaType::String));
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_result_roundtrip() -> Result<()> {
use crate::SchemaType;
let s = SchemaType::Result {
ok: Box::new(SchemaType::U64),
err: Box::new(SchemaType::String),
};
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_map_roundtrip() -> Result<()> {
use crate::SchemaType;
let s = SchemaType::Map(Box::new(SchemaType::Bytes));
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_struct_roundtrip() -> Result<()> {
use crate::{SchemaType, SchemaField};
let s = SchemaType::Struct(vec![
SchemaField::new("x", SchemaType::F64),
SchemaField::new("y", SchemaType::F64),
]);
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_enum_roundtrip() -> Result<()> {
use crate::{SchemaType, SchemaField};
let s = SchemaType::Enum(vec![
SchemaField::new("Ping", SchemaType::Unit),
SchemaField::new("Data", SchemaType::Bytes),
SchemaField::new("Move", SchemaType::Struct(vec![
SchemaField::new("x", SchemaType::S32),
SchemaField::new("y", SchemaType::S32),
])),
]);
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_nested_recursive() -> Result<()> {
use crate::{SchemaType, SchemaField};
let leaf = SchemaType::Struct(vec![
SchemaField::new("value", SchemaType::U32),
SchemaField::new("children", SchemaType::List(Box::new(SchemaType::Any))),
]);
let s = SchemaType::List(Box::new(SchemaType::Option(Box::new(leaf))));
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn schema_tuple_roundtrip() -> Result<()> {
use crate::SchemaType;
let s = SchemaType::Tuple(vec![SchemaType::U32, SchemaType::String, SchemaType::Bool]);
let bytes = s.pack_to_vec()?;
assert_eq!(SchemaType::unpack_from_bytes(&bytes)?, s);
Ok(())
}
#[test]
fn derive_schema_struct() {
use crate::{Schema, SchemaType, SchemaField};
assert_eq!(Point::schema(), SchemaType::Struct(vec![
SchemaField::new("x", SchemaType::F64),
SchemaField::new("y", SchemaType::F64),
]));
}
#[test]
fn derive_schema_enum() {
use crate::{Schema, SchemaType, SchemaField};
assert_eq!(Shape::schema(), SchemaType::Enum(vec![
SchemaField::new("Empty", SchemaType::Unit),
SchemaField::new("Circle", SchemaType::F64),
SchemaField::new("Rect", SchemaType::Struct(vec![
SchemaField::new("w", SchemaType::F64),
SchemaField::new("h", SchemaType::F64),
])),
SchemaField::new("Triangle", SchemaType::Tuple(vec![
SchemaType::F64, SchemaType::F64, SchemaType::F64,
])),
]));
}
#[test]
fn derive_schema_newtype() {
use crate::{Schema, SchemaType};
assert_eq!(Wrapper::schema(), SchemaType::U32);
}
#[test]
fn derive_schema_nested() {
use crate::{Schema, SchemaType, SchemaField};
assert_eq!(Nested::schema(), SchemaType::Struct(vec![
SchemaField::new("label", SchemaType::String),
SchemaField::new("point", SchemaType::Struct(vec![
SchemaField::new("x", SchemaType::F64),
SchemaField::new("y", SchemaType::F64),
])),
]));
}
#[test]
fn derive_schema_pack_bytes_attr() {
use crate::{Schema, SchemaType, SchemaField};
#[derive(Pack, Unpack, Schema)]
struct Msg {
topic: String,
#[pack(bytes)]
payload: Vec<u8>,
}
assert_eq!(Msg::schema(), SchemaType::Struct(vec![
SchemaField::new("topic", SchemaType::String),
SchemaField::new("payload", SchemaType::Bytes),
]));
}
#[test]
fn derive_schema_is_itself_packable() -> Result<()> {
use crate::{Schema, SchemaType};
let s = Shape::schema();
let bytes = s.pack_to_vec()?;
let s2 = SchemaType::unpack_from_bytes(&bytes)?;
assert_eq!(s, s2);
Ok(())
}
fn roundtrip(schema: &SchemaType, input: &str) -> String {
let bytes = crate::lower(schema, input).unwrap();
crate::raise(schema, &bytes).unwrap()
}
#[test]
fn text_scalars() {
assert_eq!(roundtrip(&SchemaType::Bool, "true"), "true");
assert_eq!(roundtrip(&SchemaType::Bool, "false"), "false");
assert_eq!(roundtrip(&SchemaType::U8, "255"), "255");
assert_eq!(roundtrip(&SchemaType::U32, "42"), "42");
assert_eq!(roundtrip(&SchemaType::S32, "-10"), "-10");
assert_eq!(roundtrip(&SchemaType::S64, "0"), "0");
assert_eq!(roundtrip(&SchemaType::F64, "3.14"), "3.14");
assert_eq!(roundtrip(&SchemaType::F64, "1.0"), "1.0");
assert_eq!(roundtrip(&SchemaType::F64, "0.0"), "0.0");
assert_eq!(roundtrip(&SchemaType::Char, "'a'"), "'a'");
assert_eq!(roundtrip(&SchemaType::Char, "'\\n'"), "'\\n'");
assert_eq!(roundtrip(&SchemaType::Unit, "()"), "()");
}
#[test]
fn text_string() {
assert_eq!(roundtrip(&SchemaType::String, r#""hello""#), r#""hello""#);
assert_eq!(roundtrip(&SchemaType::String, r#""a\nb""#), r#""a\nb""#);
assert_eq!(roundtrip(&SchemaType::String, r#""""#), r#""""#);
}
#[test]
fn text_bytes() {
assert_eq!(roundtrip(&SchemaType::Bytes, "#deadbeef"), "#deadbeef");
assert_eq!(roundtrip(&SchemaType::Bytes, "#"), "#");
assert_eq!(roundtrip(&SchemaType::Bytes, "#00ff"), "#00ff");
}
#[test]
fn text_list() {
let schema = SchemaType::List(Box::new(SchemaType::U32));
assert_eq!(roundtrip(&schema, "[1, 2, 3]"), "[1, 2, 3]");
assert_eq!(roundtrip(&schema, "[]"), "[]");
assert_eq!(roundtrip(&schema, "[42]"), "[42]");
assert_eq!(roundtrip(&schema, "[1, 2,]"), "[1, 2]");
}
#[test]
fn text_tuple() {
let schema = SchemaType::Tuple(vec![SchemaType::U32, SchemaType::String, SchemaType::Bool]);
assert_eq!(roundtrip(&schema, r#"(42, "hi", true)"#), r#"(42, "hi", true)"#);
}
#[test]
fn text_struct() {
use crate::Schema;
let schema = Point::schema();
assert_eq!(roundtrip(&schema, "{ x: 1.5, y: -3.0 }"), "{ x: 1.5, y: -3.0 }");
}
#[test]
fn text_enum_unit() {
use crate::Schema;
let schema = Shape::schema();
assert_eq!(roundtrip(&schema, "Empty"), "Empty");
}
#[test]
fn text_enum_single() {
use crate::Schema;
let schema = Shape::schema();
assert_eq!(roundtrip(&schema, "Circle(5.0)"), "Circle(5.0)");
}
#[test]
fn text_enum_struct() {
use crate::Schema;
let schema = Shape::schema();
assert_eq!(roundtrip(&schema, "Rect { w: 3.0, h: 4.0 }"), "Rect { w: 3.0, h: 4.0 }");
}
#[test]
fn text_enum_tuple() {
use crate::Schema;
let schema = Shape::schema();
assert_eq!(roundtrip(&schema, "Triangle(3.0, 4.0, 5.0)"), "Triangle(3.0, 4.0, 5.0)");
}
#[test]
fn text_option() {
let schema = SchemaType::Option(Box::new(SchemaType::U32));
assert_eq!(roundtrip(&schema, "None"), "None");
assert_eq!(roundtrip(&schema, "Some(42)"), "Some(42)");
}
#[test]
fn text_result() {
let schema = SchemaType::Result {
ok: Box::new(SchemaType::U64),
err: Box::new(SchemaType::String),
};
assert_eq!(roundtrip(&schema, "Ok(100)"), "Ok(100)");
assert_eq!(roundtrip(&schema, r#"Err("oops")"#), r#"Err("oops")"#);
}
#[test]
fn text_map() {
let schema = SchemaType::Map(Box::new(SchemaType::U32));
let raised = roundtrip(&schema, "{ alpha: 1, beta: 2 }");
assert_eq!(raised, "{ alpha: 1, beta: 2 }");
}
#[test]
fn text_nested() {
use crate::Schema;
let schema = SchemaType::List(Box::new(Shape::schema()));
assert_eq!(
roundtrip(&schema, "[Empty, Circle(1.0)]"),
"[Empty, Circle(1.0)]"
);
}
#[test]
fn text_whitespace_insensitive() {
use crate::Schema;
let schema = Point::schema();
assert_eq!(roundtrip(&schema, "{x:1.0,y:2.0}"), "{ x: 1.0, y: 2.0 }");
assert_eq!(roundtrip(&schema, " { x : 1.0 , y : 2.0 } "), "{ x: 1.0, y: 2.0 }");
}
#[test]
fn text_lower_typed_roundtrip() -> Result<()> {
use crate::Schema;
let schema = Point::schema();
let bytes = crate::lower(&schema, "{ x: 1.5, y: -3.0 }")?;
let p = Point::unpack_from_bytes(&bytes)?;
assert_eq!(p, Point { x: 1.5, y: -3.0 });
Ok(())
}
#[test]
fn text_raise_typed_roundtrip() -> Result<()> {
use crate::Schema;
let schema = Shape::schema();
let bytes = Shape::Rect { w: 3.0, h: 4.0 }.pack_to_vec()?;
let text = crate::raise(&schema, &bytes)?;
assert_eq!(text, "Rect { w: 3.0, h: 4.0 }");
Ok(())
}
#[test]
fn text_unicode_string() {
assert_eq!(roundtrip(&SchemaType::String, r#""hello 🦀""#), r#""hello 🦀""#);
}
#[test]
fn text_unicode_char() {
assert_eq!(roundtrip(&SchemaType::Char, "'🦀'"), "'🦀'");
}
#[test]
fn text_lower_error_wrong_type() {
assert!(crate::lower(&SchemaType::U8, "256").is_err());
assert!(crate::lower(&SchemaType::U8, "-1").is_err());
assert!(crate::lower(&SchemaType::Bool, "yes").is_err());
}
#[test]
fn text_lower_error_trailing() {
assert!(crate::lower(&SchemaType::U32, "42 extra").is_err());
}
#[test]
fn text_lower_error_unknown_variant() {
use crate::Schema;
assert!(crate::lower(&Shape::schema(), "Pentagon(5.0)").is_err());
}
}