Skip to content

Commit

Permalink
Rename Rejection to Reason.
Browse files Browse the repository at this point in the history
Since it's also on the `Fail` case, the old name doesn't really make
sense.
  • Loading branch information
AltSysrq committed Jan 14, 2018
1 parent c81a728 commit 4b9a19b
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 38 deletions.
17 changes: 9 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

### Potential Breaking Changes

- Instead of returning `-> Result<Self::Value, String>`, strategies are expected
to return `-> Result<Self::Value, Rejection>` instead. `Rejection` reduces
the amount of heap allocations, especially for `.prop_filter(..)` where
you may now also pass in `&'static str` as well as `Rc<str>`.
You will only experience breaks if you've written your own strategy types
or if you've used `TestCaseError::Reject` or `TestCaseError::Fail` expliclty.
- Instead of returning `-> Result<Self::Value, String>`, strategies are
expected to return `-> Result<Self::Value, Reason>` instead. `Reason` reduces
the amount of heap allocations, especially for `.prop_filter(..)` where you
may now also pass in `&'static str`. You will only experience breaks if
you've written your own strategy types or if you've used
`TestCaseError::Reject` or `TestCaseError::Fail` explicitly.

### New Additions

- Added `proptest::test_runner::Rejection` which allows you to avoid heap
allocation in some places or share allocation with string-interning.
- Added `proptest::test_runner::Reason` which allows you to avoid heap
allocation in some places and may be used to make the API richer in the
future without incurring more breaking changes.

- Added a type alias `proptest::strategy::NewTree<S>` where `S: Strategy`
defined as: `type NewTree<S> = Result<<S as Strategy>::Value, Rejection>`.
Expand Down
4 changes: 2 additions & 2 deletions src/strategy/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ use test_runner::*;
/// See `Strategy::prop_filter()`.
pub struct Filter<S, F> {
pub(super) source: S,
pub(super) whence: Rejection,
pub(super) whence: Reason,
pub(super) fun: Arc<F>,
}

impl<S, F> Filter<S, F> {
pub (super) fn new(source: S, whence: Rejection, fun: F) -> Self {
pub (super) fn new(source: S, whence: Reason, fun: F) -> Self {
Self { source, whence, fun: Arc::new(fun) }
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/strategy/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ where S::Value : Strategy,
}

impl<S : ValueTree> FlattenValueTree<S> where S::Value : Strategy {
fn new(runner: &mut TestRunner, meta: S) -> Result<Self, Rejection> {
fn new(runner: &mut TestRunner, meta: S) -> Result<Self, Reason> {
let current = meta.current().new_value(runner)?;
Ok(FlattenValueTree {
meta: Fuse::new(meta),
Expand Down
6 changes: 3 additions & 3 deletions src/strategy/statics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ pub trait FilterFn<T> {
#[derive(Clone)]
pub struct Filter<S, F> {
source: S,
whence: Rejection,
whence: Reason,
fun: F,
}

impl<S, F> Filter<S, F> {
/// Adapt strategy `source` to reject values which do not pass `filter`,
/// using `whence` as the reported reason/location.
pub fn new(source: S, whence: Rejection, filter: F) -> Self {
// NOTE: We don't use universal quantification R: Into<Rejection>
pub fn new(source: S, whence: Reason, filter: F) -> Self {
// NOTE: We don't use universal quantification R: Into<Reason>
// since the module is not conviniently exposed.
Filter { source, whence, fun: filter }
}
Expand Down
4 changes: 2 additions & 2 deletions src/strategy/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use test_runner::*;
/// [`ValueTree`]: trait.ValueTree.html
/// [`Ok`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Ok
/// [`Err`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Err
pub type NewTree<S> = Result<<S as Strategy>::Value, Rejection>;
pub type NewTree<S> = Result<<S as Strategy>::Value, Reason>;

/// The value that functions under test use for a particular `Strategy`.
pub type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
Expand Down Expand Up @@ -259,7 +259,7 @@ pub trait Strategy : fmt::Debug {
/// whole-input rejections.
///
/// `whence` is used to record where and why the rejection occurred.
fn prop_filter<R: Into<Rejection>, F : Fn (&ValueFor<Self>) -> bool>
fn prop_filter<R: Into<Reason>, F : Fn (&ValueFor<Self>) -> bool>
(self, whence: R, fun: F) -> Filter<Self, F>
where Self : Sized {
Filter::new(self, whence.into(), fun)
Expand Down
44 changes: 22 additions & 22 deletions src/test_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,40 +287,40 @@ impl FailurePersistence {

/// The reason for why something, such as a generated value, was rejected.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Rejection(Cow<'static, str>);
pub struct Reason(Cow<'static, str>);

impl From<&'static str> for Rejection {
impl From<&'static str> for Reason {
fn from(s: &'static str) -> Self {
Rejection(s.into())
Reason(s.into())
}
}

impl From<String> for Rejection {
impl From<String> for Reason {
fn from(s: String) -> Self {
Rejection(s.into())
Reason(s.into())
}
}

impl From<Box<str>> for Rejection {
impl From<Box<str>> for Reason {
fn from(s: Box<str>) -> Self {
Rejection(String::from(s).into())
Reason(String::from(s).into())
}
}

impl ops::Deref for Rejection {
impl ops::Deref for Reason {
type Target = str;
fn deref(&self) -> &Self::Target { self.0.deref() }
}

impl AsRef<str> for Rejection {
impl AsRef<str> for Reason {
fn as_ref(&self) -> &str { &*self }
}

impl Borrow<str> for Rejection {
impl Borrow<str> for Reason {
fn borrow(&self) -> &str { &*self }
}

impl fmt::Display for Rejection {
impl fmt::Display for Reason {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_ref(), f)
}
Expand All @@ -343,12 +343,12 @@ pub enum TestCaseError {
///
/// The string gives the location and context of the rejection, and
/// should be suitable for formatting like `Foo did X at {whence}`.
Reject(Rejection),
Reject(Reason),
/// The code under test failed the test.
///
/// The string should indicate the location of the failure, but may
/// generally be any string.
Fail(Rejection),
Fail(Reason),
}

/// Convenience for the type returned by test cases.
Expand All @@ -361,15 +361,15 @@ impl TestCaseError {
///
/// The string gives the location and context of the rejection, and
/// should be suitable for formatting like `Foo did X at {whence}`.
pub fn reject<R: Into<Rejection>>(reason: R) -> Self {
pub fn reject<R: Into<Reason>>(reason: R) -> Self {
TestCaseError::Reject(reason.into())
}

/// The code under test failed the test.
///
/// The string should indicate the location of the failure, but may
/// generally be any string.
pub fn fail<R: Into<Rejection>>(reason: R) -> Self {
pub fn fail<R: Into<Reason>>(reason: R) -> Self {
TestCaseError::Fail(reason.into())
}
}
Expand All @@ -396,11 +396,11 @@ impl<E : ::std::error::Error> From<E> for TestCaseError {
pub enum TestError<T> {
/// The test was aborted for the given reason, for example, due to too many
/// inputs having been rejected.
Abort(Rejection),
Abort(Reason),
/// A failing test case was found. The string indicates where and/or why
/// the test failed. The `T` is the minimal input found to reproduce the
/// failure.
Fail(Rejection, T),
Fail(Reason, T),
}

impl<T : fmt::Debug> fmt::Display for TestError<T> {
Expand All @@ -424,7 +424,7 @@ impl<T : fmt::Debug> ::std::error::Error for TestError<T> {
}
}

type RejectionDetail = BTreeMap<Rejection, u32>;
type RejectionDetail = BTreeMap<Reason, u32>;

/// State used when running a proptest test.
#[derive(Clone)]
Expand Down Expand Up @@ -856,9 +856,9 @@ impl TestRunner {

/// Update the state to account for a local rejection from `whence`, and
/// return `Ok` if the caller should keep going or `Err` to abort.
pub fn reject_local<R>(&mut self, whence: R) -> Result<(), Rejection>
pub fn reject_local<R>(&mut self, whence: R) -> Result<(), Reason>
where
R: Into<Rejection>
R: Into<Reason>
{
if self.local_rejects >= self.config.max_local_rejects {
Err("Too many local rejects".into())
Expand All @@ -872,7 +872,7 @@ impl TestRunner {

/// Update the state to account for a global rejection from `whence`, and
/// return `Ok` if the caller should keep going or `Err` to abort.
fn reject_global<T>(&mut self, whence: Rejection) -> Result<(),TestError<T>> {
fn reject_global<T>(&mut self, whence: Reason) -> Result<(),TestError<T>> {
if self.global_rejects >= self.config.max_global_rejects {
Err(TestError::Abort("Too many global rejects".into()))
} else {
Expand All @@ -883,7 +883,7 @@ impl TestRunner {
}

/// Insert 1 or increment the rejection detail at key for whence.
fn insert_or_increment(into: &mut RejectionDetail, whence: Rejection) {
fn insert_or_increment(into: &mut RejectionDetail, whence: Reason) {
use std::collections::btree_map::Entry::*;
match into.entry(whence) {
Occupied(oe) => { *oe.into_mut() += 1; },
Expand Down

0 comments on commit 4b9a19b

Please sign in to comment.