#![cfg(not(miri))]
use std::{
cell::{Cell, RefCell},
collections::{BTreeMap, HashMap, HashSet},
num::NonZeroUsize,
};
use proptest::{
prelude::{Strategy, any},
proptest,
};
use proptest_derive::Arbitrary;
use tinycbor::{
CborLen, Decode, Decoder, Encode, Encoded, encoded,
num::Int,
primitive::{Null, Simple, Undefined},
};
use tinycbor_derive::{CborLen, Decode, Encode};
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(naked, error = "TagOnlyError", tag(45))]
enum TagOnly {
#[n(0)]
First,
#[n(17)]
Second,
#[n(4)]
Third,
#[n(5)]
Fourth,
#[n(100)]
Fifth,
#[cbor(n(1025))]
Sixth,
#[n(200000)]
Seventh,
#[n(99999999)]
Eighth,
#[n(99999999999)]
Ninth,
}
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(error = "EmptyArrayError")]
struct EmptyArray;
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(map, error = "EmptyMapError")]
struct EmptyMap;
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(error = "PartAError", tag(1001))]
struct PartA {
#[proptest(value = "Null")]
a: Null,
b: u32,
c: String,
d: Vec<u8>,
#[cbor(tag(42))]
e: RefCell<Box<[u8]>>,
f: EmptyArray,
g: EmptyMap,
}
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(error = "PartBError", map, tag(2001))]
struct PartB {
#[n(1)]
#[proptest(value = "Undefined")]
a: Undefined,
#[cbor(n(14445), optional)]
#[proptest(strategy = "simple_strategy()")]
b: Option<Simple>,
#[n(3)]
c: std::num::Wrapping<i64>,
#[cbor(n(45), tag(45))]
#[proptest(strategy = "int_strategy()")]
d: Int,
#[cbor(n(5), tag(99), with = "tinycbor::num::U8")]
e: u8,
}
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(error = "PartCError", map)]
struct PartC {
#[n(10101010)]
a: Box<PartA>,
#[cbor(n(20202020), tag(202))]
b: RefCell<NonZeroUsize>,
#[n(30303030)]
c: Cell<u64>,
#[n(40404040)]
d: HashMap<u32, String>,
#[n(50505050)]
e: Box<[u8]>,
}
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(error = "PartDError")]
enum PartD {
#[n(0)]
VariantA {
a: HashSet<i16>,
#[cbor(tag(12))]
b: f32,
},
#[n(1)]
VariantB(BTreeMap<String, usize>, [u8; 16]),
#[n(2)]
VariantC,
}
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
#[cbor(error = "PartEError")]
#[cbor(
decode_bound = "T: Decode<'_>",
encode_bound = "T: Encode",
len_bound = "T: CborLen"
)]
struct PartE<T, const N: usize>([T; N]);
#[derive(Debug, Encode, Decode, CborLen, Arbitrary, PartialEq)]
struct Complete {
#[cbor(with = "Encoded<PartA>")]
a: PartA,
b: PartB,
c: PartC,
d: PartD,
e: PartE<PartD, 3>,
tag: TagOnly,
}
fn int_strategy() -> impl Strategy<Value = Int> {
(proptest::num::u64::ANY, proptest::bool::ANY)
.prop_map(|(bits, negative)| Int { negative, bits })
}
fn simple_strategy() -> impl Strategy<Value = Option<Simple>> {
proptest::option::of(
(0u8..=19)
.prop_union(32..=255)
.prop_map(|b| Simple::try_from(b).unwrap()),
)
}
proptest! {
#![proptest_config(config())]
#[test]
fn roundtrip(value in any::<Complete>()) {
let len = value.cbor_len();
let buf = tinycbor::to_vec(&value);
assert_eq!(buf.len(), len);
let decoded: Complete = Decode::decode(&mut Decoder(&buf)).unwrap();
assert_eq!(value, decoded);
}
}
fn config() -> proptest::test_runner::Config {
proptest::test_runner::Config {
cases: 500,
failure_persistence: None,
..proptest::test_runner::Config::default()
}
}