1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
//-
// Copyright 2017 Mazdak Farrokhzad
//
// 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.

//! [`proptest`] is a property testing framework (i.e., the [`QuickCheck`] family)
//! inspired by the [Hypothesis](http://hypothesis.works/) framework for
//! Python.
//!
//! [`quickcheck`] is another property testing framework for Rust which uses
//! a shrinking logic similar to Haskell's [`QuickCheck`].
//!
//! **This crate provides interoperability between quickcheck and proptest.**
//! Currently, this is one way - if you've implemented quickcheck's
//! [`Arbitrary`] trait as well as [`Debug`], which is a temporary requirement,
//! then you may get back the equivalent [`Strategy`] in proptest.
//!
//! ## Status of this crate
//!
//! This crate is unlikely to see major changes. Any breaking changes
//! are only likely to come as a result of changes in the dependencies used by
//! this crate, in particular proptest or quickcheck. When any of those crates
//! make breaking changes that affect this crate, then the major version of
//! this crate will be bumped.
//!
//! See the [changelog] for a full list of substantial historical changes,
//! breaking and otherwise.
//!
//! ## Using the interoperability layer
//!
//! Assuming that you already have a `Cargo.toml` file in your project with,
//! among other things, the following:
//!
//! ```toml 
//! [dependencies]
//!
//! quickcheck = "0.6.0"
//! proptest   = "0.4.1"
//! ```
//!
//! Now add this crate to your dependencies:
//! 
//! ```toml
//! [dependencies]
//!
//! quickcheck = "0.6.0"
//! proptest   = "0.4.1"
//! proptest_quickcheck_interop = "2.0.0"
//! ```
//!
//! Let's now assume that `usize` is a complex type for which you have
//! implemented `quickcheck::Arbitrary`. You wish you reuse this in proptest
//! or if you simply prefer the implementation provided by quickcheck.
//! To do so, you can use [`from_qc`]:
//!
//! ```rust
//! // Import crates:
//! #[macro_use] extern crate proptest;
//! extern crate proptest_quickcheck_interop as pqci;
//!
//! // And what we need into our scope:
//! use proptest::strategy::Strategy;
//! use pqci::from_qc;
//!
//! /// Given a usize returns the nearest usize that is also even.
//! fn make_even(x: usize) -> usize {
//!     if x % 2 == 1 { x - 1 } else { x }
//! }
//!
//! proptest! {
//!    /// A property asserting that make_even always produces an even usize.
//!    fn always_even(ref x in from_qc::<usize>().prop_map(make_even)) {
//!        prop_assert!(x % 2 == 0);
//!    }
//! }
//!
//! fn main() {
//!     always_even();
//! }
//! ```
//!
//! If you want to control the `size` of the input generated by quickcheck
//! you may instead use [`from_qc_sized(size)`][`from_qc_sized`]. If you use,
//! [`from_qc`], then the default size used by quickcheck is used.
//!
//! [`from_qc`]: https://docs.rs/proptest-quickcheck-interop/2.0.0/proptest_quickcheck_interop/fn.from_qc.html
//! [`from_qc_sized`]: https://docs.rs/proptest-quickcheck-interop/2.0.0/proptest_quickcheck_interop/fn.from_qc_sized.html
//!
//! [changelog]:
//! https://github.com/Centril/proptest-quickcheck-interop/blob/master/CHANGELOG.md
//!
//! [`Debug`]: https://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
//!
//! [`Arbitrary`]: https://docs.rs/quickcheck/0.6.0/quickcheck/trait.Arbitrary.html
//!
//! [`proptest`]: https://crates.io/crates/proptest
//!
//! [`quickcheck`]: https://crates.io/crates/quickcheck
//!
//! [`Strategy`]: https://docs.rs/proptest/0.4.1/proptest/strategy/trait.Strategy.html

#![deny(missing_docs)]

//==============================================================================
// Imports:
//==============================================================================

extern crate proptest;
extern crate quickcheck as quickcheck_crate;

use std::mem;
use std::marker::PhantomData;
use std::fmt::{Debug, Formatter, Result as FResult};

use quickcheck_crate::{Arbitrary, Gen, Rng};

use proptest::strategy::*;
use proptest::test_runner::TestRunner;
use proptest::prelude::XorShiftRng;

//==============================================================================
// Convenience API:
//==============================================================================

/// Constructs a new [`Strategy`] for any type that implements [`quickcheck`]'s
/// [`Arbitrary`] trait as well as [`Debug`] (a temporary requirement).
/// You may use this to gain interoperability by reusing implementations of
/// [`Arbitrary`] that you've already defined for some type.
///
/// Using this version, the size parameter controlling the size of inputs will
/// be the default one used by `quickcheck`. This parameter is passed to the
/// implementation of `Arbitrary`. If you want to provide some other value,
/// you may instead use [`from_qc_sized`].
///
/// [`Debug`]: https://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
/// [`Arbitrary`]: https://docs.rs/quickcheck/0.6.0/quickcheck/trait.Arbitrary.html
/// [`from_qc_sized`]: https://docs.rs/proptest-quickcheck-interop//proptest_quickcheck_interop/fn.from_qc_sized.html
/// [`quickcheck`]: https://crates.io/crates/quickcheck
/// [`Strategy`]: https://docs.rs/proptest/0.4.1/proptest/strategy/trait.Strategy.html
pub fn from_qc<A: Arbitrary + Debug>() -> QCStrategy<A> {
    QCStrategy::new(qc_gen_size())
}

/// Copied from:
/// https://docs.rs/quickcheck/0.6.0/src/quickcheck/tester.rs.html#35-41
/// TODO: Remove if @burntsushi makes this pub.
fn qc_gen_size() -> usize {
    use std::env;
    let default = 100;
    match env::var("QUICKCHECK_GENERATOR_SIZE") {
        Ok(val) => val.parse().unwrap_or(default),
        Err(_) => default,
    }
}

/// Constructs a new [`Strategy`] for any type that implements [`quickcheck`]'s
/// [`Arbitrary`] trait as well as [`Debug`] (a temporary requirement).
/// You may use this to gain interoperability by reusing implementations of
/// [`Arbitrary`] that you've already defined for some type.
///
/// Using this version, you may provide a size parameter controlling the size
/// of inputs. This parameter is passed to the implementation of `Arbitrary`.
///
/// [`Debug`]: https://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
/// [`Arbitrary`]: https://docs.rs/quickcheck/0.6.0/quickcheck/trait.Arbitrary.html
/// [`quickcheck`]: https://crates.io/crates/quickcheck
/// [`Strategy`]: https://docs.rs/proptest/0.4.1/proptest/strategy/trait.Strategy.html
pub fn from_qc_sized<A: Arbitrary + Debug>(size: usize) -> QCStrategy<A> {
    QCStrategy::new(size)
}

//==============================================================================
// The strategy
//==============================================================================

/// `QCStrategy` is a [`Strategy`] that provides interoperability with
/// [`quickcheck`]'s [`Arbitrary`] trait. If you have any type implementing
/// [`Arbitrary`] and [`Debug`], which a temporary requirement, then you may
/// get back the equivalent Strategy in proptest.
///
/// [`Debug`]: https://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
/// [`Arbitrary`]: https://docs.rs/quickcheck/0.6.0/quickcheck/trait.Arbitrary.html
/// [`quickcheck`]: https://crates.io/crates/quickcheck
/// [`Strategy`]: https://docs.rs/proptest/0.4.1/proptest/strategy/trait.Strategy.html
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct QCStrategy<A: Arbitrary + Debug> {
    __ph: PhantomData<A>,
    size: usize,
}

/// The [`ValueTree`] implementation for [`QCStrategy`].
///
/// [`QCStrategy`]: https://docs.rs/proptest-quickcheck-interop//proptest_quickcheck_interop/struct.QCStrategy.html
/// [`ValueTree`]: https://docs.rs/proptest/0.4.1/proptest/strategy/trait.ValueTree.html
pub struct QCValueTree<A: Debug> {
    curr: A,
    prev: Option<A>,
    shrinker: Box<Iterator<Item = A>>
}

impl<A: Arbitrary + Debug> QCStrategy<A> {
    /// Constructs a new `QCStrategy` given a `size` parameter that:
    ///
    /// > controls the size of random values generated. For example, it
    /// > specifies the maximum length of a randomly generated vector and also
    /// > will specify the maximum magnitude of a randomly generated number.
    ///
    /// as defined by [`quickcheck`]
    ///
    /// [`quickcheck`]: https://crates.io/crates/quickcheck
    pub fn new(size: usize) -> Self {
        Self { __ph: PhantomData, size }
    }
}

impl<A: Debug> QCValueTree<A> {
    /// Constructs a new `QCValueTree`, that is the [`ValueTree`] for
    /// [`QCStrategy`] given:
    /// + the current value,
    /// + the iterator producing increasingly shrunken versions of the current
    /// value given.
    ///
    /// [`QCStrategy`]: struct.QCStrategy
    /// [`ValueTree`]: trait.ValueTree
    fn new(curr: A, shrinker: Box<Iterator<Item = A>>) -> Self {
        Self { prev: None, curr, shrinker }
    }
}

impl<A: Arbitrary + Debug> Strategy for QCStrategy<A> {
    type Value = QCValueTree<A>;

    fn new_value(&self, runner: &mut TestRunner) -> NewTree<Self> {
        let mut gen = XorShiftGen::new(runner.rng(), self.size);
        let curr = A::arbitrary(&mut gen);
        let shrinker = curr.shrink();
        Ok(QCValueTree::new(curr, shrinker))
    }
}

impl<A: Clone + Debug> ValueTree for QCValueTree<A> {
    type Value = A;

    fn current(&self) -> Self::Value {
        self.curr.clone()
    }

    fn complicate(&mut self) -> bool {
        // We can only complicate if we previously simplified.
        // Complicating twice in a row without interleaved simplification
        // is guaranteed to always yield false for the second call.
        if let Some(prev) = self.prev.take() {
            // Throw away the current value!
            self.curr = prev;
            true
        } else {
            false
        }
    }

    fn simplify(&mut self) -> bool {
        if let Some(simpler) = self.shrinker.next() {
            // Throw away the previous value and set the current value as prev.
            // Advance the iterator and set the current value to the next one.
            self.prev = Some(mem::replace(&mut self.curr, simpler));
            true
        } else {
            // Successive calls to .next() are now assumed to yield None,
            // Can't shrink anymore.
            false
        }
    }
}

impl<A: Debug> Debug for QCValueTree<A> {
    fn fmt(&self, fmt: &mut Formatter) -> FResult {
        fmt.debug_struct("QCValueTree")
           .field("curr", &self.curr)
           .field("prev", &self.prev)
           // We could change shrinker to be : Vec<A> instead, but that seems
           // not worth the cost of maintaining all the shrinked-to elements
           // in the ValueTree. If the iterator is side-effecting the behaviour
           // may also be quite strange.
           .field("shrinker", &"<iterator>")
           .finish()
    }
}

//==============================================================================
// XorShiftGen wrapper
//==============================================================================

/// A wrapper around a mutable reference of [`XorShiftRng`] and a `size` that
/// controls the size of random values generated makes for an implementation
/// of a [`Gen`].
///
/// [`XorShiftRng`]: https://docs.rs/rand/0.4.2/rand/struct.XorShiftRng.html
/// [`Gen`]: https://docs.rs/quickcheck/0.6.0/quickcheck/trait.Gen.html
#[derive(Debug)]
struct XorShiftGen<'a> {
    rng:  &'a mut XorShiftRng,
    size: usize,
}

impl<'a> XorShiftGen<'a> {
    /// Construct a new generator given the backing RNG and the
    /// size controlling the size of random values generated.
    pub fn new(rng: &'a mut XorShiftRng, size: usize) -> Self {
        Self { rng, size }
    }
}

impl<'a> Rng for XorShiftGen<'a> {
    fn next_u32(&mut self) -> u32 { self.rng.next_u32() }
}

impl<'a> Gen for XorShiftGen<'a> {
    fn size(&self) -> usize { self.size }
}

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

#[cfg(test)]
mod tests {
    use super::*;

    impl Clone for QCValueTree<Vec<u32>> {
        /// Only implemented so that the implementation can be tested.
        /// As to why this is not a public API, read the note below.
        fn clone(&self) -> Self {
            // We assume that:
            //
            // let x = A::arbitrary(gen);
            // let s1 = x.clone().shrink();
            // let s2 = x.shrink();
            // assert_eq(s1.collect::<Vec<A>>(), s2.collect::<Vec<A>>());
            //
            // always holds. In other words, that shrinking is deterministic.
            // We also assume that:
            //
            // A::arbitrary(gen);
            // let s = x.shrink();
            // let y = x.next()?;
            // assert_eq!(x.next(), y.shrink().next());
            //
            // always holds.
            //
            // It may not actually hold for all A, but we don't care, as we only
            // provide Clone for testing purposes and we pick A = u32 for which
            // it always holds.
            QCValueTree {
                prev: self.prev.clone(),
                curr: self.curr.clone(),
                shrinker: self.curr.shrink()
            }
        }
    }

    #[test]
    fn contract_followed_by_qc_strategy() {
        check_strategy_sanity(from_qc_sized::<Vec<u32>>(10), None);
    }
}