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/tuple.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/tuple.rs')
-rw-r--r-- | vendor/proptest/src/tuple.rs | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/vendor/proptest/src/tuple.rs b/vendor/proptest/src/tuple.rs new file mode 100644 index 000000000..8230f59e4 --- /dev/null +++ b/vendor/proptest/src/tuple.rs @@ -0,0 +1,181 @@ +//- +// 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 combining strategies into tuples. +//! +//! There is no explicit "tuple strategy"; simply make a tuple containing the +//! strategy and that tuple is itself a strategy. + +use crate::strategy::*; +use crate::test_runner::*; + +/// Common `ValueTree` implementation for all tuple strategies. +#[derive(Clone, Copy, Debug)] +pub struct TupleValueTree<T> { + tree: T, + shrinker: u32, + prev_shrinker: Option<u32>, +} + +impl<T> TupleValueTree<T> { + /// Create a new `TupleValueTree` wrapping `inner`. + /// + /// It only makes sense for `inner` to be a tuple of an arity for which the + /// type implements `ValueTree`. + pub fn new(inner: T) -> Self { + TupleValueTree { + tree: inner, + shrinker: 0, + prev_shrinker: None, + } + } +} + +macro_rules! tuple { + ($($fld:tt : $typ:ident),*) => { + impl<$($typ : Strategy),*> Strategy for ($($typ,)*) { + type Tree = TupleValueTree<($($typ::Tree,)*)>; + type Value = ($($typ::Value,)*); + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let values = ($(self.$fld.new_tree(runner)?,)*); + Ok(TupleValueTree::new(values)) + } + } + + impl<$($typ : ValueTree),*> ValueTree + for TupleValueTree<($($typ,)*)> { + type Value = ($($typ::Value,)*); + + fn current(&self) -> Self::Value { + ($(self.tree.$fld.current(),)*) + } + + fn simplify(&mut self) -> bool { + $( + if $fld == self.shrinker { + if self.tree.$fld.simplify() { + self.prev_shrinker = Some(self.shrinker); + return true; + } else { + self.shrinker += 1; + } + } + )* + false + } + + fn complicate(&mut self) -> bool { + if let Some(shrinker) = self.prev_shrinker {$( + if $fld == shrinker { + if self.tree.$fld.complicate() { + self.shrinker = shrinker; + return true; + } else { + self.prev_shrinker = None; + return false; + } + } + )*} + false + } + } + } +} + +tuple!(0: A); +tuple!(0: A, 1: B); +tuple!(0: A, 1: B, 2: C); +tuple!(0: A, 1: B, 2: C, 3: D); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J); +tuple!( + 0: A, + 1: B, + 2: C, + 3: D, + 4: E, + 5: F, + 6: G, + 7: H, + 8: I, + 9: J, + 10: K +); +tuple!( + 0: A, + 1: B, + 2: C, + 3: D, + 4: E, + 5: F, + 6: G, + 7: H, + 8: I, + 9: J, + 10: K, + 11: L +); + +#[cfg(test)] +mod test { + use crate::strategy::*; + + use super::*; + + #[test] + fn shrinks_fully_ltr() { + fn pass(a: (i32, i32)) -> bool { + a.0 * a.1 <= 9 + } + + let input = (0..32, 0..32); + let mut runner = TestRunner::default(); + + 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..100, 0i32..1000, 0i32..10000), None); + } +} |