proptest/
collection.rs

1//-
2// Copyright 2017, 2018 The proptest developers
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Strategies for generating `std::collections` of values.
11
12use core::cmp::Ord;
13use core::hash::Hash;
14use core::ops::{Add, Range, RangeInclusive, RangeTo, RangeToInclusive};
15use core::usize;
16
17use crate::std_facade::{
18    fmt, BTreeMap, BTreeSet, BinaryHeap, LinkedList, Vec, VecDeque,
19};
20
21#[cfg(feature = "std")]
22use crate::std_facade::{HashMap, HashSet};
23
24use crate::bits::{BitSetLike, VarBitSet};
25use crate::num::sample_uniform_incl;
26use crate::strategy::*;
27use crate::test_runner::*;
28use crate::tuple::TupleValueTree;
29
30//==============================================================================
31// SizeRange
32//==============================================================================
33
34/// The minimum and maximum range/bounds on the size of a collection.
35/// The interval must form a subset of `[0, std::usize::MAX)`.
36///
37/// A value like `0..=std::usize::MAX` will still be accepted but will silently
38/// truncate the maximum to `std::usize::MAX - 1`.
39///
40/// The `Default` is `0..PROPTEST_MAX_DEFAULT_SIZE_RANGE`. The max can be set with
41/// the `PROPTEST_MAX_DEFAULT_SIZE_RANGE` env var, which defaults to `100`.
42#[derive(Clone, PartialEq, Eq, Hash, Debug)]
43pub struct SizeRange(Range<usize>);
44
45/// Creates a `SizeRange` from some value that is convertible into it.
46pub fn size_range(from: impl Into<SizeRange>) -> SizeRange {
47    from.into()
48}
49
50impl Default for SizeRange {
51    /// Constructs a `SizeRange` equivalent to `size_range(0..PROPTEST_MAX_DEFAULT_SIZE_RANGE)`.
52    /// The max can be set with the `PROPTEST_MAX_DEFAULT_SIZE_RANGE` env var, which defaults to `100`.
53    fn default() -> Self {
54        size_range(0..Config::default().max_default_size_range)
55    }
56}
57
58impl SizeRange {
59    /// Creates a `SizeBounds` from a `RangeInclusive<usize>`.
60    pub fn new(range: RangeInclusive<usize>) -> Self {
61        range.into()
62    }
63
64    // Don't rely on these existing internally:
65
66    /// Merges self together with some other argument producing a product
67    /// type expected by some implementations of `A: Arbitrary` in
68    /// `A::Parameters`. This can be more ergonomic to work with and may
69    /// help type inference.
70    pub fn with<X>(self, and: X) -> product_type![Self, X] {
71        product_pack![self, and]
72    }
73
74    /// Merges self together with some other argument generated with a
75    /// default value producing a product type expected by some
76    /// implementations of `A: Arbitrary` in `A::Parameters`.
77    /// This can be more ergonomic to work with and may help type inference.
78    pub fn lift<X: Default>(self) -> product_type![Self, X] {
79        self.with(Default::default())
80    }
81
82    /// The lower bound of the range (inclusive).
83    pub fn start(&self) -> usize {
84        self.0.start
85    }
86
87    /// Extract the ends `[low, high]` of a `SizeRange`.
88    pub fn start_end_incl(&self) -> (usize, usize) {
89        (self.start(), self.end_incl())
90    }
91
92    /// The upper bound of the range (inclusive).
93    pub fn end_incl(&self) -> usize {
94        self.0.end - 1
95    }
96
97    /// The upper bound of the range (exclusive).
98    pub fn end_excl(&self) -> usize {
99        self.0.end
100    }
101
102    pub(crate) fn iter(&self) -> impl Iterator<Item = usize> {
103        self.0.clone().into_iter()
104    }
105
106    pub(crate) fn is_empty(&self) -> bool {
107        self.start() == self.end_excl()
108    }
109
110    pub(crate) fn assert_nonempty(&self) {
111        if self.is_empty() {
112            panic!(
113                "Invalid use of empty size range. (hint: did you \
114                 accidentally write {}..{} where you meant {}..={} \
115                 somewhere?)",
116                self.start(),
117                self.end_excl(),
118                self.start(),
119                self.end_excl()
120            );
121        }
122    }
123}
124
125/// Given `(low: usize, high: usize)`,
126/// then a size range of `[low..high)` is the result.
127impl From<(usize, usize)> for SizeRange {
128    fn from((low, high): (usize, usize)) -> Self {
129        size_range(low..high)
130    }
131}
132
133/// Given `exact`, then a size range of `[exact, exact]` is the result.
134impl From<usize> for SizeRange {
135    fn from(exact: usize) -> Self {
136        size_range(exact..=exact)
137    }
138}
139
140/// Given `..high`, then a size range `[0, high)` is the result.
141impl From<RangeTo<usize>> for SizeRange {
142    fn from(high: RangeTo<usize>) -> Self {
143        size_range(0..high.end)
144    }
145}
146
147/// Given `low .. high`, then a size range `[low, high)` is the result.
148impl From<Range<usize>> for SizeRange {
149    fn from(r: Range<usize>) -> Self {
150        SizeRange(r)
151    }
152}
153
154/// Given `low ..= high`, then a size range `[low, high]` is the result.
155impl From<RangeInclusive<usize>> for SizeRange {
156    fn from(r: RangeInclusive<usize>) -> Self {
157        size_range(*r.start()..r.end().saturating_add(1))
158    }
159}
160
161/// Given `..=high`, then a size range `[0, high]` is the result.
162impl From<RangeToInclusive<usize>> for SizeRange {
163    fn from(high: RangeToInclusive<usize>) -> Self {
164        size_range(0..=high.end)
165    }
166}
167
168impl From<SizeRange> for Range<usize> {
169    fn from(size_range: SizeRange) -> Self {
170        size_range.0
171    }
172}
173
174/// Adds `usize` to both start and end of the bounds.
175///
176/// Panics if adding to either end overflows `usize`.
177impl Add<usize> for SizeRange {
178    type Output = SizeRange;
179
180    fn add(self, rhs: usize) -> Self::Output {
181        let (start, end) = self.start_end_incl();
182        size_range((start + rhs)..=(end + rhs))
183    }
184}
185
186//==============================================================================
187// Strategies
188//==============================================================================
189
190/// Strategy to create `Vec`s with a length in a certain range.
191///
192/// Created by the `vec()` function in the same module.
193#[must_use = "strategies do nothing unless used"]
194#[derive(Clone, Debug)]
195pub struct VecStrategy<T: Strategy> {
196    element: T,
197    size: SizeRange,
198}
199
200/// Create a strategy to generate `Vec`s containing elements drawn from
201/// `element` and with a size range given by `size`.
202///
203/// To make a `Vec` with a fixed number of elements, each with its own
204/// strategy, you can instead make a `Vec` of strategies (boxed if necessary).
205pub fn vec<T: Strategy>(
206    element: T,
207    size: impl Into<SizeRange>,
208) -> VecStrategy<T> {
209    let size = size.into();
210    size.assert_nonempty();
211    VecStrategy { element, size }
212}
213
214mapfn! {
215    [] fn VecToDeque[<T : fmt::Debug>](vec: Vec<T>) -> VecDeque<T> {
216        vec.into()
217    }
218}
219
220opaque_strategy_wrapper! {
221    /// Strategy to create `VecDeque`s with a length in a certain range.
222    ///
223    /// Created by the `vec_deque()` function in the same module.
224    #[derive(Clone, Debug)]
225    pub struct VecDequeStrategy[<T>][where T : Strategy](
226        statics::Map<VecStrategy<T>, VecToDeque>)
227        -> VecDequeValueTree<T::Tree>;
228    /// `ValueTree` corresponding to `VecDequeStrategy`.
229    #[derive(Clone, Debug)]
230    pub struct VecDequeValueTree[<T>][where T : ValueTree](
231        statics::Map<VecValueTree<T>, VecToDeque>)
232        -> VecDeque<T::Value>;
233}
234
235/// Create a strategy to generate `VecDeque`s containing elements drawn from
236/// `element` and with a size range given by `size`.
237pub fn vec_deque<T: Strategy>(
238    element: T,
239    size: impl Into<SizeRange>,
240) -> VecDequeStrategy<T> {
241    VecDequeStrategy(statics::Map::new(vec(element, size), VecToDeque))
242}
243
244mapfn! {
245    [] fn VecToLl[<T : fmt::Debug>](vec: Vec<T>) -> LinkedList<T> {
246        vec.into_iter().collect()
247    }
248}
249
250opaque_strategy_wrapper! {
251    /// Strategy to create `LinkedList`s with a length in a certain range.
252    ///
253    /// Created by the `linkedlist()` function in the same module.
254    #[derive(Clone, Debug)]
255    pub struct LinkedListStrategy[<T>][where T : Strategy](
256        statics::Map<VecStrategy<T>, VecToLl>)
257        -> LinkedListValueTree<T::Tree>;
258    /// `ValueTree` corresponding to `LinkedListStrategy`.
259    #[derive(Clone, Debug)]
260    pub struct LinkedListValueTree[<T>][where T : ValueTree](
261        statics::Map<VecValueTree<T>, VecToLl>)
262        -> LinkedList<T::Value>;
263}
264
265/// Create a strategy to generate `LinkedList`s containing elements drawn from
266/// `element` and with a size range given by `size`.
267pub fn linked_list<T: Strategy>(
268    element: T,
269    size: impl Into<SizeRange>,
270) -> LinkedListStrategy<T> {
271    LinkedListStrategy(statics::Map::new(vec(element, size), VecToLl))
272}
273
274mapfn! {
275    [] fn VecToBinHeap[<T : fmt::Debug + Ord>](vec: Vec<T>) -> BinaryHeap<T> {
276        vec.into()
277    }
278}
279
280opaque_strategy_wrapper! {
281    /// Strategy to create `BinaryHeap`s with a length in a certain range.
282    ///
283    /// Created by the `binary_heap()` function in the same module.
284    #[derive(Clone, Debug)]
285    pub struct BinaryHeapStrategy[<T>][where T : Strategy, T::Value : Ord](
286        statics::Map<VecStrategy<T>, VecToBinHeap>)
287        -> BinaryHeapValueTree<T::Tree>;
288    /// `ValueTree` corresponding to `BinaryHeapStrategy`.
289    #[derive(Clone, Debug)]
290    pub struct BinaryHeapValueTree[<T>][where T : ValueTree, T::Value : Ord](
291        statics::Map<VecValueTree<T>, VecToBinHeap>)
292        -> BinaryHeap<T::Value>;
293}
294
295/// Create a strategy to generate `BinaryHeap`s containing elements drawn from
296/// `element` and with a size range given by `size`.
297pub fn binary_heap<T: Strategy>(
298    element: T,
299    size: impl Into<SizeRange>,
300) -> BinaryHeapStrategy<T>
301where
302    T::Value: Ord,
303{
304    BinaryHeapStrategy(statics::Map::new(vec(element, size), VecToBinHeap))
305}
306
307mapfn! {
308    {#[cfg(feature = "std")]}
309    [] fn VecToHashSet[<T : fmt::Debug + Hash + Eq>](vec: Vec<T>)
310                                                     -> HashSet<T> {
311        vec.into_iter().collect()
312    }
313}
314
315#[derive(Debug, Clone, Copy)]
316struct MinSize(usize);
317
318#[cfg(feature = "std")]
319impl<T: Eq + Hash> statics::FilterFn<HashSet<T>> for MinSize {
320    fn apply(&self, set: &HashSet<T>) -> bool {
321        set.len() >= self.0
322    }
323}
324
325opaque_strategy_wrapper! {
326    {#[cfg(feature = "std")]}
327    {#[cfg_attr(docsrs, doc(cfg(feature = "std")))]}
328    /// Strategy to create `HashSet`s with a length in a certain range.
329    ///
330    /// Created by the `hash_set()` function in the same module.
331    #[derive(Clone, Debug)]
332    pub struct HashSetStrategy[<T>][where T : Strategy, T::Value : Hash + Eq](
333        statics::Filter<statics::Map<VecStrategy<T>, VecToHashSet>, MinSize>)
334        -> HashSetValueTree<T::Tree>;
335    /// `ValueTree` corresponding to `HashSetStrategy`.
336    #[derive(Clone, Debug)]
337    pub struct HashSetValueTree[<T>][where T : ValueTree, T::Value : Hash + Eq](
338        statics::Filter<statics::Map<VecValueTree<T>, VecToHashSet>, MinSize>)
339        -> HashSet<T::Value>;
340}
341
342/// Create a strategy to generate `HashSet`s containing elements drawn from
343/// `element` and with a size range given by `size`.
344///
345/// This strategy will implicitly do local rejects to ensure that the `HashSet`
346/// has at least the minimum number of elements, in case `element` should
347/// produce duplicate values.
348#[cfg(feature = "std")]
349#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
350pub fn hash_set<T: Strategy>(
351    element: T,
352    size: impl Into<SizeRange>,
353) -> HashSetStrategy<T>
354where
355    T::Value: Hash + Eq,
356{
357    let size = size.into();
358    HashSetStrategy(statics::Filter::new(
359        statics::Map::new(vec(element, size.clone()), VecToHashSet),
360        "HashSet minimum size".into(),
361        MinSize(size.start()),
362    ))
363}
364
365mapfn! {
366    [] fn VecToBTreeSet[<T : fmt::Debug + Ord>](vec: Vec<T>)
367                                                -> BTreeSet<T> {
368        vec.into_iter().collect()
369    }
370}
371
372impl<T: Ord> statics::FilterFn<BTreeSet<T>> for MinSize {
373    fn apply(&self, set: &BTreeSet<T>) -> bool {
374        set.len() >= self.0
375    }
376}
377
378opaque_strategy_wrapper! {
379    /// Strategy to create `BTreeSet`s with a length in a certain range.
380    ///
381    /// Created by the `btree_set()` function in the same module.
382    #[derive(Clone, Debug)]
383    pub struct BTreeSetStrategy[<T>][where T : Strategy, T::Value : Ord](
384        statics::Filter<statics::Map<VecStrategy<T>, VecToBTreeSet>, MinSize>)
385        -> BTreeSetValueTree<T::Tree>;
386    /// `ValueTree` corresponding to `BTreeSetStrategy`.
387    #[derive(Clone, Debug)]
388    pub struct BTreeSetValueTree[<T>][where T : ValueTree, T::Value : Ord](
389        statics::Filter<statics::Map<VecValueTree<T>, VecToBTreeSet>, MinSize>)
390        -> BTreeSet<T::Value>;
391}
392
393/// Create a strategy to generate `BTreeSet`s containing elements drawn from
394/// `element` and with a size range given by `size`.
395///
396/// This strategy will implicitly do local rejects to ensure that the
397/// `BTreeSet` has at least the minimum number of elements, in case `element`
398/// should produce duplicate values.
399pub fn btree_set<T: Strategy>(
400    element: T,
401    size: impl Into<SizeRange>,
402) -> BTreeSetStrategy<T>
403where
404    T::Value: Ord,
405{
406    let size = size.into();
407    BTreeSetStrategy(statics::Filter::new(
408        statics::Map::new(vec(element, size.clone()), VecToBTreeSet),
409        "BTreeSet minimum size".into(),
410        MinSize(size.start()),
411    ))
412}
413
414mapfn! {
415    {#[cfg(feature = "std")]}
416    [] fn VecToHashMap[<K : fmt::Debug + Hash + Eq, V : fmt::Debug>]
417        (vec: Vec<(K, V)>) -> HashMap<K, V>
418    {
419        vec.into_iter().collect()
420    }
421}
422
423#[cfg(feature = "std")]
424impl<K: Hash + Eq, V> statics::FilterFn<HashMap<K, V>> for MinSize {
425    fn apply(&self, map: &HashMap<K, V>) -> bool {
426        map.len() >= self.0
427    }
428}
429
430opaque_strategy_wrapper! {
431    {#[cfg(feature = "std")]}
432    {#[cfg_attr(docsrs, doc(cfg(feature = "std")))]}
433    /// Strategy to create `HashMap`s with a length in a certain range.
434    ///
435    /// Created by the `hash_map()` function in the same module.
436    #[derive(Clone, Debug)]
437    pub struct HashMapStrategy[<K, V>]
438        [where K : Strategy, V : Strategy, K::Value : Hash + Eq](
439            statics::Filter<statics::Map<VecStrategy<(K,V)>,
440            VecToHashMap>, MinSize>)
441        -> HashMapValueTree<K::Tree, V::Tree>;
442    /// `ValueTree` corresponding to `HashMapStrategy`.
443    #[derive(Clone, Debug)]
444    pub struct HashMapValueTree[<K, V>]
445        [where K : ValueTree, V : ValueTree, K::Value : Hash + Eq](
446            statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>,
447            VecToHashMap>, MinSize>)
448        -> HashMap<K::Value, V::Value>;
449}
450
451/// Create a strategy to generate `HashMap`s containing keys and values drawn
452/// from `key` and `value` respectively, and with a size within the given
453/// range.
454///
455/// This strategy will implicitly do local rejects to ensure that the `HashMap`
456/// has at least the minimum number of elements, in case `key` should produce
457/// duplicate values.
458#[cfg(feature = "std")]
459#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
460pub fn hash_map<K: Strategy, V: Strategy>(
461    key: K,
462    value: V,
463    size: impl Into<SizeRange>,
464) -> HashMapStrategy<K, V>
465where
466    K::Value: Hash + Eq,
467{
468    let size = size.into();
469    HashMapStrategy(statics::Filter::new(
470        statics::Map::new(vec((key, value), size.clone()), VecToHashMap),
471        "HashMap minimum size".into(),
472        MinSize(size.start()),
473    ))
474}
475
476mapfn! {
477    [] fn VecToBTreeMap[<K : fmt::Debug + Ord, V : fmt::Debug>]
478        (vec: Vec<(K, V)>) -> BTreeMap<K, V>
479    {
480        vec.into_iter().collect()
481    }
482}
483
484impl<K: Ord, V> statics::FilterFn<BTreeMap<K, V>> for MinSize {
485    fn apply(&self, map: &BTreeMap<K, V>) -> bool {
486        map.len() >= self.0
487    }
488}
489
490opaque_strategy_wrapper! {
491    /// Strategy to create `BTreeMap`s with a length in a certain range.
492    ///
493    /// Created by the `btree_map()` function in the same module.
494    #[derive(Clone, Debug)]
495    pub struct BTreeMapStrategy[<K, V>]
496        [where K : Strategy, V : Strategy, K::Value : Ord](
497            statics::Filter<statics::Map<VecStrategy<(K,V)>,
498            VecToBTreeMap>, MinSize>)
499        -> BTreeMapValueTree<K::Tree, V::Tree>;
500    /// `ValueTree` corresponding to `BTreeMapStrategy`.
501    #[derive(Clone, Debug)]
502    pub struct BTreeMapValueTree[<K, V>]
503        [where K : ValueTree, V : ValueTree, K::Value : Ord](
504            statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>,
505            VecToBTreeMap>, MinSize>)
506        -> BTreeMap<K::Value, V::Value>;
507}
508
509/// Create a strategy to generate `BTreeMap`s containing keys and values drawn
510/// from `key` and `value` respectively, and with a size within the given
511/// range.
512///
513/// This strategy will implicitly do local rejects to ensure that the
514/// `BTreeMap` has at least the minimum number of elements, in case `key`
515/// should produce duplicate values.
516pub fn btree_map<K: Strategy, V: Strategy>(
517    key: K,
518    value: V,
519    size: impl Into<SizeRange>,
520) -> BTreeMapStrategy<K, V>
521where
522    K::Value: Ord,
523{
524    let size = size.into();
525    BTreeMapStrategy(statics::Filter::new(
526        statics::Map::new(vec((key, value), size.clone()), VecToBTreeMap),
527        "BTreeMap minimum size".into(),
528        MinSize(size.start()),
529    ))
530}
531
532#[derive(Clone, Copy, Debug)]
533enum Shrink {
534    DeleteElement(usize),
535    ShrinkElement(usize),
536}
537
538/// `ValueTree` corresponding to `VecStrategy`.
539#[derive(Clone, Debug)]
540pub struct VecValueTree<T: ValueTree> {
541    elements: Vec<T>,
542    included_elements: VarBitSet,
543    min_size: usize,
544    shrink: Shrink,
545    prev_shrink: Option<Shrink>,
546}
547
548impl<T: Strategy> Strategy for VecStrategy<T> {
549    type Tree = VecValueTree<T::Tree>;
550    type Value = Vec<T::Value>;
551
552    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
553        let (start, end) = self.size.start_end_incl();
554        let max_size = sample_uniform_incl(runner, start, end);
555        let mut elements = Vec::with_capacity(max_size);
556        while elements.len() < max_size {
557            elements.push(self.element.new_tree(runner)?);
558        }
559
560        Ok(VecValueTree {
561            elements,
562            included_elements: VarBitSet::saturated(max_size),
563            min_size: start,
564            shrink: Shrink::DeleteElement(0),
565            prev_shrink: None,
566        })
567    }
568}
569
570impl<T: Strategy> Strategy for Vec<T> {
571    type Tree = VecValueTree<T::Tree>;
572    type Value = Vec<T::Value>;
573
574    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
575        let len = self.len();
576        let elements = self
577            .iter()
578            .map(|t| t.new_tree(runner))
579            .collect::<Result<Vec<_>, Reason>>()?;
580
581        Ok(VecValueTree {
582            elements,
583            included_elements: VarBitSet::saturated(len),
584            min_size: len,
585            shrink: Shrink::ShrinkElement(0),
586            prev_shrink: None,
587        })
588    }
589}
590
591impl<T: ValueTree> ValueTree for VecValueTree<T> {
592    type Value = Vec<T::Value>;
593
594    fn current(&self) -> Vec<T::Value> {
595        self.elements
596            .iter()
597            .enumerate()
598            .filter(|&(ix, _)| self.included_elements.test(ix))
599            .map(|(_, element)| element.current())
600            .collect()
601    }
602
603    fn simplify(&mut self) -> bool {
604        // The overall strategy here is to iteratively delete elements from the
605        // list until we can do so no further, then to shrink each remaining
606        // element in sequence.
607        //
608        // For `complicate()`, we simply undo the last shrink operation, if
609        // there was any.
610        if let Shrink::DeleteElement(ix) = self.shrink {
611            // Can't delete an element if beyond the end of the vec or if it
612            // would put us under the minimum length.
613            if ix >= self.elements.len()
614                || self.included_elements.count() == self.min_size
615            {
616                self.shrink = Shrink::ShrinkElement(0);
617            } else {
618                self.included_elements.clear(ix);
619                self.prev_shrink = Some(self.shrink);
620                self.shrink = Shrink::DeleteElement(ix + 1);
621                return true;
622            }
623        }
624
625        while let Shrink::ShrinkElement(ix) = self.shrink {
626            if ix >= self.elements.len() {
627                // Nothing more we can do
628                return false;
629            }
630
631            if !self.included_elements.test(ix) {
632                // No use shrinking something we're not including.
633                self.shrink = Shrink::ShrinkElement(ix + 1);
634                continue;
635            }
636
637            if !self.elements[ix].simplify() {
638                // Move on to the next element
639                self.shrink = Shrink::ShrinkElement(ix + 1);
640            } else {
641                self.prev_shrink = Some(self.shrink);
642                return true;
643            }
644        }
645
646        panic!("Unexpected shrink state");
647    }
648
649    fn complicate(&mut self) -> bool {
650        match self.prev_shrink {
651            None => false,
652            Some(Shrink::DeleteElement(ix)) => {
653                // Undo the last item we deleted. Can't complicate any further,
654                // so unset prev_shrink.
655                self.included_elements.set(ix);
656                self.prev_shrink = None;
657                true
658            }
659            Some(Shrink::ShrinkElement(ix)) => {
660                if self.elements[ix].complicate() {
661                    // Don't unset prev_shrink; we may be able to complicate
662                    // again.
663                    true
664                } else {
665                    // Can't complicate the last element any further.
666                    self.prev_shrink = None;
667                    false
668                }
669            }
670        }
671    }
672}
673
674//==============================================================================
675// Tests
676//==============================================================================
677
678#[cfg(test)]
679mod test {
680    use super::*;
681
682    use crate::bits;
683
684    #[test]
685    fn test_vec() {
686        let input = vec(1usize..20usize, 5..20);
687        let mut num_successes = 0;
688
689        let mut runner = TestRunner::deterministic();
690        for _ in 0..256 {
691            let case = input.new_tree(&mut runner).unwrap();
692            let start = case.current();
693            // Has correct length
694            assert!(start.len() >= 5 && start.len() < 20);
695            // Has at least 2 distinct values
696            assert!(start.iter().map(|&v| v).collect::<VarBitSet>().len() >= 2);
697
698            let result = runner.run_one(case, |v| {
699                prop_assert!(
700                    v.iter().map(|&v| v).sum::<usize>() < 9,
701                    "greater than 8"
702                );
703                Ok(())
704            });
705
706            match result {
707                Ok(true) => num_successes += 1,
708                Err(TestError::Fail(_, value)) => {
709                    // The minimal case always has between 5 (due to min
710                    // length) and 9 (min element value = 1) elements, and
711                    // always sums to exactly 9.
712                    assert!(
713                        value.len() >= 5
714                            && value.len() <= 9
715                            && value.iter().map(|&v| v).sum::<usize>() == 9,
716                        "Unexpected minimal value: {:?}",
717                        value
718                    );
719                }
720                e => panic!("Unexpected result: {:?}", e),
721            }
722        }
723
724        assert!(num_successes < 256);
725    }
726
727    #[test]
728    fn test_vec_sanity() {
729        check_strategy_sanity(vec(0i32..1000, 5..10), None);
730    }
731
732    #[test]
733    fn test_parallel_vec() {
734        let input =
735            vec![(1u32..10).boxed(), bits::u32::masked(0xF0u32).boxed()];
736
737        for _ in 0..256 {
738            let mut runner = TestRunner::default();
739            let mut case = input.new_tree(&mut runner).unwrap();
740
741            loop {
742                let current = case.current();
743                assert_eq!(2, current.len());
744                assert!(current[0] >= 1 && current[0] <= 10);
745                assert_eq!(0, (current[1] & !0xF0));
746
747                if !case.simplify() {
748                    break;
749                }
750            }
751        }
752    }
753
754    #[cfg(feature = "std")]
755    #[test]
756    fn test_map() {
757        // Only 8 possible keys
758        let input = hash_map("[ab]{3}", "a", 2..3);
759        let mut runner = TestRunner::deterministic();
760
761        for _ in 0..256 {
762            let v = input.new_tree(&mut runner).unwrap().current();
763            assert_eq!(2, v.len());
764        }
765    }
766
767    #[cfg(feature = "std")]
768    #[test]
769    fn test_set() {
770        // Only 8 possible values
771        let input = hash_set("[ab]{3}", 2..3);
772        let mut runner = TestRunner::deterministic();
773
774        for _ in 0..256 {
775            let v = input.new_tree(&mut runner).unwrap().current();
776            assert_eq!(2, v.len());
777        }
778    }
779}