use arbitrary;
use proptest;
use core::fmt::Debug;
use proptest::prelude::RngCore;
use proptest::test_runner::TestRunner;
use std::marker::PhantomData;
pub trait ArbInterop: for<'a> arbitrary::Arbitrary<'a> + 'static + Debug + Clone {}
impl<A: for<'a> arbitrary::Arbitrary<'a> + 'static + Debug + Clone> ArbInterop for A {}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct ArbStrategy<A: ArbInterop> {
__ph: PhantomData<A>,
size: usize,
}
#[derive(Debug)]
pub struct ArbValueTree<A: Debug> {
bytes: Vec<u8>,
curr: A,
prev: Option<A>,
next: usize,
}
impl<A: ArbInterop> proptest::strategy::ValueTree for ArbValueTree<A> {
type Value = A;
fn current(&self) -> Self::Value {
self.curr.clone()
}
fn complicate(&mut self) -> bool {
if let Some(prev) = self.prev.take() {
self.curr = prev;
true
} else {
false
}
}
fn simplify(&mut self) -> bool {
if self.next == 0 {
return false;
}
self.next -= 1;
if let Ok(simpler) = Self::gen_one_with_size(&self.bytes, self.next) {
self.prev = Some(core::mem::replace(&mut self.curr, simpler));
true
} else {
false
}
}
}
impl<A: ArbInterop> ArbStrategy<A> {
pub fn new(size: usize) -> Self {
Self {
__ph: PhantomData,
size,
}
}
}
impl<A: ArbInterop> ArbValueTree<A> {
fn gen_one_with_size(bytes: &[u8], size: usize) -> Result<A, arbitrary::Error> {
let mut unstructured = arbitrary::Unstructured::new(&bytes[0..size]);
A::arbitrary(&mut unstructured)
}
pub fn new(bytes: Vec<u8>) -> Result<Self, arbitrary::Error> {
let next = bytes.len();
let curr = Self::gen_one_with_size(&bytes, next)?;
Ok(Self {
bytes,
prev: None,
curr,
next,
})
}
}
impl<A: ArbInterop> proptest::strategy::Strategy for ArbStrategy<A> {
type Tree = ArbValueTree<A>;
type Value = A;
fn new_tree(&self, runner: &mut TestRunner) -> proptest::strategy::NewTree<Self> {
let mut bytes = std::iter::repeat(0u8).take(self.size).collect::<Vec<u8>>();
runner.rng().fill_bytes(&mut bytes);
ArbValueTree::new(bytes).map_err(|_| "initial arbitrary call failed".into())
}
}
pub fn arb_sized<A: ArbInterop>(size: usize) -> ArbStrategy<A> {
ArbStrategy::new(size)
}
pub const DEFAULT_SIZE: usize = 256;
pub fn arb<A: ArbInterop>() -> ArbStrategy<A> {
arb_sized(DEFAULT_SIZE)
}