use crate::{IdOrdItem, id_ord_map::IdOrdMap};
use core::fmt;
use proptest::{
arbitrary::{Arbitrary, StrategyFor, any_with},
collection::{SizeRange, VecStrategy, VecValueTree},
strategy::{NewTree, Strategy, ValueTree},
test_runner::TestRunner,
};
#[must_use = "strategies do nothing unless used"]
#[derive(Clone)]
pub struct IdOrdMapStrategy<T>
where
T: Strategy,
{
inner: VecStrategy<T>,
}
impl<T> fmt::Debug for IdOrdMapStrategy<T>
where
T: Strategy,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IdOrdMapStrategy")
.field("inner", &self.inner)
.finish_non_exhaustive()
}
}
pub fn prop_strategy<T: Strategy>(
element: T,
size: impl Into<SizeRange>,
) -> IdOrdMapStrategy<T> {
IdOrdMapStrategy { inner: proptest::collection::vec(element, size) }
}
impl<'a, T> Strategy for IdOrdMapStrategy<T>
where
T: Strategy,
T::Value: 'a + IdOrdItem,
<T::Value as IdOrdItem>::Key<'a>: fmt::Debug,
{
type Tree = IdOrdMapValueTree<T::Tree>;
type Value = IdOrdMap<T::Value>;
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
let inner = self.inner.new_tree(runner)?;
Ok(IdOrdMapValueTree { inner })
}
}
#[derive(Clone)]
pub struct IdOrdMapValueTree<T>
where
T: ValueTree,
{
inner: VecValueTree<T>,
}
impl<T> fmt::Debug for IdOrdMapValueTree<T>
where
T: ValueTree + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IdOrdMapValueTree")
.field("inner", &self.inner)
.finish_non_exhaustive()
}
}
impl<'a, T> ValueTree for IdOrdMapValueTree<T>
where
T: ValueTree,
T::Value: 'a + IdOrdItem,
<T::Value as IdOrdItem>::Key<'a>: fmt::Debug,
{
type Value = IdOrdMap<T::Value>;
fn current(&self) -> Self::Value {
let items = self.inner.current();
let mut map = IdOrdMap::new();
for item in items {
map.insert_overwrite(item);
}
map
}
fn simplify(&mut self) -> bool {
self.inner.simplify()
}
fn complicate(&mut self) -> bool {
self.inner.complicate()
}
}
impl<'a, T> Arbitrary for IdOrdMap<T>
where
T: 'a + IdOrdItem + Arbitrary,
<T as IdOrdItem>::Key<'a>: fmt::Debug,
{
type Parameters = (SizeRange, T::Parameters);
type Strategy = IdOrdMapStrategy<StrategyFor<T>>;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
let (size, element_args) = args;
prop_strategy(any_with::<T>(element_args), size)
}
}