Skip to content

Commit c1a49e6

Browse files
authored
Merge pull request #589 from bschoenmaeckers/assume_ok
Add `ProptestResultExt` with `prop_assume_ok` helper
2 parents 411e580 + b59a691 commit c1a49e6

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

proptest/src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
pub use crate::arbitrary::{any, any_with, Arbitrary};
2424
pub use crate::strategy::{BoxedStrategy, Just, SBoxedStrategy, Strategy};
2525
pub use crate::test_runner::Config as ProptestConfig;
26-
pub use crate::test_runner::TestCaseError;
26+
pub use crate::test_runner::{TestCaseError, ProptestResultExt};
2727
pub use crate::{
2828
prop_assert, prop_assert_eq, prop_assert_ne, prop_assume, prop_compose,
2929
prop_oneof, proptest,

proptest/src/test_runner/errors.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,54 @@ impl<T: fmt::Debug> ::std::error::Error for TestError<T> {
132132
}
133133
}
134134
}
135+
136+
mod private {
137+
pub trait Sealed {}
138+
139+
impl<T, E> Sealed for Result<T, E> {}
140+
}
141+
142+
/// Extension trait for `Result<T, E>` to provide additional functionality
143+
/// specifically for prop test cases.
144+
pub trait ProptestResultExt<T, E>: private::Sealed {
145+
/// Converts a `Result<T, E>` into a `Result<T, TestCaseError>`, where the
146+
/// `Err` case is transformed into a `TestCaseError::Reject`.
147+
///
148+
/// This is intended to be used like the [`prop_assume!`] macro, but for
149+
/// fallible computations. If the result is `Err`, the test input is rejected
150+
/// and a new input will be generated.
151+
///
152+
/// ## Example
153+
///
154+
/// ```
155+
/// use proptest::prelude::*;
156+
/// proptest! {
157+
/// #[test]
158+
/// fn test_that_only_works_with_positive_integers(a in -10i32..10i32) {
159+
/// // Reject the case if `a` cannot be converted to u8 (e.g., negative values)
160+
/// let _unsigned: u8 = a.try_into().prop_assume_ok()?;
161+
/// // ...rest of test...
162+
/// }
163+
/// }
164+
/// #
165+
/// # fn main() { test_signed_to_unsigned(); }
166+
/// ```
167+
///
168+
/// [`prop_assume!`]: crate::prop_assume
169+
fn prop_assume_ok(self) -> Result<T, TestCaseError>
170+
where
171+
E: fmt::Debug;
172+
}
173+
174+
impl<T, E> ProptestResultExt<T, E> for Result<T, E> {
175+
#[track_caller]
176+
fn prop_assume_ok(self) -> Result<T, TestCaseError>
177+
where
178+
E: fmt::Debug,
179+
{
180+
let location = core::panic::Location::caller();
181+
self.map_err(|err| {
182+
TestCaseError::reject(format!("{location}: {err:?}"))
183+
})
184+
}
185+
}

0 commit comments

Comments
 (0)