Skip to content

Commit a03aeca

Browse files
committed
Add a wrapper for disabling shrinking for an Arbitrary
In some cases, users may want to disable shrinking for a specific test. Consider, for example, some complex recursive data type. Naturally, we'd want values to be shrunk for most tests in order to isolate the specific sub-structure provoking the failure. However, due to the complexity we may end up with a shrinker with a certain complexity in itself. Hence, we may want to test our shrinker. For those specific tests, the very shrinking of input values performed by quickcheck could get in our way or cause failures on its own. Previously, the only way library users could disable shrinking in such cases was to define a wrapper type (in their own code) which forwarded `Arbitrary::arbitrary` but not `Arbitrary::shrink`. We suspect that the possibility of disabling shrinking for selected tests, such as in cases described above, is not too uncommon. The wrapper pattern is easy to understand and blends in well with quickcheck. Shipping one with the library will suit the described use-cases.
1 parent defde6f commit a03aeca

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

src/arbitrary.rs

+43
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,49 @@ impl Arbitrary for SystemTime {
11241124
}
11251125
}
11261126

1127+
/// Wrapper for disabling shrinking for an Arbitrary
1128+
///
1129+
/// This type allows generating values via a given `Arbitrary` implementation
1130+
/// for a test for which we don't want to shrink input values.
1131+
///
1132+
/// # Example
1133+
///
1134+
/// ```rust
1135+
/// use quickcheck::{QuickCheck, NoShrink};
1136+
///
1137+
/// fn prop_sane_shrinker() {
1138+
/// // Yielding the original value will result in endless recursion
1139+
/// fn shrinker_no_self(value: NoShrink<u16>) -> bool {
1140+
/// use quickcheck::Arbitrary;
1141+
/// !value.as_ref().shrink().any(|v| v == *value.as_ref())
1142+
/// }
1143+
/// QuickCheck::new().quickcheck(shrinker_no_self as fn(NoShrink<u16>) -> bool);
1144+
/// }
1145+
/// ```
1146+
#[derive(Clone, Debug)]
1147+
pub struct NoShrink<A: Arbitrary>{
1148+
inner: A,
1149+
}
1150+
1151+
impl<A: Arbitrary> NoShrink<A> {
1152+
/// Unwrap the inner value
1153+
pub fn into_inner(self) -> A {
1154+
self.inner
1155+
}
1156+
}
1157+
1158+
impl<A: Arbitrary> Arbitrary for NoShrink<A> {
1159+
fn arbitrary(gen: &mut Gen) -> Self {
1160+
Self{inner: Arbitrary::arbitrary(gen)}
1161+
}
1162+
}
1163+
1164+
impl<A: Arbitrary> AsRef<A> for NoShrink<A> {
1165+
fn as_ref(&self) -> &A {
1166+
&self.inner
1167+
}
1168+
}
1169+
11271170
#[cfg(test)]
11281171
mod test {
11291172
use std::collections::{

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ new kind of witness being generated. These sorts of changes may happen in
1414
semver compatible releases.
1515
*/
1616

17-
pub use crate::arbitrary::{empty_shrinker, single_shrinker, Arbitrary, Gen};
17+
pub use crate::arbitrary::{empty_shrinker, single_shrinker, Arbitrary, NoShrink, Gen};
1818
pub use crate::tester::{quickcheck, QuickCheck, TestResult, Testable};
1919

2020
/// A macro for writing quickcheck tests.

0 commit comments

Comments
 (0)