summaryrefslogtreecommitdiffstats
path: root/vendor/proptest/src/strategy/statics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/proptest/src/strategy/statics.rs')
-rw-r--r--vendor/proptest/src/strategy/statics.rs266
1 files changed, 266 insertions, 0 deletions
diff --git a/vendor/proptest/src/strategy/statics.rs b/vendor/proptest/src/strategy/statics.rs
new file mode 100644
index 000000000..978dc13b9
--- /dev/null
+++ b/vendor/proptest/src/strategy/statics.rs
@@ -0,0 +1,266 @@
+//-
+// 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.
+
+//! Modified versions of the normal strategy combinators which take specialised
+//! traits instead of normal functions.
+//!
+//! This entire module is strictly a workaround until
+//! <https://github.com/rust-lang/rfcs/pull/1522> and
+//! <https://github.com/rust-lang/rfcs/pull/2071> are available in stable. It
+//! allows naming types built on the combinators without resorting to dynamic
+//! dispatch or causing `Arc` to allocate space for a function pointer.
+//!
+//! External code is discouraged from using this module directly. It is
+//! deliberately not exposed in a convenient way (i.e., via the `Strategy`
+//! trait itself), but is nonetheless exposed since external trait implementors
+//! may face the same issues.
+//!
+//! **This module is subject to removal at some point after the language
+//! features linked above become stable.**
+
+use crate::std_facade::fmt;
+
+use crate::strategy::traits::*;
+use crate::test_runner::*;
+
+//==============================================================================
+// Filter
+//==============================================================================
+
+/// Essentially `Fn (&T) -> bool`.
+pub trait FilterFn<T> {
+ /// Test whether `t` passes the filter.
+ fn apply(&self, t: &T) -> bool;
+}
+
+/// Static version of `strategy::Filter`.
+#[derive(Clone)]
+#[must_use = "strategies do nothing unless used"]
+pub struct Filter<S, F> {
+ source: S,
+ 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: Reason, filter: F) -> Self {
+ // NOTE: We don't use universal quantification R: Into<Reason>
+ // since the module is not conveniently exposed.
+ Filter {
+ source,
+ whence,
+ fun: filter,
+ }
+ }
+}
+
+impl<S: fmt::Debug, F> fmt::Debug for Filter<S, F> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Filter")
+ .field("source", &self.source)
+ .field("whence", &self.whence)
+ .field("fun", &"<function>")
+ .finish()
+ }
+}
+
+impl<S: Strategy, F: FilterFn<S::Value> + Clone> Strategy for Filter<S, F> {
+ type Tree = Filter<S::Tree, F>;
+ type Value = S::Value;
+
+ fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
+ loop {
+ let val = self.source.new_tree(runner)?;
+ if !self.fun.apply(&val.current()) {
+ runner.reject_local(self.whence.clone())?;
+ } else {
+ return Ok(Filter {
+ source: val,
+ whence: "unused".into(),
+ fun: self.fun.clone(),
+ });
+ }
+ }
+ }
+}
+
+impl<S: ValueTree, F: FilterFn<S::Value>> Filter<S, F> {
+ fn ensure_acceptable(&mut self) {
+ while !self.fun.apply(&self.source.current()) {
+ if !self.source.complicate() {
+ panic!(
+ "Unable to complicate filtered strategy \
+ back into acceptable value"
+ );
+ }
+ }
+ }
+}
+
+impl<S: ValueTree, F: FilterFn<S::Value>> ValueTree for Filter<S, F> {
+ type Value = S::Value;
+
+ fn current(&self) -> S::Value {
+ self.source.current()
+ }
+
+ fn simplify(&mut self) -> bool {
+ if self.source.simplify() {
+ self.ensure_acceptable();
+ true
+ } else {
+ false
+ }
+ }
+
+ fn complicate(&mut self) -> bool {
+ if self.source.complicate() {
+ self.ensure_acceptable();
+ true
+ } else {
+ false
+ }
+ }
+}
+
+//==============================================================================
+// Map
+//==============================================================================
+
+/// Essentially `Fn (T) -> Output`.
+pub trait MapFn<T> {
+ #[allow(missing_docs)]
+ type Output: fmt::Debug;
+
+ /// Map `T` to `Output`.
+ fn apply(&self, t: T) -> Self::Output;
+}
+
+/// Static version of `strategy::Map`.
+#[derive(Clone)]
+#[must_use = "strategies do nothing unless used"]
+pub struct Map<S, F> {
+ source: S,
+ fun: F,
+}
+
+impl<S, F> Map<S, F> {
+ /// Adapt strategy `source` by applying `fun` to values it produces.
+ pub fn new(source: S, fun: F) -> Self {
+ Map { source, fun }
+ }
+}
+
+impl<S: fmt::Debug, F> fmt::Debug for Map<S, F> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Map")
+ .field("source", &self.source)
+ .field("fun", &"<function>")
+ .finish()
+ }
+}
+
+impl<S: Strategy, F: Clone + MapFn<S::Value>> Strategy for Map<S, F> {
+ type Tree = Map<S::Tree, F>;
+ type Value = F::Output;
+
+ fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
+ self.source.new_tree(runner).map(|v| Map {
+ source: v,
+ fun: self.fun.clone(),
+ })
+ }
+}
+
+impl<S: ValueTree, F: MapFn<S::Value>> ValueTree for Map<S, F> {
+ type Value = F::Output;
+
+ fn current(&self) -> F::Output {
+ self.fun.apply(self.source.current())
+ }
+
+ fn simplify(&mut self) -> bool {
+ self.source.simplify()
+ }
+
+ fn complicate(&mut self) -> bool {
+ self.source.complicate()
+ }
+}
+
+impl<I, O: fmt::Debug> MapFn<I> for fn(I) -> O {
+ type Output = O;
+ fn apply(&self, x: I) -> Self::Output {
+ self(x)
+ }
+}
+
+pub(crate) fn static_map<S: Strategy, O: fmt::Debug>(
+ strat: S,
+ fun: fn(S::Value) -> O,
+) -> Map<S, fn(S::Value) -> O> {
+ Map::new(strat, fun)
+}
+
+//==============================================================================
+// Tests
+//==============================================================================
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_static_filter() {
+ #[derive(Clone, Copy, Debug)]
+ struct MyFilter;
+ impl FilterFn<i32> for MyFilter {
+ fn apply(&self, &v: &i32) -> bool {
+ 0 == v % 3
+ }
+ }
+
+ let input = Filter::new(0..256, "%3".into(), MyFilter);
+
+ for _ in 0..256 {
+ let mut runner = TestRunner::default();
+ let mut case = input.new_tree(&mut runner).unwrap();
+
+ assert!(0 == case.current() % 3);
+
+ while case.simplify() {
+ assert!(0 == case.current() % 3);
+ }
+ assert!(0 == case.current() % 3);
+ }
+ }
+
+ #[test]
+ fn test_static_map() {
+ #[derive(Clone, Copy, Debug)]
+ struct MyMap;
+ impl MapFn<i32> for MyMap {
+ type Output = i32;
+ fn apply(&self, v: i32) -> i32 {
+ v * 2
+ }
+ }
+
+ let input = Map::new(0..10, MyMap);
+
+ TestRunner::default()
+ .run(&input, |v| {
+ assert!(0 == v % 2);
+ Ok(())
+ })
+ .unwrap();
+ }
+}