use std::collections::{BTreeMap, HashMap};
use cbor2::{cbor, Value};
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Deserialize, Serialize)]
enum Enum {
Unit,
Newtype(u32),
Tuple(u32, u32),
Struct { x: u32 },
}
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Plain {
a: u8,
b: String,
}
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct NewtypeStruct(u8);
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct TupleStruct(u8, bool);
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct UnitStruct;
#[test]
fn serialized_shapes() {
assert_eq!(Value::serialized(&true).unwrap(), Value::Bool(true));
assert_eq!(Value::serialized(&7u8).unwrap(), Value::from(7));
assert_eq!(Value::serialized(&7u16).unwrap(), Value::from(7));
assert_eq!(Value::serialized(&7u32).unwrap(), Value::from(7));
assert_eq!(Value::serialized(&7u64).unwrap(), Value::from(7));
assert_eq!(Value::serialized(&-7i8).unwrap(), Value::from(-7));
assert_eq!(Value::serialized(&-7i16).unwrap(), Value::from(-7));
assert_eq!(Value::serialized(&-7i32).unwrap(), Value::from(-7));
assert_eq!(Value::serialized(&-7i64).unwrap(), Value::from(-7));
assert_eq!(
Value::serialized(&u128::MAX).unwrap(),
Value::from(u128::MAX)
);
assert_eq!(
Value::serialized(&i128::MIN).unwrap(),
Value::from(i128::MIN)
);
assert_eq!(Value::serialized(&1.5f32).unwrap(), Value::Float(1.5));
assert_eq!(Value::serialized(&1.5f64).unwrap(), Value::Float(1.5));
assert_eq!(Value::serialized(&'æ°´').unwrap(), Value::from('æ°´'));
assert_eq!(Value::serialized("hi").unwrap(), Value::from("hi"));
assert_eq!(
Value::serialized(&serde_bytes::ByteBuf::from(vec![1u8])).unwrap(),
Value::Bytes(vec![1])
);
assert_eq!(Value::serialized(&Option::<u8>::None).unwrap(), Value::Null);
assert_eq!(Value::serialized(&Some(1u8)).unwrap(), Value::from(1));
assert_eq!(Value::serialized(&()).unwrap(), Value::Null);
assert_eq!(Value::serialized(&UnitStruct).unwrap(), Value::Null);
assert_eq!(
Value::serialized(&NewtypeStruct(9)).unwrap(),
Value::from(9)
);
assert_eq!(
Value::serialized(&vec![1u8, 2]).unwrap(),
cbor!([1, 2]).unwrap()
);
assert_eq!(
Value::serialized(&(1u8, true)).unwrap(),
Value::Array(vec![Value::from(1), Value::Bool(true)])
);
assert_eq!(
Value::serialized(&TupleStruct(1, true)).unwrap(),
Value::Array(vec![Value::from(1), Value::Bool(true)])
);
let map: BTreeMap<&str, u8> = [("k", 1)].into();
assert_eq!(Value::serialized(&map).unwrap(), cbor!({"k" => 1}).unwrap());
assert_eq!(
Value::serialized(&Plain {
a: 1,
b: "x".into()
})
.unwrap(),
cbor!({"a" => 1, "b" => "x"}).unwrap()
);
assert_eq!(Value::serialized(&Enum::Unit).unwrap(), Value::from("Unit"));
assert_eq!(
Value::serialized(&Enum::Newtype(7)).unwrap(),
cbor!({"Newtype" => 7}).unwrap()
);
assert_eq!(
Value::serialized(&Enum::Tuple(1, 2)).unwrap(),
cbor!({"Tuple" => [1, 2]}).unwrap()
);
assert_eq!(
Value::serialized(&Enum::Struct { x: 7 }).unwrap(),
cbor!({"Struct" => {"x" => 7}}).unwrap()
);
let value = cbor!({ "t" => [1, null] }).unwrap();
assert_eq!(Value::serialized(&value).unwrap(), value);
let tagged = Value::Tag(7, Box::new(Value::from(1)));
assert_eq!(Value::serialized(&tagged).unwrap(), tagged);
}
struct BadTagNumber;
impl Serialize for BadTagNumber {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeTupleVariant;
let mut acc = serializer.serialize_tuple_variant("@@TAG@@", 1, "@@TAGGED@@", 2)?;
acc.serialize_field("not a number")?;
acc.serialize_field(&0u8)?;
acc.end()
}
}
struct HalfATag;
impl Serialize for HalfATag {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeTupleVariant;
let mut acc = serializer.serialize_tuple_variant("@@TAG@@", 1, "@@TAGGED@@", 2)?;
acc.serialize_field(&1u64)?;
acc.end()
}
}
#[test]
fn malformed_tag_protocol_is_rejected() {
let err = Value::serialized(&BadTagNumber).unwrap_err();
assert!(err.to_string().contains("expected tag"));
let err = cbor2::to_vec(&BadTagNumber).unwrap_err();
assert!(err.to_string().contains("expected tag"));
let err = Value::serialized(&HalfATag).unwrap_err();
assert!(err.to_string().contains("invalid tag input"));
}
struct HumanCheck;
impl Serialize for HumanCheck {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
assert!(!serializer.is_human_readable());
serializer.serialize_unit()
}
}
impl<'de> Deserialize<'de> for HumanCheck {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
assert!(!deserializer.is_human_readable());
<()>::deserialize(deserializer)?;
Ok(HumanCheck)
}
}
#[test]
fn binary_format() {
assert_eq!(Value::serialized(&HumanCheck).unwrap(), Value::Null);
let bytes = cbor2::to_vec(&HumanCheck).unwrap();
let _: HumanCheck = cbor2::from_slice(&bytes).unwrap();
let _: HumanCheck = Value::Null.deserialized().unwrap();
}
#[test]
fn deserialized_scalars() {
assert!(Value::Bool(true).deserialized::<bool>().unwrap());
assert!(Value::from(1).deserialized::<bool>().is_err());
let int = Value::from(7);
assert_eq!(int.deserialized::<u8>().unwrap(), 7);
assert_eq!(int.deserialized::<u16>().unwrap(), 7);
assert_eq!(int.deserialized::<u32>().unwrap(), 7);
assert_eq!(int.deserialized::<u64>().unwrap(), 7);
assert_eq!(int.deserialized::<u128>().unwrap(), 7);
let neg = Value::from(-7);
assert_eq!(neg.deserialized::<i8>().unwrap(), -7);
assert_eq!(neg.deserialized::<i16>().unwrap(), -7);
assert_eq!(neg.deserialized::<i32>().unwrap(), -7);
assert_eq!(neg.deserialized::<i64>().unwrap(), -7);
assert_eq!(neg.deserialized::<i128>().unwrap(), -7);
assert!(neg.deserialized::<u8>().is_err());
assert!(Value::from(300).deserialized::<u8>().is_err());
assert!(Value::Null.deserialized::<u8>().is_err());
assert_eq!(Value::Float(1.5).deserialized::<f32>().unwrap(), 1.5);
assert_eq!(Value::Float(1.5).deserialized::<f64>().unwrap(), 1.5);
assert!(Value::from(1).deserialized::<f64>().is_err());
assert_eq!(Value::from("x").deserialized::<char>().unwrap(), 'x');
assert!(Value::from("xy").deserialized::<char>().is_err());
assert!(Value::from("").deserialized::<char>().is_err());
assert!(Value::from(1).deserialized::<char>().is_err());
assert_eq!(Value::from("hi").deserialized::<String>().unwrap(), "hi");
assert!(Value::from(1).deserialized::<String>().is_err());
let bytes = Value::Bytes(vec![1, 2]);
assert_eq!(
bytes
.deserialized::<serde_bytes::ByteBuf>()
.unwrap()
.as_ref(),
&[1, 2]
);
let array = cbor!([1, 2]).unwrap();
assert_eq!(
array
.deserialized::<serde_bytes::ByteBuf>()
.unwrap()
.as_ref(),
&[1, 2]
);
assert!(Value::from(1)
.deserialized::<serde_bytes::ByteBuf>()
.is_err());
}
#[test]
fn deserialized_bignums() {
let big = |bytes: &[u8]| Value::Tag(2, Box::new(Value::Bytes(bytes.to_vec())));
let bigneg = |bytes: &[u8]| Value::Tag(3, Box::new(Value::Bytes(bytes.to_vec())));
assert_eq!(big(&[0, 0, 7]).deserialized::<u8>().unwrap(), 7);
assert_eq!(bigneg(&[7]).deserialized::<i8>().unwrap(), -8);
assert_eq!(
big(&[1; 16]).deserialized::<u128>().unwrap(),
u128::from_be_bytes([1; 16])
);
assert!(big(&[1; 17]).deserialized::<u128>().is_err());
assert!(bigneg(&[1; 17]).deserialized::<i128>().is_err());
assert!(big(&[1; 16]).deserialized::<u8>().is_err());
assert!(bigneg(&[0x80; 16]).deserialized::<i128>().is_err());
assert!(bigneg(&[7]).deserialized::<u8>().is_err());
assert!(bigneg(&[1, 0]).deserialized::<i8>().is_err());
let weird = Value::Tag(2, Box::new(Value::from("x")));
assert!(weird.deserialized::<u64>().is_err());
let other = Value::Tag(7, Box::new(Value::from("x")));
assert!(other.deserialized::<u64>().is_err());
}
#[test]
fn deserialized_collections() {
let array = cbor!([1, 2, 3]).unwrap();
assert_eq!(array.deserialized::<Vec<u8>>().unwrap(), vec![1, 2, 3]);
assert_eq!(array.deserialized::<(u8, u8, u8)>().unwrap(), (1, 2, 3));
assert!(Value::from(1).deserialized::<Vec<u8>>().is_err());
let pair = cbor!([1, true]).unwrap();
assert_eq!(
pair.deserialized::<TupleStruct>().unwrap(),
TupleStruct(1, true)
);
let map = cbor!({"a" => 1, "b" => "x"}).unwrap();
assert_eq!(
map.deserialized::<Plain>().unwrap(),
Plain {
a: 1,
b: "x".into()
}
);
let simple = cbor!({"k" => 1}).unwrap();
assert_eq!(
simple.deserialized::<BTreeMap<String, u8>>().unwrap(),
[("k".to_string(), 1u8)].into()
);
assert_eq!(
simple.deserialized::<HashMap<String, u8>>().unwrap(),
[("k".to_string(), 1u8)].into()
);
assert!(Value::from(1)
.deserialized::<BTreeMap<String, u8>>()
.is_err());
let extra = cbor!({
"a" => 1,
"b" => "x",
"ignored" => { "deep" => [1, 2, {"k" => null}] },
})
.unwrap();
assert_eq!(
extra.deserialized::<Plain>().unwrap(),
Plain {
a: 1,
b: "x".into()
}
);
}
#[test]
fn deserialized_options_and_units() {
assert_eq!(Value::Null.deserialized::<Option<u8>>().unwrap(), None);
assert_eq!(
Value::from(1).deserialized::<Option<u8>>().unwrap(),
Some(1)
);
Value::Null.deserialized::<()>().unwrap();
assert!(Value::from(1).deserialized::<()>().is_err());
Value::Null.deserialized::<UnitStruct>().unwrap();
assert_eq!(
Value::from(9).deserialized::<NewtypeStruct>().unwrap(),
NewtypeStruct(9)
);
}
#[test]
fn deserialized_enums() {
assert_eq!(
Value::from("Unit").deserialized::<Enum>().unwrap(),
Enum::Unit
);
let newtype = cbor!({"Newtype" => 7}).unwrap();
assert_eq!(newtype.deserialized::<Enum>().unwrap(), Enum::Newtype(7));
let tuple = cbor!({"Tuple" => [1, 2]}).unwrap();
assert_eq!(tuple.deserialized::<Enum>().unwrap(), Enum::Tuple(1, 2));
let strukt = cbor!({"Struct" => {"x" => 7}}).unwrap();
assert_eq!(
strukt.deserialized::<Enum>().unwrap(),
Enum::Struct { x: 7 }
);
let unit = cbor!({"Unit" => null}).unwrap();
assert_eq!(unit.deserialized::<Enum>().unwrap(), Enum::Unit);
let tagged = Value::Tag(99, Box::new(newtype));
assert_eq!(tagged.deserialized::<Enum>().unwrap(), Enum::Newtype(7));
assert!(Value::from(1).deserialized::<Enum>().is_err());
let unit_with_payload = cbor!({"Unit" => 5}).unwrap();
assert!(unit_with_payload.deserialized::<Enum>().is_err());
let not_an_array = cbor!({"Tuple" => 5}).unwrap();
assert!(not_an_array.deserialized::<Enum>().is_err());
let not_a_map = cbor!({"Struct" => 5}).unwrap();
assert!(not_a_map.deserialized::<Enum>().is_err());
let two_entries = cbor!({"Newtype" => 7, "Tuple" => [1, 2]}).unwrap();
assert!(two_entries.deserialized::<Enum>().is_err());
}
#[test]
fn deserialized_unwraps_tags_for_scalars() {
let tag = |v: Value| Value::Tag(7, Box::new(v));
assert!(tag(Value::Bool(true)).deserialized::<bool>().unwrap());
assert_eq!(tag(Value::Float(1.5)).deserialized::<f64>().unwrap(), 1.5);
assert_eq!(tag(Value::from("x")).deserialized::<char>().unwrap(), 'x');
assert_eq!(
tag(Value::from("hi")).deserialized::<String>().unwrap(),
"hi"
);
assert_eq!(
tag(Value::Bytes(vec![1]))
.deserialized::<serde_bytes::ByteBuf>()
.unwrap()
.as_ref(),
&[1]
);
assert_eq!(
tag(cbor!([1]).unwrap()).deserialized::<Vec<u8>>().unwrap(),
vec![1]
);
assert_eq!(
tag(cbor!({"k" => 1}).unwrap())
.deserialized::<BTreeMap<String, u8>>()
.unwrap(),
[("k".to_string(), 1u8)].into()
);
}
#[test]
fn deserialized_error_messages_name_the_input() {
let err = |v: &Value| v.deserialized::<bool>().unwrap_err().to_string();
assert!(err(&Value::from(7)).contains('7'));
assert!(err(&Value::from(-7)).contains("-7"));
assert!(err(&Value::from(u64::MAX)).contains("18446744073709551615"));
assert!(err(&Value::from(-(u64::MAX as i128) - 1)).contains("large integer"));
assert!(err(&Value::Float(0.5)).contains("0.5"));
assert!(err(&Value::from("s")).contains('s'));
assert!(err(&Value::Bytes(vec![1])).contains("bool"));
assert!(err(&Value::Array(vec![])).contains("sequence"));
assert!(err(&Value::Map(vec![])).contains("map"));
assert!(Value::Null
.deserialized::<u8>()
.unwrap_err()
.to_string()
.contains("null"));
let tagged = Value::Tag(9, Box::new(Value::Null));
assert!(tagged
.deserialized::<u8>()
.unwrap_err()
.to_string()
.contains("tag"));
assert!(Value::Bool(true)
.deserialized::<String>()
.unwrap_err()
.to_string()
.contains("bool"));
}
#[test]
fn roundtrip_through_value_equals_direct_wire() {
macro_rules! check {
($t:ty, $v:expr) => {{
let v: $t = $v;
let direct = cbor2::to_vec(&v).unwrap();
let through = cbor2::to_vec(&Value::serialized(&v).unwrap()).unwrap();
assert_eq!(direct, through);
let value: Value = cbor2::from_slice(&direct).unwrap();
assert_eq!(value.deserialized::<$t>().unwrap(), v);
}};
}
check!(bool, true);
check!(i32, -300);
check!(u64, u64::MAX);
check!(u128, u128::MAX);
check!(i128, i128::MIN);
check!(f64, 1.5);
check!(String, "æ°´".into());
check!(Vec<u8>, vec![1, 2, 3]);
check!(
Plain,
Plain {
a: 1,
b: "x".into()
}
);
check!(Enum, Enum::Unit);
check!(Enum, Enum::Struct { x: 7 });
check!(Option<u8>, None);
}
#[test]
fn value_identity_through_deserialized() {
let samples = [
Value::Bool(true),
Value::from(7),
Value::from(-7),
Value::from(u64::MAX),
Value::from(-2i128.pow(64)), Value::Float(1.5),
Value::from("hi"),
Value::Bytes(vec![1, 2]),
Value::Null,
Value::Tag(9, Box::new(Value::from(1))),
Value::Array(vec![Value::Null]),
Value::Map(vec![(Value::from(1), Value::Null)]),
];
for value in samples {
assert_eq!(value.deserialized::<Value>().unwrap(), value, "{value:?}");
}
}
#[test]
fn tag_wrappers_from_values() {
use cbor2::tag::AllowAny;
let plain = Value::from(5);
assert_eq!(
plain.deserialized::<AllowAny<u64>>().unwrap(),
AllowAny(None, 5)
);
let tagged = Value::Tag(1, Box::new(Value::from(5)));
assert_eq!(
tagged.deserialized::<AllowAny<u64>>().unwrap(),
AllowAny(Some(1), 5)
);
}
#[test]
fn oversized_bignum_payloads_skip_leading_zeros() {
let mut payload = vec![0u8, 0];
payload.extend_from_slice(&[1; 16]);
let value = Value::Tag(2, Box::new(Value::Bytes(payload)));
assert_eq!(
value.deserialized::<u128>().unwrap(),
u128::from_be_bytes([1; 16])
);
}
struct TagInTagNumber;
impl Serialize for TagInTagNumber {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeTupleVariant;
let mut acc = serializer.serialize_tuple_variant("@@TAG@@", 1, "@@TAGGED@@", 2)?;
acc.serialize_field(&Value::Tag(1, Box::new(Value::Null)))?;
acc.serialize_field(&0u8)?;
acc.end()
}
}
#[test]
fn tag_protocol_rejects_tagged_tag_numbers() {
assert!(Value::serialized(&TagInTagNumber).is_err());
assert!(cbor2::to_vec(&TagInTagNumber).is_err());
}
mod foreign {
use serde::de::value::{Error as DeError, U64Deserializer};
use serde::de::{self, IntoDeserializer};
use serde::forward_to_deserialize_any;
use serde::Deserialize;
use cbor2::Value;
pub enum Mode {
Some,
Unit,
NewtypeStruct,
Nothing,
}
pub struct WeirdDe(pub Mode);
impl<'de> de::Deserializer<'de> for WeirdDe {
type Error = DeError;
fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.0 {
Mode::Some => visitor.visit_some(5u64.into_deserializer()),
Mode::Unit => visitor.visit_unit(),
Mode::NewtypeStruct => {
visitor.visit_newtype_struct(U64Deserializer::<DeError>::new(5))
}
Mode::Nothing => Err(de::Error::invalid_type(
de::Unexpected::Other("nothing"),
&visitor,
)),
}
}
forward_to_deserialize_any! {
i8 i16 i32 i64 i128 u8 u16 u32 u64 u128
bool f32 f64 char str string bytes byte_buf
seq map struct tuple tuple_struct identifier ignored_any
option unit unit_struct newtype_struct enum
}
}
#[test]
fn value_absorbs_unusual_visits() {
assert_eq!(
Value::deserialize(WeirdDe(Mode::Some)).unwrap(),
Value::from(5)
);
assert_eq!(
Value::deserialize(WeirdDe(Mode::Unit)).unwrap(),
Value::Null
);
assert_eq!(
Value::deserialize(WeirdDe(Mode::NewtypeStruct)).unwrap(),
Value::from(5)
);
let msg = Value::deserialize(WeirdDe(Mode::Nothing))
.unwrap_err()
.to_string();
assert!(msg.contains("a valid CBOR item"), "{msg}");
}
}
#[test]
fn every_width_rejects_wrong_input() {
assert!(Value::Null.deserialized::<i8>().is_err());
assert!(Value::Null.deserialized::<i16>().is_err());
assert!(Value::Null.deserialized::<i32>().is_err());
assert!(Value::Null.deserialized::<i64>().is_err());
assert!(Value::Null.deserialized::<i128>().is_err());
assert!(Value::Null.deserialized::<u16>().is_err());
assert!(Value::Null.deserialized::<u32>().is_err());
assert!(Value::Null.deserialized::<u64>().is_err());
assert!(Value::Null.deserialized::<u128>().is_err());
}
#[test]
fn nested_errors_propagate_through_value() {
let array = Value::Array(vec![Value::Null]);
assert!(array.deserialized::<Vec<u8>>().is_err());
let map = cbor!({"k" => null}).unwrap();
assert!(map.deserialized::<BTreeMap<String, u8>>().is_err());
let map = Value::Map(vec![(Value::Null, Value::from(1))]);
assert!(map.deserialized::<BTreeMap<String, u8>>().is_err());
let newtype = cbor!({"Newtype" => null}).unwrap();
assert!(newtype.deserialized::<Enum>().is_err());
let tuple = cbor!({"Tuple" => [1, null]}).unwrap();
assert!(tuple.deserialized::<Enum>().is_err());
let strukt = cbor!({"Struct" => {"x" => null}}).unwrap();
assert!(strukt.deserialized::<Enum>().is_err());
let tagged_garbage = Value::Tag(9, Box::new(Value::from(1)));
assert!(tagged_garbage.deserialized::<Enum>().is_err());
let some_garbage = Value::from("x");
assert!(some_garbage.deserialized::<Option<u8>>().is_err());
}
#[test]
fn unserializable_values_fail_inside_every_container() {
struct Boom;
impl Serialize for Boom {
fn serialize<S: serde::Serializer>(&self, _: S) -> Result<S::Ok, S::Error> {
Err(serde::ser::Error::custom("boom"))
}
}
assert!(Value::serialized(&vec![Boom]).is_err());
assert!(Value::serialized(&(1u8, Boom)).is_err());
struct T(u8, Boom);
impl Serialize for T {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeTupleStruct;
let mut acc = serializer.serialize_tuple_struct("T", 2)?;
acc.serialize_field(&self.0)?;
acc.serialize_field(&self.1)?;
acc.end()
}
}
assert!(Value::serialized(&T(1, Boom)).is_err());
struct BoomKeyMap;
impl Serialize for BoomKeyMap {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut acc = serializer.serialize_map(Some(1))?;
acc.serialize_key(&Boom)?;
acc.serialize_value(&1u8)?;
acc.end()
}
}
assert!(Value::serialized(&BoomKeyMap).is_err());
assert!(Value::serialized(&BTreeMap::from([(1u8, Boom)])).is_err());
struct S {
x: Boom,
}
impl Serialize for S {
fn serialize<S2: serde::Serializer>(&self, serializer: S2) -> Result<S2::Ok, S2::Error> {
use serde::ser::SerializeStruct;
let mut acc = serializer.serialize_struct("S", 1)?;
acc.serialize_field("x", &self.x)?;
acc.end()
}
}
assert!(Value::serialized(&S { x: Boom }).is_err());
enum E {
Newtype(Boom),
Tuple(Boom),
Struct(Boom),
}
impl Serialize for E {
fn serialize<S2: serde::Serializer>(&self, serializer: S2) -> Result<S2::Ok, S2::Error> {
use serde::ser::{SerializeStructVariant, SerializeTupleVariant};
match self {
E::Newtype(b) => serializer.serialize_newtype_variant("E", 0, "N", b),
E::Tuple(b) => {
let mut acc = serializer.serialize_tuple_variant("E", 1, "T", 1)?;
acc.serialize_field(b)?;
acc.end()
}
E::Struct(b) => {
let mut acc = serializer.serialize_struct_variant("E", 2, "S", 1)?;
acc.serialize_field("x", b)?;
acc.end()
}
}
}
}
assert!(Value::serialized(&E::Newtype(Boom)).is_err());
assert!(Value::serialized(&E::Tuple(Boom)).is_err());
assert!(Value::serialized(&E::Struct(Boom)).is_err());
assert!(Value::serialized(&cbor2::tag::AllowAny(Some(1), Boom)).is_err());
assert!(Value::serialized(&cbor2::tag::AllowAny(None, Boom)).is_err());
struct FW;
impl std::io::Write for FW {
fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
Err(std::io::Error::other("x"))
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
assert!(cbor2::to_writer(&Value::Array(vec![]), FW).is_err());
assert!(cbor2::to_writer(&Value::Map(vec![]), FW).is_err());
assert!(cbor2::to_vec(&BoomKeyMap).is_err());
}
#[test]
fn enum_variant_names_must_be_valid() {
assert!(Value::from("Bogus").deserialized::<Enum>().is_err());
assert!(cbor!({"Bogus" => 1})
.unwrap()
.deserialized::<Enum>()
.is_err());
assert!(cbor!({5 => 1}).unwrap().deserialized::<Enum>().is_err());
let map = Value::Map(vec![(Value::Null, Value::from(1))]);
assert!(map.deserialized::<Plain>().is_err());
}
struct ValueWithoutKey;
impl Serialize for ValueWithoutKey {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut acc = serializer.serialize_map(Some(1))?;
acc.serialize_value(&1u8)?;
acc.end()
}
}
#[test]
fn map_value_without_key_is_an_error() {
let err = Value::serialized(&ValueWithoutKey).unwrap_err();
assert!(
err.to_string()
.contains("serialize_value called before serialize_key"),
"{err}"
);
}