use reliakit_codec::{decode_from_slice_exact, encode_to_vec, CodecErrorKind};
use reliakit_derive::{CanonicalDecode, CanonicalEncode};
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Point {
x: u16,
y: u16,
}
#[test]
fn named_struct_roundtrip() {
let point = Point { x: 10, y: 20 };
let bytes = encode_to_vec(&point).unwrap();
assert_eq!(bytes, [10, 0, 20, 0]);
assert_eq!(decode_from_slice_exact::<Point>(&bytes).unwrap(), point);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Header {
tag: u8,
flag: bool,
label: String,
}
#[test]
fn named_struct_mixed_fields_roundtrip() {
let header = Header {
tag: 7,
flag: true,
label: "ok".to_string(),
};
let bytes = encode_to_vec(&header).unwrap();
assert_eq!(decode_from_slice_exact::<Header>(&bytes).unwrap(), header);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Pair(u8, u16);
#[test]
fn tuple_struct_roundtrip() {
let pair = Pair(1, 2);
let bytes = encode_to_vec(&pair).unwrap();
assert_eq!(bytes, [1, 2, 0]);
assert_eq!(decode_from_slice_exact::<Pair>(&bytes).unwrap(), pair);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Marker;
#[test]
fn unit_struct_roundtrip() {
let bytes = encode_to_vec(&Marker).unwrap();
assert!(bytes.is_empty());
assert_eq!(decode_from_slice_exact::<Marker>(&bytes).unwrap(), Marker);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Empty {}
#[test]
fn empty_named_struct_roundtrip() {
let bytes = encode_to_vec(&Empty {}).unwrap();
assert!(bytes.is_empty());
assert_eq!(decode_from_slice_exact::<Empty>(&bytes).unwrap(), Empty {});
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Single {
only: u64,
}
#[test]
fn single_field_struct_roundtrip() {
let value = Single { only: 42 };
let bytes = encode_to_vec(&value).unwrap();
assert_eq!(decode_from_slice_exact::<Single>(&bytes).unwrap(), value);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
pub struct Documented {
pub tag: u8,
#[allow(dead_code)]
pub value: u32,
pub r#type: u8,
}
#[test]
fn attributed_public_raw_ident_struct_roundtrip() {
let value = Documented {
tag: 1,
value: 2,
r#type: 3,
};
let bytes = encode_to_vec(&value).unwrap();
assert_eq!(
decode_from_slice_exact::<Documented>(&bytes).unwrap(),
value
);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
pub struct Wrapped(pub u8, pub u16);
#[test]
fn public_tuple_struct_roundtrip() {
let value = Wrapped(5, 6);
let bytes = encode_to_vec(&value).unwrap();
assert_eq!(bytes, [5, 6, 0]);
assert_eq!(decode_from_slice_exact::<Wrapped>(&bytes).unwrap(), value);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
enum Signal {
Ping,
Pong,
}
#[test]
fn unit_enum_encode_exact_bytes() {
assert_eq!(encode_to_vec(&Signal::Ping).unwrap(), [0, 0, 0, 0]);
assert_eq!(encode_to_vec(&Signal::Pong).unwrap(), [1, 0, 0, 0]);
}
#[test]
fn unit_enum_decode() {
assert_eq!(
decode_from_slice_exact::<Signal>(&[0, 0, 0, 0]).unwrap(),
Signal::Ping
);
assert_eq!(
decode_from_slice_exact::<Signal>(&[1, 0, 0, 0]).unwrap(),
Signal::Pong
);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
enum Command {
SetPort(u16),
SetName(String),
}
#[test]
fn tuple_enum_encode_exact_bytes() {
assert_eq!(
encode_to_vec(&Command::SetPort(8080)).unwrap(),
[0, 0, 0, 0, 0x90, 0x1f]
);
assert_eq!(
encode_to_vec(&Command::SetName("hi".to_string())).unwrap(),
[1, 0, 0, 0, 2, 0, 0, 0, b'h', b'i']
);
}
#[test]
fn tuple_enum_decode() {
assert_eq!(
decode_from_slice_exact::<Command>(&[0, 0, 0, 0, 0x90, 0x1f]).unwrap(),
Command::SetPort(8080)
);
assert_eq!(
decode_from_slice_exact::<Command>(&[1, 0, 0, 0, 2, 0, 0, 0, b'h', b'i']).unwrap(),
Command::SetName("hi".to_string())
);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
enum Event {
UserCreated { id: u64, name: String },
UserDeleted { id: u64 },
}
#[test]
fn struct_enum_encode_exact_bytes() {
assert_eq!(
encode_to_vec(&Event::UserCreated {
id: 1,
name: "a".to_string(),
})
.unwrap(),
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'a']
);
assert_eq!(
encode_to_vec(&Event::UserDeleted { id: 5 }).unwrap(),
[1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0]
);
}
#[test]
fn struct_enum_decode() {
assert_eq!(
decode_from_slice_exact::<Event>(&[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'a'])
.unwrap(),
Event::UserCreated {
id: 1,
name: "a".to_string(),
}
);
assert_eq!(
decode_from_slice_exact::<Event>(&[1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
Event::UserDeleted { id: 5 }
);
}
#[test]
fn unknown_tag_rejected() {
let err = decode_from_slice_exact::<Signal>(&[9, 0, 0, 0]).unwrap_err();
assert_eq!(err.kind(), CodecErrorKind::InvalidValue);
}
#[test]
fn truncated_tag_rejected() {
let err = decode_from_slice_exact::<Signal>(&[0, 0]).unwrap_err();
assert_eq!(err.kind(), CodecErrorKind::UnexpectedEof);
}
#[test]
fn truncated_tuple_payload_rejected() {
let err = decode_from_slice_exact::<Command>(&[0, 0, 0, 0, 0x90]).unwrap_err();
assert_eq!(err.kind(), CodecErrorKind::UnexpectedEof);
}
#[test]
fn truncated_struct_payload_rejected() {
let err = decode_from_slice_exact::<Event>(&[1, 0, 0, 0, 5, 0, 0]).unwrap_err();
assert_eq!(err.kind(), CodecErrorKind::UnexpectedEof);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
enum Many {
A,
B,
C,
D,
}
#[test]
fn declaration_order_tags_preserved() {
assert_eq!(encode_to_vec(&Many::A).unwrap(), [0, 0, 0, 0]);
assert_eq!(encode_to_vec(&Many::B).unwrap(), [1, 0, 0, 0]);
assert_eq!(encode_to_vec(&Many::C).unwrap(), [2, 0, 0, 0]);
assert_eq!(encode_to_vec(&Many::D).unwrap(), [3, 0, 0, 0]);
}
#[test]
fn decode_returns_correct_variant() {
assert_eq!(
decode_from_slice_exact::<Many>(&[2, 0, 0, 0]).unwrap(),
Many::C
);
assert_eq!(
decode_from_slice_exact::<Many>(&[3, 0, 0, 0]).unwrap(),
Many::D
);
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
pub enum Mixed {
Empty,
One(u8),
Two(u16, u8),
Record { a: u8, b: u16 },
}
#[test]
fn mixed_enum_roundtrip() {
for value in [
Mixed::Empty,
Mixed::One(7),
Mixed::Two(1000, 9),
Mixed::Record { a: 3, b: 600 },
] {
let bytes = encode_to_vec(&value).unwrap();
assert_eq!(decode_from_slice_exact::<Mixed>(&bytes).unwrap(), value);
}
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
struct Inner {
a: u8,
b: u16,
}
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
enum Nested {
Wrap(Inner),
Pair { left: Inner, right: u8 },
List(Vec<u8>),
Maybe(Option<u16>),
}
#[test]
fn nested_and_composite_roundtrip() {
for value in [
Nested::Wrap(Inner { a: 1, b: 2 }),
Nested::Pair {
left: Inner { a: 3, b: 4 },
right: 5,
},
Nested::List(vec![10, 20, 30]),
Nested::Maybe(Some(700)),
Nested::Maybe(None),
] {
let bytes = encode_to_vec(&value).unwrap();
assert_eq!(decode_from_slice_exact::<Nested>(&bytes).unwrap(), value);
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, CanonicalEncode, CanonicalDecode)]
enum Keywords {
r#type,
r#match(u8),
Pair { r#fn: u8, r#struct: u16 },
}
#[test]
fn raw_identifier_variants_and_fields_roundtrip() {
for value in [
Keywords::r#type,
Keywords::r#match(9),
Keywords::Pair {
r#fn: 1,
r#struct: 2,
},
] {
let bytes = encode_to_vec(&value).unwrap();
assert_eq!(decode_from_slice_exact::<Keywords>(&bytes).unwrap(), value);
}
}