1use core::marker::PhantomData;
22
23use crate::strategy::*;
24use crate::test_runner::*;
25
26#[must_use = "strategies do nothing unless used"]
52#[derive(Clone, Copy, Debug)]
53pub struct UniformArrayStrategy<S, T> {
54 strategy: S,
55 _marker: PhantomData<T>,
56}
57
58impl<S, T> UniformArrayStrategy<S, T> {
59 pub fn new(strategy: S) -> Self {
68 UniformArrayStrategy {
69 strategy,
70 _marker: PhantomData,
71 }
72 }
73}
74
75#[derive(Clone, Copy, Debug)]
77pub struct ArrayValueTree<T> {
78 tree: T,
79 shrinker: usize,
80 last_shrinker: Option<usize>,
81}
82
83pub fn uniform<S: Strategy, const N: usize>(
91 strategy: S,
92) -> UniformArrayStrategy<S, [S::Value; N]> {
93 UniformArrayStrategy {
94 strategy,
95 _marker: PhantomData,
96 }
97}
98
99macro_rules! small_array {
100 ($n:tt $uni:ident) => {
101 pub fn $uni<S: Strategy>(
110 strategy: S,
111 ) -> UniformArrayStrategy<S, [S::Value; $n]> {
112 UniformArrayStrategy {
113 strategy,
114 _marker: PhantomData,
115 }
116 }
117 };
118}
119
120impl<S: Strategy, const N: usize> Strategy for [S; N] {
121 type Tree = ArrayValueTree<[S::Tree; N]>;
122 type Value = [S::Value; N];
123
124 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
125 Ok(ArrayValueTree {
126 tree: unarray::build_array_result(|i| self[i].new_tree(runner))?,
127 shrinker: 0,
128 last_shrinker: None,
129 })
130 }
131}
132impl<S: Strategy, const N: usize> Strategy
133 for UniformArrayStrategy<S, [S::Value; N]>
134{
135 type Tree = ArrayValueTree<[S::Tree; N]>;
136 type Value = [S::Value; N];
137
138 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
139 Ok(ArrayValueTree {
140 tree: unarray::build_array_result(|_| {
141 self.strategy.new_tree(runner)
142 })?,
143 shrinker: 0,
144 last_shrinker: None,
145 })
146 }
147}
148impl<T: ValueTree, const N: usize> ValueTree for ArrayValueTree<[T; N]> {
149 type Value = [T::Value; N];
150
151 fn current(&self) -> [T::Value; N] {
152 core::array::from_fn(|i| self.tree[i].current())
153 }
154
155 fn simplify(&mut self) -> bool {
156 while self.shrinker < N {
157 if self.tree[self.shrinker].simplify() {
158 self.last_shrinker = Some(self.shrinker);
159 return true;
160 } else {
161 self.shrinker += 1;
162 }
163 }
164 false
165 }
166
167 fn complicate(&mut self) -> bool {
168 if let Some(shrinker) = self.last_shrinker {
169 self.shrinker = shrinker;
170 if self.tree[shrinker].complicate() {
171 true
172 } else {
173 self.last_shrinker = None;
174 false
175 }
176 } else {
177 false
178 }
179 }
180}
181
182small_array!(1 uniform1);
183small_array!(2 uniform2);
184small_array!(3 uniform3);
185small_array!(4 uniform4);
186small_array!(5 uniform5);
187small_array!(6 uniform6);
188small_array!(7 uniform7);
189small_array!(8 uniform8);
190small_array!(9 uniform9);
191small_array!(10 uniform10);
192small_array!(11 uniform11);
193small_array!(12 uniform12);
194small_array!(13 uniform13);
195small_array!(14 uniform14);
196small_array!(15 uniform15);
197small_array!(16 uniform16);
198small_array!(17 uniform17);
199small_array!(18 uniform18);
200small_array!(19 uniform19);
201small_array!(20 uniform20);
202small_array!(21 uniform21);
203small_array!(22 uniform22);
204small_array!(23 uniform23);
205small_array!(24 uniform24);
206small_array!(25 uniform25);
207small_array!(26 uniform26);
208small_array!(27 uniform27);
209small_array!(28 uniform28);
210small_array!(29 uniform29);
211small_array!(30 uniform30);
212small_array!(31 uniform31);
213small_array!(32 uniform32);
214
215#[cfg(test)]
216mod test {
217 use super::*;
218
219 #[test]
220 fn shrinks_fully_ltr() {
221 fn pass(a: [i32; 2]) -> bool {
222 a[0] * a[1] <= 9
223 }
224
225 let input = [0..32, 0..32];
226 let mut runner = TestRunner::deterministic();
227
228 let mut cases_tested = 0;
229 for _ in 0..256 {
230 let mut case = input.new_tree(&mut runner).unwrap();
232 if pass(case.current()) {
233 continue;
234 }
235
236 loop {
237 if pass(case.current()) {
238 if !case.complicate() {
239 break;
240 }
241 } else {
242 if !case.simplify() {
243 break;
244 }
245 }
246 }
247
248 let last = case.current();
249 assert!(!pass(last));
250 assert!(pass([last[0] - 1, last[1]]));
252 assert!(pass([last[0], last[1] - 1]));
253
254 cases_tested += 1;
255 }
256
257 assert!(cases_tested > 32, "Didn't find enough test cases");
258 }
259
260 #[test]
261 fn test_sanity() {
262 check_strategy_sanity([(0i32..1000), (1i32..1000)], None);
263 }
264}