diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/proptest/src/array.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/proptest/src/array.rs')
-rw-r--r-- | vendor/proptest/src/array.rs | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/vendor/proptest/src/array.rs b/vendor/proptest/src/array.rs new file mode 100644 index 000000000..2edce4608 --- /dev/null +++ b/vendor/proptest/src/array.rs @@ -0,0 +1,264 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for strategies producing fixed-length arrays. +//! +//! An array of strategies (but only length 1 to 32 for now) is itself a +//! strategy which generates arrays of that size drawing elements from the +//! corresponding input strategies. +//! +//! See also [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for +//! easily making a strategy for an array drawn from one strategy. +//! +//! General implementations are available for sizes 1 through 32. + +use core::marker::PhantomData; + +use crate::strategy::*; +use crate::test_runner::*; + +/// A `Strategy` which generates fixed-size arrays containing values drawn from +/// an inner strategy. +/// +/// `T` must be an array type of length 1 to 32 whose values are produced by +/// strategy `S`. Instances of this type are normally created by the various +/// `uniformXX` functions in this module. +/// +/// This is mainly useful when the inner strategy is not `Copy`, precluding +/// expressing the strategy as `[myStrategy; 32]`, for example. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// #[test] +/// fn test_something(a in prop::array::uniform32(1u32..)) { +/// let unexpected = [0u32;32]; +/// // `a` is also a [u32;32], so we can compare them directly +/// assert_ne!(unexpected, a); +/// } +/// } +/// # fn main() { } +/// ``` +#[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> { + /// Directly create a `UniformArrayStrategy`. + /// + /// This is only intended for advanced use, since the only way to specify + /// the array size is with the turbofish operator and explicitly naming the + /// type of the values in the array and the strategy itself. + /// + /// Prefer the `uniformXX` functions at module-level unless something + /// precludes their use. + pub fn new(strategy: S) -> Self { + UniformArrayStrategy { + strategy, + _marker: PhantomData, + } + } +} + +/// A `ValueTree` operating over a fixed-size array. +#[derive(Clone, Copy, Debug)] +pub struct ArrayValueTree<T> { + tree: T, + shrinker: usize, + last_shrinker: Option<usize>, +} + +/// Create a strategy to generate fixed-length arrays. +/// +/// All values within the new strategy are generated using the given +/// strategy. +/// +/// See [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for +/// example usage. +pub fn uniform<S: Strategy, const N: usize>( + strategy: S, +) -> UniformArrayStrategy<S, [S::Value; N]> { + UniformArrayStrategy { + strategy, + _marker: PhantomData, + } +} + +macro_rules! small_array { + ($n:tt $uni:ident) => { + /// Create a strategy to generate fixed-length arrays. + /// + /// All values within the new strategy are generated using the given + /// strategy. The length of the array corresponds to the suffix of the + /// name of this function. + /// + /// See [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for + /// example usage. + pub fn $uni<S: Strategy>( + strategy: S, + ) -> UniformArrayStrategy<S, [S::Value; $n]> { + UniformArrayStrategy { + strategy, + _marker: PhantomData, + } + } + }; +} + +impl<S: Strategy, const N: usize> 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: unarray::build_array_result(|i| self[i].new_tree(runner))?, + shrinker: 0, + last_shrinker: None, + }) + } +} +impl<S: Strategy, const N: usize> 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: unarray::build_array_result(|_| { + self.strategy.new_tree(runner) + })?, + shrinker: 0, + last_shrinker: None, + }) + } +} +impl<T: ValueTree, const N: usize> ValueTree for ArrayValueTree<[T; N]> { + type Value = [T::Value; N]; + + fn current(&self) -> [T::Value; N] { + unarray::build_array(|i| self.tree[i].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); +small_array!(2 uniform2); +small_array!(3 uniform3); +small_array!(4 uniform4); +small_array!(5 uniform5); +small_array!(6 uniform6); +small_array!(7 uniform7); +small_array!(8 uniform8); +small_array!(9 uniform9); +small_array!(10 uniform10); +small_array!(11 uniform11); +small_array!(12 uniform12); +small_array!(13 uniform13); +small_array!(14 uniform14); +small_array!(15 uniform15); +small_array!(16 uniform16); +small_array!(17 uniform17); +small_array!(18 uniform18); +small_array!(19 uniform19); +small_array!(20 uniform20); +small_array!(21 uniform21); +small_array!(22 uniform22); +small_array!(23 uniform23); +small_array!(24 uniform24); +small_array!(25 uniform25); +small_array!(26 uniform26); +small_array!(27 uniform27); +small_array!(28 uniform28); +small_array!(29 uniform29); +small_array!(30 uniform30); +small_array!(31 uniform31); +small_array!(32 uniform32); + +#[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 { + // Find a failing test case + 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)); + // Maximally shrunken + 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); + } +} |