use core::marker::PhantomData;
use crate::strategy::*;
use crate::test_runner::*;
#[must_use = "strategies do nothing unless used"]
#[derive(Clone, Copy, Debug)]
pub struct UniformArrayStrategy<S, T> {
strategy: S,
_marker: PhantomData<T>,
}
impl<S, T> UniformArrayStrategy<S, T> {
pub fn new(strategy: S) -> Self {
UniformArrayStrategy {
strategy,
_marker: PhantomData,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct ArrayValueTree<T> {
tree: T,
shrinker: usize,
last_shrinker: Option<usize>,
}
macro_rules! small_array {
($n:tt $uni:ident : $($ix:expr),*) => {
pub fn $uni<S : Strategy>
(strategy: S) -> UniformArrayStrategy<S, [S::Value; $n]>
{
UniformArrayStrategy {
strategy,
_marker: PhantomData
}
}
impl<S : Strategy> Strategy for [S; $n] {
type Tree = ArrayValueTree<[S::Tree; $n]>;
type Value = [S::Value; $n];
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
Ok(ArrayValueTree {
tree: [$(self[$ix].new_tree(runner)?,)*],
shrinker: 0,
last_shrinker: None,
})
}
}
impl<S : Strategy> Strategy
for UniformArrayStrategy<S, [S::Value; $n]> {
type Tree = ArrayValueTree<[S::Tree; $n]>;
type Value = [S::Value; $n];
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
Ok(ArrayValueTree {
tree: [$({
let _ = $ix;
self.strategy.new_tree(runner)?
},)*],
shrinker: 0,
last_shrinker: None,
})
}
}
impl<T : ValueTree> ValueTree for ArrayValueTree<[T;$n]> {
type Value = [T::Value;$n];
fn current(&self) -> [T::Value;$n] {
[$(self.tree[$ix].current(),)*]
}
fn simplify(&mut self) -> bool {
while self.shrinker < $n {
if self.tree[self.shrinker].simplify() {
self.last_shrinker = Some(self.shrinker);
return true;
} else {
self.shrinker += 1;
}
}
false
}
fn complicate(&mut self) -> bool {
if let Some(shrinker) = self.last_shrinker {
self.shrinker = shrinker;
if self.tree[shrinker].complicate() {
true
} else {
self.last_shrinker = None;
false
}
} else {
false
}
}
}
}
}
small_array!(1 uniform1:
0);
small_array!(2 uniform2:
0, 1);
small_array!(3 uniform3:
0, 1, 2);
small_array!(4 uniform4:
0, 1, 2, 3);
small_array!(5 uniform5:
0, 1, 2, 3, 4);
small_array!(6 uniform6:
0, 1, 2, 3, 4, 5);
small_array!(7 uniform7:
0, 1, 2, 3, 4, 5, 6);
small_array!(8 uniform8:
0, 1, 2, 3, 4, 5, 6, 7);
small_array!(9 uniform9:
0, 1, 2, 3, 4, 5, 6, 7, 8);
small_array!(10 uniform10:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
small_array!(11 uniform11:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
small_array!(12 uniform12:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
small_array!(13 uniform13:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
small_array!(14 uniform14:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
small_array!(15 uniform15:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
small_array!(16 uniform16:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
small_array!(17 uniform17:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
small_array!(18 uniform18:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
small_array!(19 uniform19:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18);
small_array!(20 uniform20:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19);
small_array!(21 uniform21:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20);
small_array!(22 uniform22:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21);
small_array!(23 uniform23:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22);
small_array!(24 uniform24:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23);
small_array!(25 uniform25:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24);
small_array!(26 uniform26:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25);
small_array!(27 uniform27:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26);
small_array!(28 uniform28:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27);
small_array!(29 uniform29:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28);
small_array!(30 uniform30:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29);
small_array!(31 uniform31:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30);
small_array!(32 uniform32:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn shrinks_fully_ltr() {
fn pass(a: [i32; 2]) -> bool {
a[0] * a[1] <= 9
}
let input = [0..32, 0..32];
let mut runner = TestRunner::deterministic();
let mut cases_tested = 0;
for _ in 0..256 {
let mut case = input.new_tree(&mut runner).unwrap();
if pass(case.current()) {
continue;
}
loop {
if pass(case.current()) {
if !case.complicate() {
break;
}
} else {
if !case.simplify() {
break;
}
}
}
let last = case.current();
assert!(!pass(last));
assert!(pass([last[0] - 1, last[1]]));
assert!(pass([last[0], last[1] - 1]));
cases_tested += 1;
}
assert!(cases_tested > 32, "Didn't find enough test cases");
}
#[test]
fn test_sanity() {
check_strategy_sanity([(0i32..1000), (1i32..1000)], None);
}
}