use serde::Serialize;
fn ok(hex: &str) {
let bytes = hex::decode(hex).unwrap();
assert!(cbor2::validate(&bytes[..]).is_ok(), "{hex} must validate");
}
fn bad(hex: &str) {
let bytes = hex::decode(hex).unwrap();
assert!(
cbor2::validate(&bytes[..]).is_err(),
"{hex} must be rejected"
);
}
#[test]
fn everything_we_encode_validates() {
fn check<T: ?Sized + Serialize>(value: &T) {
let bytes = cbor2::to_vec(value).unwrap();
assert!(cbor2::validate(&bytes[..]).is_ok());
}
check(&true);
check(&u64::MAX);
check(&i64::MIN);
check(&u128::MAX);
check(&i128::MIN);
check(&1.5f64);
check(&f64::NAN);
check(&'水');
check(&"hello, world");
check(&serde_bytes::ByteBuf::from(vec![0xab; 300]));
check(&Option::<u8>::None);
check(&(0..100).collect::<Vec<u64>>());
check(&std::collections::BTreeMap::from([("k", 1u8), ("v", 2)]));
check(&cbor2::tag::AllowAny(Some(99), "tagged"));
check(&cbor2::cbor!({ "a" => [1, {"b" => null}], 2 => true }).unwrap());
}
#[test]
fn rfc_vectors_validate() {
for hex in [
"00",
"1bffffffffffffffff",
"3bffffffffffffffff",
"c249010000000000000000",
"f90000",
"fb3ff199999999999a",
"f97c00",
"f4",
"f6",
"f7",
"c074323031332d30332d32315432303a30343a30305a",
"d74401020304",
"64f0908591",
"83018202039f0405ff",
"9f018202039f0405ffff",
"5f42010243030405ff",
"7f657374726561646d696e67ff",
"bf61610161629f0203ffff",
"a26161016162820203",
"80",
"a0",
"9fff",
"bfff",
] {
ok(hex);
}
ok("f0");
ok("f8ff");
}
#[test]
fn malformed_input_is_rejected() {
bad("");
for hex in [
"18", "19", "1a", "1b", "61", "41", "5f", "5f41", "7f", "7f6161", "9f", "bf", "bf01", "a1",
"a16161", "81", "c2", "8201", "9f01", "62c3",
] {
bad(hex);
}
for hex in ["1c", "1d", "1e", "fc", "f800", "f81f", "1f", "3f", "df"] {
bad(hex);
}
bad("ff"); bad("81ff"); bad("a1ff"); bad("bf6161ff"); bad("bf62fffeff"); bad("c2ff");
bad("5f6161ff"); bad("7f4161ff"); bad("5f5f4101ffff"); bad("5f00ff");
bad("62fffe");
bad("7f62fffeff");
bad("7f61e261829461acff");
bad("0001");
bad("f6f6");
bad("5bffffffffffffffff");
bad("7bffffffffffffffff");
bad("9bffffffffffffffff");
bad("bbffffffffffffffff");
}
#[test]
fn nesting_is_depth_limited() {
let mut array_bomb = vec![0x81u8; 65536];
*array_bomb.last_mut().unwrap() = 0x01;
assert!(matches!(
cbor2::validate(&array_bomb[..]),
Err(cbor2::de::Error::RecursionLimitExceeded)
));
let mut tag_bomb = vec![0xc1u8; 65536];
*tag_bomb.last_mut().unwrap() = 0x01;
assert!(matches!(
cbor2::validate(&tag_bomb[..]),
Err(cbor2::de::Error::RecursionLimitExceeded)
));
let mut mixed = vec![0x9fu8; 65536];
*mixed.last_mut().unwrap() = 0x01;
assert!(matches!(
cbor2::validate(&mixed[..]),
Err(cbor2::de::Error::RecursionLimitExceeded)
));
}
#[test]
fn utf8_across_chunk_boundaries() {
for prefix_len in [4094usize, 4095, 4096] {
let mut text = "a".repeat(prefix_len);
text.push_str("水水");
let bytes = cbor2::to_vec(&text).unwrap();
assert!(cbor2::validate(&bytes[..]).is_ok(), "prefix {prefix_len}");
}
let mut body = vec![0x61u8; 5000];
body[4500] = 0xff;
let mut bytes = vec![0x7a, 0x00, 0x00, 0x13, 0x88]; bytes.extend_from_slice(&body);
assert!(cbor2::validate(&bytes[..]).is_err());
let mut bytes = vec![0x7a, 0x00, 0x00, 0x13, 0x88];
let mut body = vec![0x61u8; 4999];
body.push(0xc3); bytes.extend_from_slice(&body);
assert!(cbor2::validate(&bytes[..]).is_err());
}
#[test]
fn io_errors_propagate() {
use std::io::Read;
struct FailReader;
impl Read for FailReader {
fn read(&mut self, _: &mut [u8]) -> std::io::Result<usize> {
Err(std::io::Error::other("source broke"))
}
}
assert!(matches!(
cbor2::validate(FailReader),
Err(cbor2::de::Error::Io(..))
));
let reader = (&[0x01u8][..]).chain(FailReader);
assert!(matches!(
cbor2::validate(reader),
Err(cbor2::de::Error::Io(..))
));
}