use conjure_object::{DoubleKey, Uuid};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_bytes::ByteBuf;
use std::collections::BTreeMap;
use std::fmt::Debug;
fn serialize<T>(value: &T) -> Vec<u8>
where
T: Serialize,
{
crate::cbor::to_vec(value).unwrap()
}
fn deserialize_client<T>(cbor: &[u8]) -> T
where
T: DeserializeOwned,
{
crate::cbor::client_from_slice(cbor).unwrap()
}
fn deserialize_server<T>(cbor: &[u8]) -> T
where
T: DeserializeOwned,
{
crate::cbor::server_from_slice(cbor).unwrap()
}
fn test_ser<T>(ty: &T, expected_cbor: &[u8])
where
T: Serialize,
{
let actual_cbor = serialize(ty);
let expected_value = serde_cbor_2::from_slice::<serde_cbor_2::Value>(expected_cbor).unwrap();
let actual_value = serde_cbor_2::from_slice::<serde_cbor_2::Value>(&actual_cbor).unwrap();
assert_eq!(expected_value, actual_value);
}
fn test_de<T>(ty: &T, cbor: &[u8])
where
T: DeserializeOwned + PartialEq + Debug,
{
let deserialized = deserialize_client(cbor);
assert_eq!(*ty, deserialized);
let deserialized = deserialize_server(cbor);
assert_eq!(*ty, deserialized);
}
fn test_serde<T>(ty: &T, expected_cbor: &[u8])
where
T: Serialize + DeserializeOwned + PartialEq + Debug,
{
test_ser(ty, expected_cbor);
test_de(ty, expected_cbor);
}
#[test]
fn binary_serde() {
test_serde(
&ByteBuf::from(b"foobar".to_vec()),
&[0x46, b'f', b'o', b'o', b'b', b'a', b'r'],
);
}
#[test]
fn binary_keys() {
test_serde(
&BTreeMap::from([(ByteBuf::from(b"foobar".to_vec()), 0)]),
&[
0xa1, 0x46, b'f', b'o', b'o', b'b', b'a', b'r', 0x00, ],
)
}
#[test]
fn boolean_keys() {
test_serde(
&BTreeMap::from([(false, 0), (true, 1)]),
&[
0xa2, 0xf4, 0x00, 0xf5, 0x01, ],
);
}
#[test]
fn double_keys() {
let map = BTreeMap::from([
(DoubleKey(f64::NEG_INFINITY), 0),
(DoubleKey(-1.5), 1),
(DoubleKey(1.5), 2),
(DoubleKey(f64::INFINITY), 3),
(DoubleKey(f64::NAN), 4),
]);
let cbor = serialize(&map);
let _: BTreeMap<DoubleKey, i32> = deserialize_client(&cbor);
let _: BTreeMap<DoubleKey, i32> = deserialize_server(&cbor);
}
#[test]
fn uuid_keys() {
test_serde(
&BTreeMap::from([(Uuid::nil(), 1)]),
&[
0xa1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, ],
);
}
#[test]
fn uuid_values() {
test_serde(
&Uuid::nil(),
&[
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
],
)
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Foo {
foo: i32,
}
#[test]
fn client_unknown_fields() {
let deserialized = deserialize_client::<Foo>(&[
0xa2, 0x63, b'f', b'o', b'o', 0x01, 0x65, b'b', b'o', b'g', b'u', b's', 0x65, b'h', b'e', b'l', b'l', b'o', ]);
assert_eq!(Foo { foo: 1 }, deserialized);
}
#[test]
fn server_unknown_fields() {
let cbor = &[
0xa2, 0x63, b'f', b'o', b'o', 0x01, 0x65, b'b', b'o', b'g', b'u', b's', 0x65, b'h', b'e', b'l', b'l', b'o', ];
let e = crate::cbor::server_from_slice::<Foo>(cbor).err().unwrap();
assert!(e.to_string().contains("bogus") || e.to_string().contains("unknown"));
}
#[derive(Deserialize, Debug, PartialEq)]
struct Collections {
list: Vec<u32>,
set: std::collections::BTreeSet<u32>,
map: BTreeMap<String, u32>,
}
#[test]
fn null_collections() {
let cbor = &[
0xa3, 0x64, b'l', b'i', b's', b't', 0xf6, 0x63, b'm', b'a', b'p', 0xf6, 0x63, b's', b'e', b't', 0xf6, ];
let expected = Collections {
list: vec![],
set: std::collections::BTreeSet::new(),
map: BTreeMap::new(),
};
let actual = deserialize_server(cbor);
assert_eq!(expected, actual);
let actual = deserialize_client(cbor);
assert_eq!(expected, actual);
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct UuidField {
uuid: Uuid,
}
#[test]
fn uuid_field() {
let cbor = &[
0xa1, 0x64, b'u', b'u', b'i', b'd', 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
];
let value = UuidField { uuid: Uuid::nil() };
let actual = crate::cbor::to_vec(&value).unwrap();
assert_eq!(actual, cbor);
let actual = crate::cbor::client_from_slice::<UuidField>(cbor).unwrap();
assert_eq!(actual, value);
let actual = crate::cbor::server_from_slice::<UuidField>(cbor).unwrap();
assert_eq!(actual, value);
}
#[test]
fn round_trip() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct TestStruct {
a: i32,
b: String,
c: Vec<u8>,
d: Option<bool>,
}
let value = TestStruct {
a: 42,
b: "hello".to_string(),
c: vec![1, 2, 3],
d: Some(true),
};
let cbor = serialize(&value);
let deserialized: TestStruct = deserialize_client(&cbor);
assert_eq!(value, deserialized);
let deserialized: TestStruct = deserialize_server(&cbor);
assert_eq!(value, deserialized);
}
#[test]
fn integer_keys_from_cbor() {
let cbor = &[
0xbf, 0x01, 0x63, b'o', b'n', b'e', 0x18, 0x2a, 0x69, b'f', b'o', b'r', b't', b'y', b'-', b't', b'w', b'o', 0xff, ];
let map: BTreeMap<i32, String> = deserialize_client(cbor);
assert_eq!(map.get(&1), Some(&"one".to_string()));
assert_eq!(map.get(&42), Some(&"forty-two".to_string()));
assert_eq!(map.len(), 2);
}
#[test]
fn binary_as_byte_string() {
let cbor = &[
0x47, 0x00, 0x01, 0x02, 0x03, 0xFF, 0xAB, 0xCD,
];
let bytes: conjure_object::Bytes = deserialize_client(cbor);
assert_eq!(bytes.as_ref(), &[0x00, 0x01, 0x02, 0x03, 0xFF, 0xAB, 0xCD]);
}
#[test]
fn serialize_map_keys_as_strings() {
#[derive(Serialize)]
struct TestStructWithUuidKeys {
#[serde(serialize_with = "conjure_object::private::serialize_map_keys_as_strings")]
uuid_map: BTreeMap<Uuid, String>,
}
#[derive(Deserialize)]
struct TestStructWithStringKeys {
uuid_map: BTreeMap<String, String>,
}
let mut map = BTreeMap::new();
map.insert(
Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
"first".to_string(),
);
map.insert(
Uuid::parse_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap(),
"second".to_string(),
);
let test_struct = TestStructWithUuidKeys { uuid_map: map };
let cbor = serialize(&test_struct);
let deserialized: TestStructWithStringKeys = serde_cbor_2::from_slice(&cbor).unwrap();
assert_eq!(
deserialized
.uuid_map
.get("550e8400-e29b-41d4-a716-446655440000"),
Some(&"first".to_string())
);
assert_eq!(
deserialized
.uuid_map
.get("6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
Some(&"second".to_string())
);
}
#[test]
fn serialize_uuid_alias_map_keys_as_strings() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
struct UuidAlias(Uuid);
impl std::fmt::Display for UuidAlias {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
#[derive(Serialize)]
struct TestStructWithAliasKeys {
#[serde(serialize_with = "conjure_object::private::serialize_map_keys_as_strings")]
alias_map: BTreeMap<UuidAlias, String>,
}
#[derive(Deserialize)]
struct TestStructWithStringKeys {
alias_map: BTreeMap<String, String>,
}
let mut map = BTreeMap::new();
map.insert(
UuidAlias(Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap()),
"first".to_string(),
);
map.insert(
UuidAlias(Uuid::parse_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap()),
"second".to_string(),
);
let test_struct = TestStructWithAliasKeys { alias_map: map };
let cbor = serialize(&test_struct);
let deserialized: TestStructWithStringKeys = serde_cbor_2::from_slice(&cbor).unwrap();
assert_eq!(
deserialized
.alias_map
.get("550e8400-e29b-41d4-a716-446655440000"),
Some(&"first".to_string())
);
assert_eq!(
deserialized
.alias_map
.get("6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
Some(&"second".to_string())
);
}