use facet::Facet;
use facet_cbor::to_vec;
use std::collections::HashMap;
#[test]
fn test_u32() {
let bytes = to_vec(&42u32).unwrap();
assert_eq!(bytes, vec![0x18, 0x2a]);
}
#[test]
fn test_u32_small() {
assert_eq!(to_vec(&0u32).unwrap(), vec![0x00]);
assert_eq!(to_vec(&23u32).unwrap(), vec![0x17]);
assert_eq!(to_vec(&24u32).unwrap(), vec![0x18, 0x18]);
}
#[test]
fn test_u64_large() {
let bytes = to_vec(&1_000_000u64).unwrap();
assert_eq!(bytes, vec![0x1a, 0x00, 0x0f, 0x42, 0x40]);
}
#[test]
fn test_i64_positive() {
let bytes = to_vec(&100i64).unwrap();
assert_eq!(bytes, vec![0x18, 0x64]);
}
#[test]
fn test_i64_negative() {
assert_eq!(to_vec(&-1i64).unwrap(), vec![0x20]);
assert_eq!(to_vec(&-10i64).unwrap(), vec![0x29]);
assert_eq!(to_vec(&-100i64).unwrap(), vec![0x38, 0x63]);
}
#[test]
fn test_string() {
let bytes = to_vec(&String::from("hello")).unwrap();
assert_eq!(bytes, vec![0x65, b'h', b'e', b'l', b'l', b'o']);
}
#[test]
fn test_empty_string() {
let bytes = to_vec(&String::from("")).unwrap();
assert_eq!(bytes, vec![0x60]); }
#[test]
fn test_bool() {
assert_eq!(to_vec(&true).unwrap(), vec![0xf5]);
assert_eq!(to_vec(&false).unwrap(), vec![0xf4]);
}
#[test]
fn test_f64() {
let bytes = to_vec(&1.0f64).unwrap();
assert_eq!(bytes.len(), 9);
assert_eq!(bytes[0], 0xfb);
assert_eq!(&bytes[1..], &1.0f64.to_be_bytes());
}
#[test]
fn test_f32() {
let bytes = to_vec(&1.0f32).unwrap();
assert_eq!(bytes.len(), 5);
assert_eq!(bytes[0], 0xfa);
assert_eq!(&bytes[1..], &1.0f32.to_be_bytes());
}
#[test]
fn test_unit() {
assert_eq!(to_vec(&()).unwrap(), vec![0xf6]); }
#[derive(Facet)]
struct Point {
x: i32,
y: i32,
}
#[test]
fn test_struct() {
let p = Point { x: 1, y: 2 };
let bytes = to_vec(&p).unwrap();
let expected = vec![
0xa2, 0x61, b'x', 0x01, 0x61, b'y', 0x02,
];
assert_eq!(bytes, expected);
}
#[derive(Facet)]
struct Nested {
name: String,
point: Point,
}
#[test]
fn test_nested_struct() {
let n = Nested {
name: String::from("A"),
point: Point { x: 10, y: 20 },
};
let bytes = to_vec(&n).unwrap();
let mut expected = Vec::new();
expected.push(0xa2); expected.extend_from_slice(&[0x64, b'n', b'a', b'm', b'e']);
expected.extend_from_slice(&[0x61, b'A']);
expected.extend_from_slice(&[0x65, b'p', b'o', b'i', b'n', b't']);
expected.push(0xa2);
expected.extend_from_slice(&[0x61, b'x']);
expected.push(0x0a); expected.extend_from_slice(&[0x61, b'y']);
expected.push(0x14); assert_eq!(bytes, expected);
}
#[derive(Facet)]
#[repr(u8)]
enum Color {
Red,
Green,
Blue,
}
#[test]
fn test_unit_variant() {
let bytes = to_vec(&Color::Red).unwrap();
let mut expected = Vec::new();
expected.push(0xa1); expected.extend_from_slice(&[0x63, b'R', b'e', b'd']); expected.push(0xf6); assert_eq!(bytes, expected);
}
#[derive(Facet)]
#[repr(u8)]
#[allow(dead_code)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
#[test]
fn test_struct_variant() {
let s = Shape::Circle { radius: 1.5 };
let bytes = to_vec(&s).unwrap();
let mut expected = Vec::new();
expected.push(0xa1); expected.extend_from_slice(&[0x66, b'C', b'i', b'r', b'c', b'l', b'e']); expected.push(0xa1); expected.extend_from_slice(&[0x66, b'r', b'a', b'd', b'i', b'u', b's']); expected.push(0xfb); expected.extend_from_slice(&1.5f64.to_be_bytes());
assert_eq!(bytes, expected);
}
#[derive(Facet)]
#[repr(u8)]
#[allow(dead_code)]
enum Value {
Num(i64),
Text(String),
}
#[test]
fn test_newtype_variant() {
let v = Value::Num(42);
let bytes = to_vec(&v).unwrap();
let mut expected = Vec::new();
expected.push(0xa1);
expected.extend_from_slice(&[0x63, b'N', b'u', b'm']); expected.extend_from_slice(&[0x18, 0x2a]); assert_eq!(bytes, expected);
}
#[test]
fn test_vec() {
let v = vec![1u32, 2, 3];
let bytes = to_vec(&v).unwrap();
assert_eq!(bytes, vec![0x83, 0x01, 0x02, 0x03]);
}
#[test]
fn test_vec_u8_as_bytes() {
let v: Vec<u8> = vec![0xde, 0xad, 0xbe, 0xef];
let bytes = to_vec(&v).unwrap();
assert_eq!(bytes, vec![0x44, 0xde, 0xad, 0xbe, 0xef]);
}
#[test]
fn test_option_some() {
let v: Option<u32> = Some(42);
let bytes = to_vec(&v).unwrap();
assert_eq!(bytes, vec![0x18, 0x2a]);
}
#[test]
fn test_option_none() {
let v: Option<u32> = None;
let bytes = to_vec(&v).unwrap();
assert_eq!(bytes, vec![0xf6]);
}
#[test]
fn test_hashmap() {
let mut m = HashMap::new();
m.insert(String::from("a"), 1u32);
let bytes = to_vec(&m).unwrap();
let mut expected = Vec::new();
expected.push(0xa1); expected.extend_from_slice(&[0x61, b'a']); expected.push(0x01); assert_eq!(bytes, expected);
}
#[test]
fn test_deterministic() {
let p = Point { x: 42, y: -7 };
let bytes1 = to_vec(&p).unwrap();
let bytes2 = to_vec(&p).unwrap();
assert_eq!(
bytes1, bytes2,
"same input must produce identical CBOR bytes"
);
}
#[derive(Facet, Debug, PartialEq)]
#[repr(u8)]
#[facet(tag = "tag", rename_all = "snake_case")]
#[allow(dead_code)]
enum PrimType {
Bool,
U8,
U16,
String,
}
#[test]
fn test_internally_tagged_unit_variant() {
let bytes = to_vec(&PrimType::Bool).unwrap();
assert_eq!(bytes, vec![0x64, b'b', b'o', b'o', b'l']);
}
#[test]
fn test_internally_tagged_unit_variant_u8() {
let bytes = to_vec(&PrimType::U8).unwrap();
assert_eq!(bytes, vec![0x62, b'u', b'8']);
}
#[test]
fn test_internally_tagged_unit_variant_string() {
let bytes = to_vec(&PrimType::String).unwrap();
assert_eq!(bytes, vec![0x66, b's', b't', b'r', b'i', b'n', b'g']);
}
#[derive(Facet, Debug, PartialEq)]
#[repr(u8)]
#[facet(tag = "tag", rename_all = "snake_case")]
#[allow(dead_code)]
enum TaggedShape {
Struct { name: String, field_count: u32 },
Primitive { primitive_type: String },
}
#[test]
fn test_internally_tagged_struct_variant() {
let s = TaggedShape::Primitive {
primitive_type: "bool".to_string(),
};
let bytes = to_vec(&s).unwrap();
let decoded: std::collections::HashMap<String, String> =
facet_cbor::from_slice(&bytes).unwrap();
assert_eq!(decoded.get("tag").unwrap(), "primitive");
assert_eq!(decoded.get("primitive_type").unwrap(), "bool");
}
#[test]
fn test_internally_tagged_struct_variant_multi_field() {
let s = TaggedShape::Struct {
name: "Foo".to_string(),
field_count: 3,
};
let bytes = to_vec(&s).unwrap();
let mut offset = 0;
assert_eq!(bytes[0], 0xa3); offset += 1;
let tag_key_len = bytes[offset] - 0x60;
offset += 1;
let tag_key = std::str::from_utf8(&bytes[offset..offset + tag_key_len as usize]).unwrap();
assert_eq!(tag_key, "tag");
offset += tag_key_len as usize;
let tag_val_len = bytes[offset] - 0x60;
offset += 1;
let tag_val = std::str::from_utf8(&bytes[offset..offset + tag_val_len as usize]).unwrap();
assert_eq!(tag_val, "struct");
}
#[derive(Facet, Debug, PartialEq)]
#[repr(u8)]
#[facet(tag = "tag", rename_all = "snake_case")]
#[allow(dead_code)]
enum MixedTagged {
Unit,
WithData { value: u32 },
}
#[test]
fn test_internally_tagged_mixed_unit() {
let bytes = to_vec(&MixedTagged::Unit).unwrap();
assert_eq!(bytes, vec![0x64, b'u', b'n', b'i', b't']);
}
#[test]
fn test_internally_tagged_mixed_struct() {
let bytes = to_vec(&MixedTagged::WithData { value: 42 }).unwrap();
assert_eq!(bytes[0], 0xa2); }
#[test]
fn test_internally_tagged_roundtrip_unit() {
let original = PrimType::U16;
let bytes = to_vec(&original).unwrap();
let decoded: PrimType = facet_cbor::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn test_internally_tagged_roundtrip_struct() {
let original = TaggedShape::Primitive {
primitive_type: "u32".to_string(),
};
let bytes = to_vec(&original).unwrap();
let decoded: TaggedShape = facet_cbor::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn test_internally_tagged_roundtrip_struct_multi_field() {
let original = TaggedShape::Struct {
name: "Point".to_string(),
field_count: 2,
};
let bytes = to_vec(&original).unwrap();
let decoded: TaggedShape = facet_cbor::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn test_internally_tagged_roundtrip_mixed() {
for original in [MixedTagged::Unit, MixedTagged::WithData { value: 99 }] {
let bytes = to_vec(&original).unwrap();
let decoded: MixedTagged = facet_cbor::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
}
}
#[derive(Facet, Debug, PartialEq)]
#[repr(u8)]
#[facet(tag = "tag", rename_all = "snake_case")]
#[allow(dead_code)]
enum CasingTest {
SimpleCase,
TwoWords,
XMLParser,
}
#[test]
fn test_rename_all_snake_case() {
let bytes = to_vec(&CasingTest::SimpleCase).unwrap();
let s = std::str::from_utf8(&bytes[1..]).unwrap(); assert_eq!(s, "simple_case");
}
#[test]
fn test_rename_all_two_words() {
let bytes = to_vec(&CasingTest::TwoWords).unwrap();
let s = std::str::from_utf8(&bytes[1..]).unwrap();
assert_eq!(s, "two_words");
}
#[derive(Facet, Debug, PartialEq)]
#[repr(u8)]
#[allow(dead_code)]
enum NoRename {
MyVariant,
}
#[test]
fn test_externally_tagged_no_rename() {
let bytes = to_vec(&NoRename::MyVariant).unwrap();
let mut expected = Vec::new();
expected.push(0xa1); expected.extend_from_slice(&[0x69]); expected.extend_from_slice(b"MyVariant");
expected.push(0xf6); assert_eq!(bytes, expected);
}
#[derive(Facet, Debug, PartialEq)]
#[repr(u8)]
#[facet(rename_all = "snake_case")]
#[allow(dead_code)]
enum ExtRename {
MyVariant,
}
#[test]
fn test_externally_tagged_with_rename() {
let bytes = to_vec(&ExtRename::MyVariant).unwrap();
let mut expected = Vec::new();
expected.push(0xa1); expected.extend_from_slice(&[0x6a]); expected.extend_from_slice(b"my_variant");
expected.push(0xf6); assert_eq!(bytes, expected);
}
#[test]
fn test_negative_integers_use_major_1() {
let bytes = to_vec(&-1i32).unwrap();
assert_eq!(bytes[0] >> 5, 1, "first byte should have major type 1");
assert_eq!(bytes, vec![0x20]);
let bytes = to_vec(&-24i32).unwrap();
assert_eq!(bytes, vec![0x37]);
let bytes = to_vec(&-25i32).unwrap();
assert_eq!(bytes, vec![0x38, 0x18]);
}