use std::collections::HashMap;
use cbor2::de::Error;
use cbor2::Value;
use serde::Deserialize;
fn de<T: serde::de::DeserializeOwned>(hex: &str) -> Result<T, Error> {
cbor2::from_slice(&hex::decode(hex).unwrap())
}
#[derive(Debug, PartialEq, Deserialize)]
enum Enum {
Unit,
Newtype(u32),
Tuple(u32, u32),
Struct { x: u32 },
}
#[test]
fn type_mismatches() {
assert!(de::<bool>("01").is_err());
assert!(de::<f64>("01").is_err());
assert!(de::<u64>("6161").is_err()); assert!(de::<i64>("f4").is_err()); assert!(de::<char>("01").is_err());
assert!(de::<String>("01").is_err());
assert!(de::<serde_bytes::ByteBuf>("01").is_err());
assert!(de::<Vec<u8>>("f4").is_err());
assert!(de::<HashMap<String, u8>>("01").is_err());
assert!(de::<()>("01").is_err());
assert!(de::<Enum>("01").is_err());
let msg = de::<u64>("44deadbeef").unwrap_err().to_string();
assert!(msg.contains("bytes"), "{msg}");
let msg = de::<u64>("80").unwrap_err().to_string();
assert!(msg.contains("sequence"), "{msg}");
let msg = de::<u64>("a0").unwrap_err().to_string();
assert!(msg.contains("map"), "{msg}");
let msg = de::<u64>("f6").unwrap_err().to_string();
assert!(msg.contains("null"), "{msg}");
let msg = de::<u64>("f7").unwrap_err().to_string();
assert!(msg.contains("undefined"), "{msg}");
let msg = de::<u64>("f4").unwrap_err().to_string();
assert!(msg.contains("false") || msg.contains("boolean"), "{msg}");
let msg = de::<u64>("f93c00").unwrap_err().to_string();
assert!(msg.contains('1'), "{msg}");
let msg = de::<bool>("f0").unwrap_err().to_string();
assert!(msg.contains("expected bool"), "{msg}");
}
#[test]
fn tags_are_skipped_in_typed_positions() {
assert!(de::<bool>("c1f5").unwrap());
assert_eq!(de::<f64>("c1f93c00").unwrap(), 1.0);
assert_eq!(de::<f32>("c1f93c00").unwrap(), 1.0);
assert_eq!(de::<char>("c16161").unwrap(), 'a');
assert_eq!(de::<String>("c16161").unwrap(), "a");
assert_eq!(de::<serde_bytes::ByteBuf>("c14101").unwrap().as_ref(), &[1]);
assert_eq!(de::<Vec<u8>>("c18101").unwrap(), vec![1]);
assert_eq!(
de::<HashMap<String, u8>>("c1a1616101").unwrap(),
[("a".to_string(), 1u8)].into()
);
de::<()>("c1f6").unwrap();
assert_eq!(de::<Option<u64>>("c101").unwrap(), Some(1));
assert_eq!(
de::<Enum>("c1a1674e657774797065182a").unwrap(),
Enum::Newtype(42)
);
assert_eq!(de::<u64>("c1c1c101").unwrap(), 1);
}
#[test]
fn chars() {
assert_eq!(de::<char>("63e6b0b4").unwrap(), 'æ°´');
assert_eq!(de::<char>("7f6161ff").unwrap(), 'a');
assert!(de::<char>("626162").is_err());
assert!(de::<char>("7f61616162ff").is_err());
assert!(de::<char>("60").is_err());
assert!(matches!(de::<char>("62fffe"), Err(Error::Syntax(0))));
assert!(de::<char>("6568656c6c6f").is_err());
}
#[test]
fn bignum_errors() {
assert!(de::<u64>("c201").is_err());
assert!(de::<u64>("c249010101010101010101").is_err()); assert!(de::<i64>("c349010101010101010101").is_err());
let msg = de::<u128>(
"c25101010101010101010101010101010101 01"
.replace(' ', "")
.as_str(),
)
.unwrap_err()
.to_string();
assert!(msg.contains("bigint too large"), "{msg}"); assert!(de::<i128>(
"c35101010101010101010101010101010101 01"
.replace(' ', "")
.as_str()
)
.is_err());
assert!(de::<i128>("c35080000000000000000000000000000000").is_err());
assert!(de::<i128>(
"c25101010101010101010101010101010101 01"
.replace(' ', "")
.as_str()
)
.is_err());
let msg = de::<u64>("20").unwrap_err().to_string();
assert!(msg.contains("unexpected negative"), "{msg}");
assert!(de::<u128>("c34101").is_err());
}
#[test]
fn bignums_collapse_or_stay_tagged_in_any() {
assert_eq!(de::<Value>("c24101").unwrap(), Value::from(1));
assert_eq!(de::<Value>("c34101").unwrap(), Value::from(-2));
let value = de::<Value>("c35080000000000000000000000000000000").unwrap();
let (tag, inner) = value.as_tag().unwrap();
assert_eq!(tag, 3);
assert_eq!(inner.as_bytes().unwrap().len(), 16);
assert_eq!(de::<u8>("c243000007").unwrap(), 7);
assert_eq!(de::<Value>("c243000007").unwrap(), Value::from(7));
}
#[test]
fn identifiers() {
#[derive(Debug, PartialEq, Deserialize)]
struct F {
a: u8,
}
assert_eq!(de::<F>("a1416101").unwrap(), F { a: 1 });
assert_eq!(de::<F>("a17f6161ff01").unwrap(), F { a: 1 });
assert_eq!(de::<F>("a15f4161ff01").unwrap(), F { a: 1 });
assert_eq!(de::<F>("a1c1616101").unwrap(), F { a: 1 });
assert!(matches!(de::<F>("a162fffe01"), Err(Error::Syntax(1))));
let msg = de::<F>("a10102").unwrap_err().to_string();
assert!(msg.contains("missing field"), "{msg}");
let msg = de::<F>("a1f93c0001").unwrap_err().to_string();
assert!(msg.contains("str, bytes or an integer"), "{msg}");
}
#[test]
fn enum_forms() {
assert_eq!(de::<Enum>("a164556e6974f6").unwrap(), Enum::Unit);
assert!(de::<Enum>("a164556e697405").is_err());
let text = |name: &str| cbor2::to_vec(&name).unwrap();
assert!(cbor2::from_slice::<Enum>(&text("Newtype")).is_err());
assert!(cbor2::from_slice::<Enum>(&text("Tuple")).is_err());
assert!(cbor2::from_slice::<Enum>(&text("Struct")).is_err());
assert!(de::<Enum>("bf674e657774797065182aff").is_err());
assert!(de::<Enum>("a2674e657774797065182a6155f6").is_err());
}
#[test]
fn stream_iterator_errors() {
let mut iter = cbor2::de::Deserializer::from_reader(&[0x01, 0x1c][..]).into_iter::<u32>();
assert_eq!(iter.next().unwrap().unwrap(), 1);
assert!(matches!(iter.next().unwrap(), Err(Error::Syntax(1))));
}
#[test]
fn indefinite_segment_majors_must_match() {
assert!(matches!(de::<Value>("5f6161ff"), Err(Error::Syntax(1))));
assert!(matches!(de::<String>("7f4161ff"), Err(Error::Syntax(1))));
}
#[test]
fn deeply_tagged_input_hits_the_recursion_limit() {
let bomb = vec![0xc1u8; 65536];
assert!(matches!(
cbor2::from_slice::<Value>(&bomb),
Err(Error::RecursionLimitExceeded)
));
}
#[test]
fn options_and_units() {
assert_eq!(de::<Option<Option<u64>>>("f7").unwrap(), None);
de::<()>("f7").unwrap();
#[derive(Debug, PartialEq, Deserialize)]
struct UnitStruct;
de::<UnitStruct>("f6").unwrap();
assert!(de::<UnitStruct>("01").is_err());
}
#[derive(Debug, PartialEq)]
enum StrVisit {
Str(String),
String(String),
}
#[derive(Debug, PartialEq)]
struct StrProbe(StrVisit);
impl<'de> Deserialize<'de> for StrProbe {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V;
impl serde::de::Visitor<'_> for V {
type Value = StrVisit;
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "a string")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<StrVisit, E> {
Ok(StrVisit::Str(v.to_owned()))
}
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<StrVisit, E> {
Ok(StrVisit::String(v))
}
}
deserializer.deserialize_str(V).map(StrProbe)
}
}
#[derive(Debug, PartialEq)]
enum BytesVisit {
Bytes(Vec<u8>),
ByteBuf(Vec<u8>),
Seq(Vec<u8>),
}
#[derive(Debug, PartialEq)]
struct BytesProbe(BytesVisit);
impl<'de> Deserialize<'de> for BytesProbe {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V;
impl<'a> serde::de::Visitor<'a> for V {
type Value = BytesVisit;
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "bytes")
}
fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<BytesVisit, E> {
Ok(BytesVisit::Bytes(v.to_vec()))
}
fn visit_byte_buf<E: serde::de::Error>(self, v: Vec<u8>) -> Result<BytesVisit, E> {
Ok(BytesVisit::ByteBuf(v))
}
fn visit_seq<A: serde::de::SeqAccess<'a>>(
self,
mut seq: A,
) -> Result<BytesVisit, A::Error> {
let mut bytes = Vec::new();
while let Some(byte) = seq.next_element()? {
bytes.push(byte);
}
Ok(BytesVisit::Seq(bytes))
}
}
deserializer.deserialize_bytes(V).map(BytesProbe)
}
}
#[test]
fn borrowing_entry_points() {
assert_eq!(
de::<StrProbe>("6161").unwrap(),
StrProbe(StrVisit::Str("a".into()))
);
assert_eq!(
de::<BytesProbe>("4101").unwrap(),
BytesProbe(BytesVisit::Bytes(vec![1]))
);
assert_eq!(
de::<BytesProbe>("8101").unwrap(),
BytesProbe(BytesVisit::Seq(vec![1]))
);
}
#[derive(Debug, PartialEq, Deserialize)]
struct BorrowedFields<'a> {
#[serde(borrow)]
s: &'a str,
#[serde(borrow, with = "serde_bytes")]
b: &'a [u8],
}
#[test]
fn from_slice_borrows_definite_text_and_bytes() {
let bytes = hex::decode("a26173626869616242dead").unwrap();
let out: BorrowedFields<'_> = cbor2::from_slice(&bytes).unwrap();
assert_eq!(
out,
BorrowedFields {
s: "hi",
b: &[0xde, 0xad]
}
);
assert_eq!(out.s.as_ptr(), bytes[4..].as_ptr());
assert_eq!(out.b.as_ptr(), bytes[9..].as_ptr());
let chunked = hex::decode("7f6161ff").unwrap();
assert_eq!(cbor2::from_slice::<String>(&chunked).unwrap(), "a");
assert!(cbor2::from_slice::<&str>(&chunked).is_err());
}
#[test]
fn more_unexpected_descriptions() {
let msg = de::<f64>("20").unwrap_err().to_string();
assert!(msg.contains("-1"), "{msg}");
let msg = de::<u64>("f5").unwrap_err().to_string();
assert!(msg.contains("true") || msg.contains("boolean"), "{msg}");
let msg = de::<u64>("c2c101").unwrap_err().to_string();
assert!(msg.contains("tag"), "{msg}");
}
#[test]
fn empty_input_fails_everywhere() {
assert!(de::<bool>("").is_err());
assert!(de::<u64>("").is_err());
assert!(de::<i64>("").is_err());
assert!(de::<u128>("").is_err());
assert!(de::<i128>("").is_err());
assert!(de::<f32>("").is_err());
assert!(de::<f64>("").is_err());
assert!(de::<char>("").is_err());
assert!(de::<String>("").is_err());
assert!(de::<StrProbe>("").is_err());
assert!(de::<serde_bytes::ByteBuf>("").is_err());
assert!(de::<BytesProbe>("").is_err());
assert!(de::<Vec<u8>>("").is_err());
assert!(de::<(u8, u8)>("").is_err());
assert!(de::<HashMap<String, u8>>("").is_err());
assert!(de::<()>("").is_err());
assert!(de::<Option<u8>>("").is_err());
assert!(de::<Enum>("").is_err());
assert!(de::<cbor2::tag::AllowAny<u8>>("").is_err());
assert!(de::<Value>("").is_err());
}
#[test]
fn truncated_arguments_and_bodies() {
for hex in [
"18",
"19",
"1a",
"1b",
"1901",
"1a010203",
"1b01020304050607",
] {
assert!(matches!(de::<u64>(hex), Err(Error::Io(..))), "{hex}");
}
assert!(de::<u64>("c2").is_err());
assert!(de::<Value>("c2").is_err());
assert!(de::<serde_bytes::ByteBuf>("42ff").is_err());
assert!(de::<serde_bytes::ByteBuf>("5f").is_err());
assert!(de::<serde_bytes::ByteBuf>("5f4101").is_err());
assert!(de::<String>("7f").is_err());
assert!(de::<String>("7f6161").is_err());
assert!(de::<Vec<u8>>("8201").is_err());
assert!(de::<HashMap<String, u8>>("a16161").is_err());
assert!(de::<Enum>("a1").is_err());
assert!(de::<Enum>("a1674e657774797065").is_err());
assert!(de::<Option<u8>>("c1").is_err());
assert!(de::<()>("c1").is_err());
assert!(de::<Value>("9f01").is_err());
assert!(de::<Value>("bf6161").is_err());
}
#[test]
fn nested_element_errors_propagate() {
assert!(de::<Vec<u64>>("81f5").is_err()); assert!(de::<HashMap<String, u64>>("a16161f5").is_err()); assert!(de::<HashMap<u64, u64>>("a1f501").is_err()); assert!(de::<(u8, bool)>("820102").is_err()); assert!(de::<Enum>("a1674e6577747970656161").is_err()); assert!(de::<Enum>("a1655475706c65820161").is_err()); assert!(de::<Enum>("a166537472756374a1617861").is_err()); assert!(de::<Option<u64>>("f5").is_err()); assert!(de::<cbor2::tag::AllowAny<u64>>("c1f5").is_err()); }
#[test]
fn truncated_bodies_in_every_position() {
assert!(de::<u64>("c241").is_err());
assert!(de::<Vec<u32>>("41").is_err());
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct F {
a: u8,
}
assert!(de::<F>("a161").is_err());
assert!(de::<F>("a141").is_err());
assert!(de::<serde_bytes::ByteBuf>("5f41").is_err());
assert!(de::<Value>("bf").is_err());
assert!(de::<HashMap<String, u8>>("bf").is_err());
assert!(de::<Value>("9f").is_err());
}