proptest 0.9.3

Hypothesis-like property-based testing and shrinking.
Documentation
//-
// 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.

use core::fmt;
use core::marker::PhantomData;
use crate::std_facade::Arc;

use crate::strategy::traits::*;
use crate::test_runner::*;

//==============================================================================
// Map
//==============================================================================

/// `Strategy` and `ValueTree` map adaptor.
///
/// See `Strategy::prop_map()`.
#[must_use = "strategies do nothing unless used"]
pub struct Map<S, F> {
    pub(super) source: S,
    pub(super) fun: Arc<F>,
}

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 : Clone, F> Clone for Map<S, F> {
    fn clone(&self) -> Self {
        Map {
            source: self.source.clone(),
            fun: Arc::clone(&self.fun),
        }
    }
}

impl<S : Strategy, O : fmt::Debug,
     F : Fn (S::Value) -> O>
Strategy for Map<S, F> {
    type Tree = Map<S::Tree, F>;
    type Value = O;

    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
        self.source.new_tree(runner).map(
            |v| Map { source: v, fun: Arc::clone(&self.fun) })
    }
}

impl<S : ValueTree, O : fmt::Debug, F : Fn (S::Value) -> O>
ValueTree for Map<S, F> {
    type Value = O;

    fn current(&self) -> O {
        (self.fun)(self.source.current())
    }

    fn simplify(&mut self) -> bool {
        self.source.simplify()
    }

    fn complicate(&mut self) -> bool {
        self.source.complicate()
    }
}

//==============================================================================
// MapInto
//==============================================================================

// NOTE: Since this is external stable API,
// we avoid relying on the Map in `statics`.

/// `Strategy` and `ValueTree` map into adaptor.
///
/// See `Strategy::prop_map_into()`.
#[must_use = "strategies do nothing unless used"]
pub struct MapInto<S, O> {
    pub(super) source: S,
    pub(super) output: PhantomData<O>,
}

impl<S, O> MapInto<S, O> {
    /// Construct a `MapInto` mapper from an `S` strategy into a strategy
    /// producing `O`s.
    pub(super) fn new(source: S) -> Self {
        Self { source, output: PhantomData }
    }
}

impl<S : fmt::Debug, O> fmt::Debug for MapInto<S, O> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("MapInto").field("source", &self.source).finish()
    }
}

impl<S : Clone, O> Clone for MapInto<S, O> {
    fn clone(&self) -> Self {
        Self::new(self.source.clone())
    }
}

impl<S : Strategy, O : fmt::Debug> Strategy for MapInto<S, O>
where
    S::Value : Into<O>
{
    type Tree = MapInto<S::Tree, O>;
    type Value = O;

    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
        self.source.new_tree(runner).map(MapInto::new)
    }
}

impl<S : ValueTree, O : fmt::Debug> ValueTree for MapInto<S, O>
where
    S::Value: Into<O>
{
    type Value = O;

    fn current(&self) -> O {
        self.source.current().into()
    }

    fn simplify(&mut self) -> bool {
        self.source.simplify()
    }

    fn complicate(&mut self) -> bool {
        self.source.complicate()
    }
}

//==============================================================================
// Perturb
//==============================================================================

/// `Strategy` perturbation adaptor.
///
/// See `Strategy::prop_perturb()`.
#[must_use = "strategies do nothing unless used"]
pub struct Perturb<S, F> {
    pub(super) source: S,
    pub(super) fun: Arc<F>,
}

impl<S : fmt::Debug, F> fmt::Debug for Perturb<S, F> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Perturb")
            .field("source", &self.source)
            .field("fun", &"<function>")
            .finish()
    }
}

impl<S : Clone, F> Clone for Perturb<S, F> {
    fn clone(&self) -> Self {
        Perturb {
            source: self.source.clone(),
            fun: Arc::clone(&self.fun),
        }
    }
}

impl<S : Strategy, O : fmt::Debug,
     F : Fn (S::Value, TestRng) -> O>
Strategy for Perturb<S, F> {
    type Tree = PerturbValueTree<S::Tree, F>;
    type Value = O;

    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
        let rng = runner.new_rng();

        self.source.new_tree(runner).map(|source|
            PerturbValueTree { source, rng, fun: Arc::clone(&self.fun) }
        )
    }
}

/// `ValueTree` perturbation adaptor.
///
/// See `Strategy::prop_perturb()`.
pub struct PerturbValueTree<S, F> {
    source: S,
    fun: Arc<F>,
    rng: TestRng,
}

impl<S : fmt::Debug, F> fmt::Debug for PerturbValueTree<S, F> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PerturbValueTree")
            .field("source", &self.source)
            .field("fun", &"<function>")
            .field("rng", &self.rng)
            .finish()
    }
}

impl<S : Clone, F> Clone for PerturbValueTree<S, F> {
    fn clone(&self) -> Self {
        PerturbValueTree {
            source: self.source.clone(),
            fun: Arc::clone(&self.fun),
            rng: self.rng.clone(),
        }
    }
}

impl<S : ValueTree, O : fmt::Debug, F : Fn (S::Value, TestRng) -> O>
ValueTree for PerturbValueTree<S, F> {
    type Value = O;

    fn current(&self) -> O {
        (self.fun)(self.source.current(), self.rng.clone())
    }

    fn simplify(&mut self) -> bool {
        self.source.simplify()
    }

    fn complicate(&mut self) -> bool {
        self.source.complicate()
    }
}

//==============================================================================
// Tests
//==============================================================================

#[cfg(test)]
mod test {
    use std::collections::HashSet;

    use rand::RngCore;

    use crate::strategy::just::Just;
    use super::*;

    #[test]
    fn test_map() {
        TestRunner::default()
            .run(&(0..10).prop_map(|v| v * 2), |v| {
                assert!(0 == v % 2);
                Ok(())
            }).unwrap();
    }

    #[test]
    fn test_map_into() {
        TestRunner::default()
            .run(&(0..10u8).prop_map_into::<usize>(), |v| {
                assert!(v < 10);
                Ok(())
            }).unwrap();
    }

    #[test]
    fn perturb_uses_same_rng_every_time() {
        let mut runner = TestRunner::default();
        let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32());

        for _ in 0..16 {
            let value = input.new_tree(&mut runner).unwrap();
            assert_eq!(value.current(), value.current());
        }
    }

    #[test]
    fn perturb_uses_varying_random_seeds() {
        let mut runner = TestRunner::default();
        let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32());

        let mut seen = HashSet::new();
        for _ in 0..64 {
            seen.insert(input.new_tree(&mut runner).unwrap().current());
        }

        assert_eq!(64, seen.len());
    }
}