quickcheck-0.9.0/.gitignore010066400017500000144000000000531320734732200140420ustar0000000000000000doc .*.swp tags target build Cargo.lock *~ quickcheck-0.9.0/COPYING010064400017500000144000000001761274016737000131150ustar0000000000000000This project is dual-licensed under the Unlicense and MIT licenses. You may use this code under the terms of either license. quickcheck-0.9.0/Cargo.toml.orig010064400017500000144000000016761353051535500147550ustar0000000000000000[package] name = "quickcheck" version = "0.9.0" #:version authors = ["Andrew Gallant "] description = "Automatic property based testing with shrinking." documentation = "http://burntsushi.net/rustdoc/quickcheck/" homepage = "https://github.com/BurntSushi/quickcheck" repository = "https://github.com/BurntSushi/quickcheck" readme = "README.md" keywords = ["testing", "quickcheck", "property", "shrinking", "fuzz"] categories = ["development-tools::testing"] license = "Unlicense/MIT" exclude = ["/.travis.yml", "/Makefile", "/ctags.rust", "/session.vim"] edition = "2018" [workspace] members = ["quickcheck_macros"] [features] default = ["regex", "use_logging"] unstable = [] use_logging = ["log", "env_logger"] regex = ["env_logger/regex"] [lib] name = "quickcheck" [dependencies] env_logger = { version = "0.6.0", default-features = false, optional = true } log = { version = "0.4", optional = true } rand = "0.7" rand_core = "0.5" quickcheck-0.9.0/Cargo.toml0000644000000027030000000000000112130ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "quickcheck" version = "0.9.0" authors = ["Andrew Gallant "] exclude = ["/.travis.yml", "/Makefile", "/ctags.rust", "/session.vim"] description = "Automatic property based testing with shrinking." homepage = "https://github.com/BurntSushi/quickcheck" documentation = "http://burntsushi.net/rustdoc/quickcheck/" readme = "README.md" keywords = ["testing", "quickcheck", "property", "shrinking", "fuzz"] categories = ["development-tools::testing"] license = "Unlicense/MIT" repository = "https://github.com/BurntSushi/quickcheck" [lib] name = "quickcheck" [dependencies.env_logger] version = "0.6.0" optional = true default-features = false [dependencies.log] version = "0.4" optional = true [dependencies.rand] version = "0.7" [dependencies.rand_core] version = "0.5" [features] default = ["regex", "use_logging"] regex = ["env_logger/regex"] unstable = [] use_logging = ["log", "env_logger"] quickcheck-0.9.0/LICENSE-MIT010064400017500000144000000020711274016737000135120ustar0000000000000000The MIT License (MIT) Copyright (c) 2015 Andrew Gallant Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. quickcheck-0.9.0/README.md010064400017500000144000000406011343052660600133340ustar0000000000000000QuickCheck is a way to do property based testing using randomly generated input. This crate comes with the ability to randomly generate and shrink integers, floats, tuples, booleans, lists, strings, options and results. All QuickCheck needs is a property function—it will then randomly generate inputs to that function and call the property for each set of inputs. If the property fails (whether by a runtime error like index out-of-bounds or by not satisfying your property), the inputs are "shrunk" to find a smaller counter-example. The shrinking strategies for lists and numbers use a binary search to cover the input space quickly. (It should be the same strategy used in [Koen Claessen's QuickCheck for Haskell](http://hackage.haskell.org/package/QuickCheck).) [![Build status](https://travis-ci.org/BurntSushi/quickcheck.svg?branch=master)](https://travis-ci.org/BurntSushi/quickcheck) [![](http://meritbadge.herokuapp.com/quickcheck)](https://crates.io/crates/quickcheck) Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). ### Documentation The API is fully documented: [http://burntsushi.net/rustdoc/quickcheck/](http://burntsushi.net/rustdoc/quickcheck/). ### Simple example Here's an example that tests a function that reverses a vector: ```rust #[cfg(test)] #[macro_use] extern crate quickcheck; fn reverse(xs: &[T]) -> Vec { let mut rev = vec!(); for x in xs.iter() { rev.insert(0, x.clone()) } rev } #[cfg(test)] mod tests { quickcheck! { fn prop(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) } } } ``` This example uses the `quickcheck!` macro, which is backwards compatible with old versions of Rust. ### The `#[quickcheck]` attribute (requires Rust 1.30 or later) To make it easier to write QuickCheck tests, the `#[quickcheck]` attribute will convert a property function into a `#[test]` function. To use the `#[quickcheck]` attribute, you must import the `quickcheck` macro from the `quickcheck_macros` crate: ```rust #[cfg(test)] extern crate quickcheck; #[cfg(test)] #[macro_use(quickcheck)] extern crate quickcheck_macros; #[cfg(test)] mod tests { fn reverse(xs: &[T]) -> Vec { let mut rev = vec!(); for x in xs { rev.insert(0, x.clone()) } rev } #[quickcheck] fn double_reversal_is_identity(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) } } ``` ### Installation `quickcheck` is on `crates.io`, so you can include it in your project like so: ```toml [dependencies] quickcheck = "0.8" ``` If you're only using `quickcheck` in your test code, then you can add it as a development dependency instead: ```toml [dev-dependencies] quickcheck = "0.8" ``` If you want to use the `#[quickcheck]` attribute, then add `quickcheck_macros` ```toml [dev-dependencies] quickcheck = "0.8" quickcheck_macros = "0.8" ``` N.B. When using `quickcheck` (either directly or via the attributes), `RUST_LOG=quickcheck` enables `info!` so that it shows useful output (like the number of tests passed). This is **not** needed to show witnesses for failures. Crate features: - `"unstable"`: Enables Arbitrary implementations that require the Rust nightly channel. - `"use_logging"`: (Enabled by default.) Enables the log messages governed `RUST_LOG`. - `"regex"`: (Enabled by default.) Enables the use of regexes with `env_logger`. Prior to quickcheck 0.8, this crate had an `i128` feature for enabling support for 128-bit integers. As of quickcheck 0.8, whose minimium supported Rust version is Rust 1.30.0, this feature is now provided by default and thus no longer available. ### Alternative Rust crates for property testing The [`proptest`](https://docs.rs/proptest) crate is inspired by the [Hypothesis](http://hypothesis.works) framework for Python. You can read a comparison between `proptest` and `quickcheck` [here](https://github.com/AltSysrq/proptest/blob/master/README.md#differences-between-quickcheck-and-proptest) and [here](https://github.com/AltSysrq/proptest/issues/15#issuecomment-348382287). In particular, `proptest` improves on the concept of shrinking. So if you've ever had problems/frustration with shrinking in `quickcheck`, then `proptest` might be worth a try! ### Discarding test results (or, properties are polymorphic!) Sometimes you want to test a property that only holds for a *subset* of the possible inputs, so that when your property is given an input that is outside of that subset, you'd discard it. In particular, the property should *neither* pass nor fail on inputs outside of the subset you want to test. But properties return boolean values—which either indicate pass or fail. To fix this, we need to take a step back and look at the type of the `quickcheck` function: ```rust pub fn quickcheck(f: A) { // elided } ``` So `quickcheck` can test any value with a type that satisfies the `Testable` trait. Great, so what is this `Testable` business? ```rust pub trait Testable { fn result(&self, &mut G) -> TestResult; } ``` This trait states that a type is testable if it can produce a `TestResult` given a source of randomness. (A `TestResult` stores information about the results of a test, like whether it passed, failed or has been discarded.) Sure enough, `bool` satisfies the `Testable` trait: ```rust impl Testable for bool { fn result(&self, _: &mut G) -> TestResult { TestResult::from_bool(*self) } } ``` But in the example, we gave a *function* to `quickcheck`. Yes, functions can satisfy `Testable` too! ```rust impl Testable for fn(A) -> B { fn result(&self, g: &mut G) -> TestResult { // elided } } ``` Which says that a function satisfies `Testable` if and only if it has a single parameter type (whose values can be randomly generated and shrunk) and returns any type (that also satisfies `Testable`). So a function with type `fn(usize) -> bool` satisfies `Testable` since `usize` satisfies `Arbitrary` and `bool` satisfies `Testable`. So to discard a test, we need to return something other than `bool`. What if we just returned a `TestResult` directly? That should work, but we'll need to make sure `TestResult` satisfies `Testable`: ```rust impl Testable for TestResult { fn result(&self, _: &mut G) -> TestResult { self.clone() } } ``` Now we can test functions that return a `TestResult` directly. As an example, let's test our reverse function to make sure that the reverse of a vector of length 1 is equal to the vector itself. ```rust fn prop(xs: Vec) -> TestResult { if xs.len() != 1 { return TestResult::discard() } TestResult::from_bool(xs == reverse(&xs)) } quickcheck(prop as fn(Vec) -> TestResult); ``` (A full working program for this example is in [`examples/reverse_single.rs`](https://github.com/BurntSushi/quickcheck/blob/master/examples/reverse_single.rs).) So now our property returns a `TestResult`, which allows us to encode a bit more information. There are a few more [convenience functions defined for the `TestResult` type](http://docs.rs/quickcheck/0.8/quickcheck/struct.TestResult.html). For example, we can't just return a `bool`, so we convert a `bool` value to a `TestResult`. (The ability to discard tests allows you to get similar functionality as Haskell's `==>` combinator.) N.B. Since discarding a test means it neither passes nor fails, `quickcheck` will try to replace the discarded test with a fresh one. However, if your condition is seldom met, it's possible that `quickcheck` will have to settle for running fewer tests than usual. By default, if `quickcheck` can't find `100` valid tests after trying `10,000` times, then it will give up. These parameters may be changed using [`QuickCheck::tests`](https://docs.rs/quickcheck/0.4.1/quickcheck/struct.QuickCheck.html#method.tests) and [`QuickCheck::max_tests`](https://docs.rs/quickcheck/0.4.1/quickcheck/struct.QuickCheck.html#method.max_tests), or by setting the `QUICKCHECK_TESTS` and `QUICKCHECK_MAX_TESTS` environment variables. There is also `QUICKCHECK_MIN_TESTS_PASSED` which sets the minimum number of valid tests that need pass (defaults to `0`) in order for it to be considered a success. ### Shrinking Shrinking is a crucial part of QuickCheck that simplifies counter-examples for your properties automatically. For example, if you erroneously defined a function for reversing vectors as: (my apologies for the contrived example) ```rust fn reverse(xs: &[T]) -> Vec { let mut rev = vec![]; for i in 1..xs.len() { rev.insert(0, xs[i].clone()) } rev } ``` And a property to test that `xs == reverse(reverse(xs))`: ```rust fn prop(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) } quickcheck(prop as fn(Vec) -> bool); ``` Then without shrinking, you might get a counter-example like: ``` [quickcheck] TEST FAILED. Arguments: ([-17, 13, -12, 17, -8, -10, 15, -19, -19, -9, 11, -5, 1, 19, -16, 6]) ``` Which is pretty mysterious. But with shrinking enabled, you're nearly guaranteed to get this counter-example every time: ``` [quickcheck] TEST FAILED. Arguments: ([0]) ``` Which is going to be much easier to debug. ### More Thorough Checking Quickcheck uses random input to test, so it won't always find bugs that could be uncovered with a particular property. You can improve your odds of finding these latent bugs by spending more CPU cycles asking quickcheck to find them for you. There are a few different ways to do this, and which one you choose is mostly a matter of taste. If you are finding yourself doing this sort of thing a lot, you might also be interested in trying out [`cargo fuzz`](https://github.com/rust-fuzz/cargo-fuzz), which runs in a loop by default. ##### Running in a Loop One approach is to run your quickcheck properties in a loop that just keeps going until you tell it to stop or it finds a bug. For example, you could use a bash script such as the following one. ```bash #!/usr/bin/bash while true do cargo test qc_ if [[ x$? != x0 ]] ; then exit $? fi done ``` One thing to note is that this script passes the `qc_` filter to `cargo test`. This assumes that you've prefixed all your quickcheck properties with `qc_`. You could leave off the filter, but then you would be running all your deterministic tests as well, which would take time away from quickcheck! Checking the return code and exiting is also important. Without that test, you won't ever notice when a failure happens. ##### Cranking the Number of Tests Another approach is to just ask quickcheck to run properties more times. You can do this either via the [tests()](https://docs.rs/quickcheck/0.8/quickcheck/struct.QuickCheck.html#method.tests) method, or via the `QUICKCHECK_TESTS` environment variable. This will cause quickcheck to run for a much longer time. Unlike, the loop approach this will take a bounded amount of time, which makes it more suitable for something like a release cycle that wants to really hammer your software. ##### Making Arbitrary Smarter This approach entails spending more time generating interesting inputs in your implementations of Arbitrary. The idea is to focus on the corner cases. This approach can be tricky because programmers are not usually great at intuiting corner cases, and the whole idea of property checking is to take that burden off the programmer. Despite the theoretical discomfort, this approach can turn out to be practical. ### Case study: The Sieve of Eratosthenes The [Sieve of Eratosthenes](http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) is a simple and elegant way to find all primes less than or equal to `N`. Briefly, the algorithm works by allocating an array with `N` slots containing booleans. Slots marked with `false` correspond to prime numbers (or numbers not known to be prime while building the sieve) and slots marked with `true` are known to not be prime. For each `n`, all of its multiples in this array are marked as true. When all `n` have been checked, the numbers marked `false` are returned as the primes. As you might imagine, there's a lot of potential for off-by-one errors, which makes it ideal for randomized testing. So let's take a look at my implementation and see if we can spot the bug: ```rust fn sieve(n: usize) -> Vec { if n <= 1 { return vec![]; } let mut marked = vec![false; n+1]; marked[0] = true; marked[1] = true; marked[2] = true; for p in 2..n { for i in (2*p..n).filter(|&n| n % p == 0) { marked[i] = true; } } marked.iter() .enumerate() .filter_map(|(i, &m)| if m { None } else { Some(i) }) .collect() } ``` Let's try it on a few inputs by hand: ``` sieve(3) => [2, 3] sieve(5) => [2, 3, 5] sieve(8) => [2, 3, 5, 7, 8] # !!! ``` Something has gone wrong! But where? The bug is rather subtle, but it's an easy one to make. It's OK if you can't spot it, because we're going to use QuickCheck to help us track it down. Even before looking at some example outputs, it's good to try and come up with some *properties* that are always satisfiable by the output of the function. An obvious one for the prime number sieve is to check if all numbers returned are prime. For that, we'll need an `is_prime` function: ```rust fn is_prime(n: usize) -> bool { n != 0 && n != 1 && (2..).take_while(|i| i*i <= n).all(|i| n % i != 0) } ``` All this is doing is checking to see if any number in `[2, sqrt(n)]` divides `n` with base cases for `0` and `1`. Now we can write our QuickCheck property: ```rust fn prop_all_prime(n: usize) -> bool { sieve(n).into_iter().all(is_prime) } ``` And finally, we need to invoke `quickcheck` with our property: ```rust fn main() { quickcheck(prop_all_prime as fn(usize) -> bool); } ``` A fully working source file with this code is in [`examples/sieve.rs`](https://github.com/BurntSushi/quickcheck/blob/master/examples/sieve.rs). The output of running this program has this message: ``` [quickcheck] TEST FAILED. Arguments: (4) ``` Which says that `sieve` failed the `prop_all_prime` test when given `n = 4`. Because of shrinking, it was able to find a (hopefully) minimal counter-example for our property. With such a short counter-example, it's hopefully a bit easier to narrow down where the bug is. Since `4` is returned, it's likely never marked as being not prime. Since `4` is a multiple of `2`, its slot should be marked as `true` when `p = 2` on these lines: ```rust for i in (2*p..n).filter(|&n| n % p == 0) { marked[i] = true; } ``` Ah! But does the `..` (range) operator include `n`? Nope! This particular operator is a half-open interval. A `2*p..n` range will never yield `4` when `n = 4`. When we change this to `2*p..n+1`, all tests pass. In addition, if our bug happened to result in an index out-of-bounds error, then `quickcheck` can handle it just like any other failure—including shrinking on failures caused by runtime errors. But hold on... we're not done yet. Right now, our property tests that all the numbers returned by `sieve` are prime but it doesn't test if the list is complete. It does not ensure that all the primes between `0` and `n` are found. Here's a property that is more comprehensive: ```rust fn prop_prime_iff_in_the_sieve(n: usize) -> bool { sieve(n) == (0..(n + 1)).filter(|&i| is_prime(i)).collect::>() } ``` It tests that for each number between 0 and n, inclusive, the naive primality test yields the same result as the sieve. Now, if we run it: ```rust fn main() { quickcheck(prop_all_prime as fn(usize) -> bool); quickcheck(prop_prime_iff_in_the_sieve as fn(usize) -> bool); } ``` we see that it fails immediately for value n = 2. ``` [quickcheck] TEST FAILED. Arguments: (2) ``` If we inspect `sieve()` once again, we see that we mistakenly mark `2` as non-prime. Removing the line `marked[2] = true;` results in both properties passing. ### What's not in this port of QuickCheck? I think I've captured the key features, but there are still things missing: * As of now, only functions with 8 or fewer parameters can be quickchecked. This limitation can be lifted to some `N`, but requires an implementation for each `n` of the `Testable` trait. * Functions that fail because of a stack overflow are not caught by QuickCheck. Therefore, such failures will not have a witness attached to them. (I'd like to fix this, but I don't know how.) * `Coarbitrary` does not exist in any form in this package. I think it's possible; I just haven't gotten around to it yet. quickcheck-0.9.0/UNLICENSE010064400017500000144000000022731274016737000133320ustar0000000000000000This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to quickcheck-0.9.0/examples/btree_set_range.rs010064400017500000144000000033371353051520000173630ustar0000000000000000extern crate quickcheck; use quickcheck::{quickcheck, TestResult}; use std::collections::BTreeSet; use std::ops::Bound::{self, *}; /// Covers every `std::ops::Range*` plus variants with exclusive start. type RangeAny = (Bound, Bound); /// Mimic `RangeBounds::contains`, stabilized in Rust 1.35. trait RangeBounds { fn contains(&self, _: &T) -> bool; } impl RangeBounds for RangeAny { fn contains(&self, item: &T) -> bool { (match &self.0 { Included(start) => start <= item, Excluded(start) => start < item, Unbounded => true, }) && (match &self.1 { Included(end) => item <= end, Excluded(end) => item < end, Unbounded => true, }) } } /// Checks conditions where `BTreeSet::range` panics: /// - Panics if range start > end. /// - Panics if range start == end and both bounds are Excluded. fn panics(range: RangeAny) -> bool { match (&range.0, &range.1) { (Excluded(start), Excluded(end)) => start >= end, (Included(start), Excluded(end)) | (Excluded(start), Included(end)) | (Included(start), Included(end)) => start > end, (Unbounded, _) | (_, Unbounded) => false, } } /// Checks that `BTreeSet::range` returns all items contained in the given `range`. fn check_range(set: BTreeSet, range: RangeAny) -> TestResult { if panics(range) { TestResult::discard() } else { let xs: BTreeSet<_> = set.range(range).cloned().collect(); TestResult::from_bool( set.iter().all(|x| range.contains(x) == xs.contains(x)), ) } } fn main() { quickcheck(check_range as fn(_, _) -> TestResult); } quickcheck-0.9.0/examples/out_of_bounds.rs010064400017500000144000000006061353051434200171020ustar0000000000000000extern crate quickcheck; use quickcheck::{quickcheck, TestResult}; fn main() { fn prop(length: usize, index: usize) -> TestResult { let v: Vec<_> = (0..length).collect(); if index < length { TestResult::discard() } else { TestResult::must_fail(move || v[index]) } } quickcheck(prop as fn(usize, usize) -> TestResult); } quickcheck-0.9.0/examples/reverse.rs010064400017500000144000000006011353051434200157030ustar0000000000000000extern crate quickcheck; use quickcheck::quickcheck; fn reverse(xs: &[T]) -> Vec { let mut rev = vec![]; for x in xs { rev.insert(0, x.clone()) } rev } fn main() { fn equality_after_applying_twice(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) } quickcheck(equality_after_applying_twice as fn(Vec) -> bool); } quickcheck-0.9.0/examples/reverse_single.rs010064400017500000144000000007061353051434200172520ustar0000000000000000extern crate quickcheck; use quickcheck::{quickcheck, TestResult}; fn reverse(xs: &[T]) -> Vec { let mut rev = vec![]; for x in xs { rev.insert(0, x.clone()) } rev } fn main() { fn prop(xs: Vec) -> TestResult { if xs.len() != 1 { return TestResult::discard(); } TestResult::from_bool(xs == reverse(&*xs)) } quickcheck(prop as fn(Vec) -> TestResult); } quickcheck-0.9.0/examples/sieve.rs010064400017500000144000000017141353051434200153510ustar0000000000000000extern crate quickcheck; use quickcheck::quickcheck; fn sieve(n: usize) -> Vec { if n <= 1 { return vec![]; } let mut marked = vec![false; n + 1]; marked[0] = true; marked[1] = true; marked[2] = true; for p in 2..n { for i in (2 * p..n).filter(|&n| n % p == 0) { marked[i] = true; } } marked .iter() .enumerate() .filter_map(|(i, &m)| if m { None } else { Some(i) }) .collect() } fn is_prime(n: usize) -> bool { n != 0 && n != 1 && (2..).take_while(|i| i * i <= n).all(|i| n % i != 0) } fn main() { fn prop_all_prime(n: usize) -> bool { sieve(n).into_iter().all(is_prime) } fn prop_prime_iff_in_the_sieve(n: usize) -> bool { sieve(n) == (0..(n + 1)).filter(|&i| is_prime(i)).collect::>() } quickcheck(prop_all_prime as fn(usize) -> bool); quickcheck(prop_prime_iff_in_the_sieve as fn(usize) -> bool); } quickcheck-0.9.0/examples/sort.rs010064400017500000144000000023171353051434200152250ustar0000000000000000// This is a buggy quick sort implementation, QuickCheck will find the bug for // you. extern crate quickcheck; use quickcheck::quickcheck; fn smaller_than(xs: &[T], pivot: &T) -> Vec { return xs.iter().filter(|&x| *x < *pivot).map(|x| x.clone()).collect(); } fn larger_than(xs: &[T], pivot: &T) -> Vec { return xs.iter().filter(|&x| *x > *pivot).map(|x| x.clone()).collect(); } fn sortk(x: &T, xs: &[T]) -> Vec { let mut result: Vec = sort(&*smaller_than(xs, x)); let last_part = sort(&*larger_than(xs, x)); result.push(x.clone()); result.extend(last_part.iter().map(|x| x.clone())); result } fn sort(list: &[T]) -> Vec { if list.is_empty() { vec![] } else { sortk(&list[0], &list[1..]) } } fn main() { fn is_sorted(xs: Vec) -> bool { for win in xs.windows(2) { if win[0] > win[1] { return false; } } true } fn keeps_length(xs: Vec) -> bool { xs.len() == sort(&*xs).len() } quickcheck(keeps_length as fn(Vec) -> bool); quickcheck(is_sorted as fn(Vec) -> bool) } quickcheck-0.9.0/rustfmt.toml010064400017500000144000000000541353051433200144460ustar0000000000000000max_width = 79 use_small_heuristics = "max" quickcheck-0.9.0/src/arbitrary.rs010064400017500000144000001154241353051434200152120ustar0000000000000000use std::char; use std::collections::{ BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque, }; use std::env; use std::ffi::OsString; use std::hash::{BuildHasher, Hash}; use std::iter::{empty, once}; use std::net::{ IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, }; use std::num::Wrapping; use std::ops::{Bound, Range, RangeFrom, RangeFull, RangeTo}; use std::path::PathBuf; use std::sync::Arc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use rand::seq::SliceRandom; use rand::{self, Rng, RngCore}; /// `Gen` wraps a `rand::RngCore` with parameters to control the distribution of /// random values. /// /// A value with type satisfying the `Gen` trait can be constructed with the /// `gen` function in this crate. pub trait Gen: RngCore { fn size(&self) -> usize; } /// StdGen is the default implementation of `Gen`. /// /// Values of type `StdGen` can be created with the `gen` function in this /// crate. pub struct StdGen { rng: R, size: usize, } impl StdGen { /// Returns a `StdGen` with the given configuration using any random number /// generator. /// /// The `size` parameter 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. pub fn new(rng: R, size: usize) -> StdGen { StdGen { rng: rng, size: size } } } impl RngCore for StdGen { fn next_u32(&mut self) -> u32 { self.rng.next_u32() } // some RNGs implement these more efficiently than the default, so // we might as well defer to them. fn next_u64(&mut self) -> u64 { self.rng.next_u64() } fn fill_bytes(&mut self, dest: &mut [u8]) { self.rng.fill_bytes(dest) } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { self.rng.try_fill_bytes(dest) } } impl Gen for StdGen { fn size(&self) -> usize { self.size } } /// StdThreadGen is an RNG in thread-local memory. /// /// This is the default RNG used by quickcheck. pub struct StdThreadGen(StdGen); impl StdThreadGen { /// Returns a new thread-local RNG. /// /// The `size` parameter 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. pub fn new(size: usize) -> StdThreadGen { StdThreadGen(StdGen { rng: rand::thread_rng(), size: size }) } } impl RngCore for StdThreadGen { fn next_u32(&mut self) -> u32 { self.0.next_u32() } // some RNGs implement these more efficiently than the default, so // we might as well defer to them. fn next_u64(&mut self) -> u64 { self.0.next_u64() } fn fill_bytes(&mut self, dest: &mut [u8]) { self.0.fill_bytes(dest) } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { self.0.try_fill_bytes(dest) } } impl Gen for StdThreadGen { fn size(&self) -> usize { self.0.size } } /// Creates a shrinker with zero elements. pub fn empty_shrinker() -> Box> { Box::new(empty()) } /// Creates a shrinker with a single element. pub fn single_shrinker(value: A) -> Box> { Box::new(once(value)) } /// `Arbitrary` describes types whose values can be randomly generated and /// shrunk. /// /// Aside from shrinking, `Arbitrary` is different from the `std::Rand` trait /// in that it uses a `Gen` to control the distribution of random values. /// /// As of now, all types that implement `Arbitrary` must also implement /// `Clone`. (I'm not sure if this is a permanent restriction.) /// /// They must also be sendable and static since every test is run in its own /// thread using `thread::Builder::spawn`, which requires the `Send + 'static` /// bounds. pub trait Arbitrary: Clone + Send + 'static { fn arbitrary(g: &mut G) -> Self; fn shrink(&self) -> Box> { empty_shrinker() } } impl Arbitrary for () { fn arbitrary(_: &mut G) -> () { () } } impl Arbitrary for bool { fn arbitrary(g: &mut G) -> bool { g.gen() } fn shrink(&self) -> Box> { if *self { single_shrinker(false) } else { empty_shrinker() } } } impl Arbitrary for Option { fn arbitrary(g: &mut G) -> Option { if g.gen() { None } else { Some(Arbitrary::arbitrary(g)) } } fn shrink(&self) -> Box>> { match *self { None => empty_shrinker(), Some(ref x) => { let chain = single_shrinker(None).chain(x.shrink().map(Some)); Box::new(chain) } } } } impl Arbitrary for Result { fn arbitrary(g: &mut G) -> Result { if g.gen() { Ok(Arbitrary::arbitrary(g)) } else { Err(Arbitrary::arbitrary(g)) } } fn shrink(&self) -> Box>> { match *self { Ok(ref x) => { let xs = x.shrink(); let tagged = xs.map(Ok); Box::new(tagged) } Err(ref x) => { let xs = x.shrink(); let tagged = xs.map(Err); Box::new(tagged) } } } } macro_rules! impl_arb_for_single_tuple { ($(($type_param:ident, $tuple_index:tt),)*) => { impl<$($type_param),*> Arbitrary for ($($type_param,)*) where $($type_param: Arbitrary,)* { fn arbitrary(g: &mut GEN) -> ($($type_param,)*) { ( $( $type_param::arbitrary(g), )* ) } fn shrink(&self) -> Box> { let iter = ::std::iter::empty(); $( let cloned = self.clone(); let iter = iter.chain(self.$tuple_index.shrink().map(move |shr_value| { let mut result = cloned.clone(); result.$tuple_index = shr_value; result })); )* Box::new(iter) } } }; } macro_rules! impl_arb_for_tuples { (@internal [$($acc:tt,)*]) => { }; (@internal [$($acc:tt,)*] ($type_param:ident, $tuple_index:tt), $($rest:tt,)*) => { impl_arb_for_single_tuple!($($acc,)* ($type_param, $tuple_index),); impl_arb_for_tuples!(@internal [$($acc,)* ($type_param, $tuple_index),] $($rest,)*); }; ($(($type_param:ident, $tuple_index:tt),)*) => { impl_arb_for_tuples!(@internal [] $(($type_param, $tuple_index),)*); }; } impl_arb_for_tuples! { (A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6), (H, 7), } impl Arbitrary for Vec { fn arbitrary(g: &mut G) -> Vec { let size = { let s = g.size(); g.gen_range(0, s) }; (0..size).map(|_| Arbitrary::arbitrary(g)).collect() } fn shrink(&self) -> Box>> { VecShrinker::new(self.clone()) } } ///Iterator which returns successive attempts to shrink the vector `seed` struct VecShrinker { seed: Vec, /// How much which is removed when trying with smaller vectors size: usize, /// The end of the removed elements offset: usize, /// The shrinker for the element at `offset` once shrinking of individual /// elements are attempted element_shrinker: Box>, } impl VecShrinker { fn new(seed: Vec) -> Box>> { let es = match seed.get(0) { Some(e) => e.shrink(), None => return empty_shrinker(), }; let size = seed.len(); Box::new(VecShrinker { seed: seed, size: size, offset: size, element_shrinker: es, }) } /// Returns the next shrunk element if any, `offset` points to the index /// after the returned element after the function returns fn next_element(&mut self) -> Option { loop { match self.element_shrinker.next() { Some(e) => return Some(e), None => match self.seed.get(self.offset) { Some(e) => { self.element_shrinker = e.shrink(); self.offset += 1; } None => return None, }, } } } } impl Iterator for VecShrinker where A: Arbitrary, { type Item = Vec; fn next(&mut self) -> Option> { // Try with an empty vector first if self.size == self.seed.len() { self.size /= 2; self.offset = self.size; return Some(vec![]); } if self.size != 0 { // Generate a smaller vector by removing the elements between // (offset - size) and offset let xs1 = self.seed[..(self.offset - self.size)] .iter() .chain(&self.seed[self.offset..]) .cloned() .collect(); self.offset += self.size; // Try to reduce the amount removed from the vector once all // previous sizes tried if self.offset > self.seed.len() { self.size /= 2; self.offset = self.size; } Some(xs1) } else { // A smaller vector did not work so try to shrink each element of // the vector instead Reuse `offset` as the index determining which // element to shrink // The first element shrinker is already created so skip the first // offset (self.offset == 0 only on first entry to this part of the // iterator) if self.offset == 0 { self.offset = 1 } match self.next_element() { Some(e) => Some( self.seed[..self.offset - 1] .iter() .cloned() .chain(Some(e).into_iter()) .chain(self.seed[self.offset..].iter().cloned()) .collect(), ), None => None, } } } } impl Arbitrary for BTreeMap { fn arbitrary(g: &mut G) -> BTreeMap { let vec: Vec<(K, V)> = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box>> { let vec: Vec<(K, V)> = self.clone().into_iter().collect(); Box::new( vec.shrink().map(|v| v.into_iter().collect::>()), ) } } impl< K: Arbitrary + Eq + Hash, V: Arbitrary, S: BuildHasher + Default + Clone + Send + 'static, > Arbitrary for HashMap { fn arbitrary(g: &mut G) -> Self { let vec: Vec<(K, V)> = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box> { let vec: Vec<(K, V)> = self.clone().into_iter().collect(); Box::new(vec.shrink().map(|v| v.into_iter().collect::())) } } impl Arbitrary for BTreeSet { fn arbitrary(g: &mut G) -> BTreeSet { let vec: Vec = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box>> { let vec: Vec = self.clone().into_iter().collect(); Box::new(vec.shrink().map(|v| v.into_iter().collect::>())) } } impl Arbitrary for BinaryHeap { fn arbitrary(g: &mut G) -> BinaryHeap { let vec: Vec = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box>> { let vec: Vec = self.clone().into_iter().collect(); Box::new( vec.shrink().map(|v| v.into_iter().collect::>()), ) } } impl< T: Arbitrary + Eq + Hash, S: BuildHasher + Default + Clone + Send + 'static, > Arbitrary for HashSet { fn arbitrary(g: &mut G) -> Self { let vec: Vec = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box> { let vec: Vec = self.clone().into_iter().collect(); Box::new(vec.shrink().map(|v| v.into_iter().collect::())) } } impl Arbitrary for LinkedList { fn arbitrary(g: &mut G) -> LinkedList { let vec: Vec = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box>> { let vec: Vec = self.clone().into_iter().collect(); Box::new( vec.shrink().map(|v| v.into_iter().collect::>()), ) } } impl Arbitrary for VecDeque { fn arbitrary(g: &mut G) -> VecDeque { let vec: Vec = Arbitrary::arbitrary(g); vec.into_iter().collect() } fn shrink(&self) -> Box>> { let vec: Vec = self.clone().into_iter().collect(); Box::new(vec.shrink().map(|v| v.into_iter().collect::>())) } } impl Arbitrary for IpAddr { fn arbitrary(g: &mut G) -> IpAddr { let ipv4: bool = g.gen(); if ipv4 { IpAddr::V4(Arbitrary::arbitrary(g)) } else { IpAddr::V6(Arbitrary::arbitrary(g)) } } } impl Arbitrary for Ipv4Addr { fn arbitrary(g: &mut G) -> Ipv4Addr { Ipv4Addr::new(g.gen(), g.gen(), g.gen(), g.gen()) } } impl Arbitrary for Ipv6Addr { fn arbitrary(g: &mut G) -> Ipv6Addr { Ipv6Addr::new( g.gen(), g.gen(), g.gen(), g.gen(), g.gen(), g.gen(), g.gen(), g.gen(), ) } } impl Arbitrary for SocketAddr { fn arbitrary(g: &mut G) -> SocketAddr { SocketAddr::new(Arbitrary::arbitrary(g), g.gen()) } } impl Arbitrary for SocketAddrV4 { fn arbitrary(g: &mut G) -> SocketAddrV4 { SocketAddrV4::new(Arbitrary::arbitrary(g), g.gen()) } } impl Arbitrary for SocketAddrV6 { fn arbitrary(g: &mut G) -> SocketAddrV6 { SocketAddrV6::new(Arbitrary::arbitrary(g), g.gen(), g.gen(), g.gen()) } } impl Arbitrary for PathBuf { fn arbitrary(g: &mut G) -> PathBuf { // use some real directories as guesses, so we may end up with // actual working directories in case that is relevant. let here = env::current_dir().unwrap_or(PathBuf::from("/test/directory")); let temp = env::temp_dir(); #[allow(deprecated)] let home = env::home_dir().unwrap_or(PathBuf::from("/home/user")); let choices = &[ here, temp, home, PathBuf::from("."), PathBuf::from(".."), PathBuf::from("../../.."), PathBuf::new(), ]; let mut p = choices.choose(g).unwrap().clone(); p.extend(Vec::::arbitrary(g).iter()); p } fn shrink(&self) -> Box> { let mut shrunk = vec![]; let mut popped = self.clone(); if popped.pop() { shrunk.push(popped); } // Iterating over a Path performs a small amount of normalization. let normalized = self.iter().collect::(); if normalized.as_os_str() != self.as_os_str() { shrunk.push(normalized); } // Add the canonicalized variant only if canonicalizing the path // actually does something, making it (hopefully) smaller. Also, ignore // canonicalization if canonicalization errors. if let Ok(canonicalized) = self.canonicalize() { if canonicalized.as_os_str() != self.as_os_str() { shrunk.push(canonicalized); } } Box::new(shrunk.into_iter()) } } impl Arbitrary for OsString { fn arbitrary(g: &mut G) -> OsString { OsString::from(String::arbitrary(g)) } fn shrink(&self) -> Box> { let mystring: String = self.clone().into_string().unwrap(); Box::new(mystring.shrink().map(|s| OsString::from(s))) } } impl Arbitrary for String { fn arbitrary(g: &mut G) -> String { let size = { let s = g.size(); g.gen_range(0, s) }; let mut s = String::with_capacity(size); for _ in 0..size { s.push(char::arbitrary(g)); } s } fn shrink(&self) -> Box> { // Shrink a string by shrinking a vector of its characters. let chars: Vec = self.chars().collect(); Box::new(chars.shrink().map(|x| x.into_iter().collect::())) } } impl Arbitrary for char { fn arbitrary(g: &mut G) -> char { let mode = g.gen_range(0, 100); match mode { 0..=49 => { // ASCII + some control characters g.gen_range(0, 0xB0) as u8 as char } 50..=59 => { // Unicode BMP characters loop { if let Some(x) = char::from_u32(g.gen_range(0, 0x10000)) { return x; } // ignore surrogate pairs } } 60..=84 => { // Characters often used in programming languages [ ' ', ' ', ' ', '\t', '\n', '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '-', '=', '+', '[', ']', '{', '}', ':', ';', '\'', '"', '\\', '|', ',', '<', '>', '.', '/', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ] .choose(g) .unwrap() .to_owned() } 85..=89 => { // Tricky Unicode, part 1 [ '\u{0149}', // a deprecated character '\u{fff0}', // some of "Other, format" category: '\u{fff1}', '\u{fff2}', '\u{fff3}', '\u{fff4}', '\u{fff5}', '\u{fff6}', '\u{fff7}', '\u{fff8}', '\u{fff9}', '\u{fffA}', '\u{fffB}', '\u{fffC}', '\u{fffD}', '\u{fffE}', '\u{fffF}', '\u{0600}', '\u{0601}', '\u{0602}', '\u{0603}', '\u{0604}', '\u{0605}', '\u{061C}', '\u{06DD}', '\u{070F}', '\u{180E}', '\u{110BD}', '\u{1D173}', '\u{e0001}', // tag '\u{e0020}', // tag space '\u{e000}', '\u{e001}', '\u{ef8ff}', // private use '\u{f0000}', '\u{ffffd}', '\u{ffffe}', '\u{fffff}', '\u{100000}', '\u{10FFFD}', '\u{10FFFE}', '\u{10FFFF}', // "Other, surrogate" characters are so that very special // that they are not even allowed in safe Rust, //so omitted here '\u{3000}', // ideographic space '\u{1680}', // other space characters are already covered by two next // branches ] .choose(g) .unwrap() .to_owned() } 90..=94 => { // Tricky unicode, part 2 char::from_u32(g.gen_range(0x2000, 0x2070)).unwrap() } 95..=99 => { // Completely arbitrary characters g.gen() } _ => unreachable!(), } } fn shrink(&self) -> Box> { Box::new((*self as u32).shrink().filter_map(char::from_u32)) } } macro_rules! unsigned_shrinker { ($ty:ty) => { mod shrinker { pub struct UnsignedShrinker { x: $ty, i: $ty, } impl UnsignedShrinker { pub fn new(x: $ty) -> Box> { if x == 0 { super::empty_shrinker() } else { Box::new( vec![0] .into_iter() .chain(UnsignedShrinker { x: x, i: x / 2 }), ) } } } impl Iterator for UnsignedShrinker { type Item = $ty; fn next(&mut self) -> Option<$ty> { if self.x - self.i < self.x { let result = Some(self.x - self.i); self.i = self.i / 2; result } else { None } } } } }; } macro_rules! unsigned_arbitrary { ($($ty:tt),*) => { $( impl Arbitrary for $ty { fn arbitrary(g: &mut G) -> $ty { #![allow(trivial_numeric_casts)] let s = g.size() as $ty; use std::cmp::{min, max}; g.gen_range(0, max(1, min(s, $ty::max_value()))) } fn shrink(&self) -> Box> { unsigned_shrinker!($ty); shrinker::UnsignedShrinker::new(*self) } } )* } } unsigned_arbitrary! { usize, u8, u16, u32, u64 } unsigned_arbitrary! { u128 } macro_rules! signed_shrinker { ($ty:ty) => { mod shrinker { pub struct SignedShrinker { x: $ty, i: $ty, } impl SignedShrinker { pub fn new(x: $ty) -> Box> { if x == 0 { super::empty_shrinker() } else { let shrinker = SignedShrinker { x: x, i: x / 2 }; let mut items = vec![0]; if shrinker.i < 0 { items.push(shrinker.x.abs()); } Box::new(items.into_iter().chain(shrinker)) } } } impl Iterator for SignedShrinker { type Item = $ty; fn next(&mut self) -> Option<$ty> { if (self.x - self.i).abs() < self.x.abs() { let result = Some(self.x - self.i); self.i = self.i / 2; result } else { None } } } } }; } macro_rules! signed_arbitrary { ($($ty:tt),*) => { $( impl Arbitrary for $ty { fn arbitrary(g: &mut G) -> $ty { use std::cmp::{min,max}; let upper = min(g.size(), $ty::max_value() as usize); let lower = if upper > $ty::max_value() as usize { $ty::min_value() } else { -(upper as $ty) }; g.gen_range(lower, max(1, upper as $ty)) } fn shrink(&self) -> Box> { signed_shrinker!($ty); shrinker::SignedShrinker::new(*self) } } )* } } signed_arbitrary! { isize, i8, i16, i32, i64 } signed_arbitrary! { i128 } impl Arbitrary for f32 { fn arbitrary(g: &mut G) -> f32 { let s = g.size(); g.gen_range(-(s as f32), s as f32) } fn shrink(&self) -> Box> { signed_shrinker!(i32); let it = shrinker::SignedShrinker::new(*self as i32); Box::new(it.map(|x| x as f32)) } } impl Arbitrary for f64 { fn arbitrary(g: &mut G) -> f64 { let s = g.size(); g.gen_range(-(s as f64), s as f64) } fn shrink(&self) -> Box> { signed_shrinker!(i64); let it = shrinker::SignedShrinker::new(*self as i64); Box::new(it.map(|x| x as f64)) } } impl Arbitrary for Wrapping { fn arbitrary(g: &mut G) -> Wrapping { Wrapping(T::arbitrary(g)) } fn shrink(&self) -> Box>> { Box::new(self.0.shrink().map(|inner| Wrapping(inner))) } } impl Arbitrary for Bound { fn arbitrary(g: &mut G) -> Bound { match g.gen_range(0, 3) { 0 => Bound::Included(T::arbitrary(g)), 1 => Bound::Excluded(T::arbitrary(g)), _ => Bound::Unbounded, } } fn shrink(&self) -> Box>> { match *self { Bound::Included(ref x) => { Box::new(x.shrink().map(Bound::Included)) } Bound::Excluded(ref x) => { Box::new(x.shrink().map(Bound::Excluded)) } Bound::Unbounded => empty_shrinker(), } } } impl Arbitrary for Range { fn arbitrary(g: &mut G) -> Range { Arbitrary::arbitrary(g)..Arbitrary::arbitrary(g) } fn shrink(&self) -> Box>> { Box::new( (self.start.clone(), self.end.clone()).shrink().map(|(s, e)| s..e), ) } } impl Arbitrary for RangeFrom { fn arbitrary(g: &mut G) -> RangeFrom { Arbitrary::arbitrary(g).. } fn shrink(&self) -> Box>> { Box::new(self.start.clone().shrink().map(|start| start..)) } } impl Arbitrary for RangeTo { fn arbitrary(g: &mut G) -> RangeTo { ..Arbitrary::arbitrary(g) } fn shrink(&self) -> Box>> { Box::new(self.end.clone().shrink().map(|end| ..end)) } } impl Arbitrary for RangeFull { fn arbitrary(_: &mut G) -> RangeFull { .. } } impl Arbitrary for Duration { fn arbitrary(gen: &mut G) -> Self { let seconds = u64::arbitrary(gen); let nanoseconds = u32::arbitrary(gen) % 1_000_000; Duration::new(seconds, nanoseconds) } fn shrink(&self) -> Box> { Box::new( (self.as_secs(), self.subsec_nanos()) .shrink() .map(|(secs, nanos)| Duration::new(secs, nanos % 1_000_000)), ) } } impl Arbitrary for Box { fn arbitrary(g: &mut G) -> Box { Box::new(A::arbitrary(g)) } fn shrink(&self) -> Box>> { Box::new((**self).shrink().map(Box::new)) } } impl Arbitrary for Arc { fn arbitrary(g: &mut G) -> Arc { Arc::new(A::arbitrary(g)) } fn shrink(&self) -> Box>> { Box::new((**self).shrink().map(Arc::new)) } } impl Arbitrary for SystemTime { fn arbitrary(gen: &mut G) -> Self { let after_epoch = bool::arbitrary(gen); let duration = Duration::arbitrary(gen); if after_epoch { UNIX_EPOCH + duration } else { UNIX_EPOCH - duration } } fn shrink(&self) -> Box> { let duration = match self.duration_since(UNIX_EPOCH) { Ok(duration) => duration, Err(e) => e.duration(), }; Box::new( duration .shrink() .flat_map(|d| vec![UNIX_EPOCH + d, UNIX_EPOCH - d]), ) } } #[cfg(test)] mod test { use super::Arbitrary; use rand; use std::collections::{ BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque, }; use std::fmt::Debug; use std::hash::Hash; use std::num::Wrapping; use std::path::PathBuf; #[test] fn arby_unit() { assert_eq!(arby::<()>(), ()); } #[test] fn arby_int() { rep(&mut || { let n: isize = arby(); assert!(n >= -5 && n <= 5); }); } #[test] fn arby_uint() { rep(&mut || { let n: usize = arby(); assert!(n <= 5); }); } fn arby() -> A { super::Arbitrary::arbitrary(&mut gen()) } fn gen() -> super::StdGen { super::StdGen::new(rand::thread_rng(), 5) } fn rep(f: &mut F) where F: FnMut() -> (), { for _ in 0..100 { f() } } // Shrink testing. #[test] fn unit() { eq((), vec![]); } #[test] fn bools() { eq(false, vec![]); eq(true, vec![false]); } #[test] fn options() { eq(None::<()>, vec![]); eq(Some(false), vec![None]); eq(Some(true), vec![None, Some(false)]); } #[test] fn results() { // Result doesn't implement the Hash trait, so these tests // depends on the order of shrunk results. Ug. // TODO: Fix this. ordered_eq(Ok::(true), vec![Ok(false)]); ordered_eq(Err::<(), bool>(true), vec![Err(false)]); } #[test] fn tuples() { eq((false, false), vec![]); eq((true, false), vec![(false, false)]); eq((true, true), vec![(false, true), (true, false)]); } #[test] fn triples() { eq((false, false, false), vec![]); eq((true, false, false), vec![(false, false, false)]); eq( (true, true, false), vec![(false, true, false), (true, false, false)], ); } #[test] fn quads() { eq((false, false, false, false), vec![]); eq((true, false, false, false), vec![(false, false, false, false)]); eq( (true, true, false, false), vec![(false, true, false, false), (true, false, false, false)], ); } #[test] fn ints() { // TODO: Test overflow? eq(5isize, vec![0, 3, 4]); eq(-5isize, vec![5, 0, -3, -4]); eq(0isize, vec![]); } #[test] fn ints8() { eq(5i8, vec![0, 3, 4]); eq(-5i8, vec![5, 0, -3, -4]); eq(0i8, vec![]); } #[test] fn ints16() { eq(5i16, vec![0, 3, 4]); eq(-5i16, vec![5, 0, -3, -4]); eq(0i16, vec![]); } #[test] fn ints32() { eq(5i32, vec![0, 3, 4]); eq(-5i32, vec![5, 0, -3, -4]); eq(0i32, vec![]); } #[test] fn ints64() { eq(5i64, vec![0, 3, 4]); eq(-5i64, vec![5, 0, -3, -4]); eq(0i64, vec![]); } #[test] fn ints128() { eq(5i128, vec![0, 3, 4]); eq(-5i128, vec![5, 0, -3, -4]); eq(0i128, vec![]); } #[test] fn uints() { eq(5usize, vec![0, 3, 4]); eq(0usize, vec![]); } #[test] fn uints8() { eq(5u8, vec![0, 3, 4]); eq(0u8, vec![]); } #[test] fn uints16() { eq(5u16, vec![0, 3, 4]); eq(0u16, vec![]); } #[test] fn uints32() { eq(5u32, vec![0, 3, 4]); eq(0u32, vec![]); } #[test] fn uints64() { eq(5u64, vec![0, 3, 4]); eq(0u64, vec![]); } #[test] fn uints128() { eq(5u128, vec![0, 3, 4]); eq(0u128, vec![]); } macro_rules! define_float_eq { ($ty:ty) => { fn eq(s: $ty, v: Vec<$ty>) { let shrunk: Vec<$ty> = s.shrink().collect(); for n in v { let found = shrunk.iter().any(|&i| i == n); if !found { panic!(format!( "Element {:?} was not found \ in shrink results {:?}", n, shrunk )); } } } }; } #[test] fn floats32() { define_float_eq!(f32); eq(0.0, vec![]); eq(-0.0, vec![]); eq(1.0, vec![0.0]); eq(2.0, vec![0.0, 1.0]); eq(-2.0, vec![0.0, 2.0, -1.0]); eq(1.5, vec![0.0]); } #[test] fn floats64() { define_float_eq!(f64); eq(0.0, vec![]); eq(-0.0, vec![]); eq(1.0, vec![0.0]); eq(2.0, vec![0.0, 1.0]); eq(-2.0, vec![0.0, 2.0, -1.0]); eq(1.5, vec![0.0]); } #[test] fn wrapping_ints32() { eq(Wrapping(5i32), vec![Wrapping(0), Wrapping(3), Wrapping(4)]); eq( Wrapping(-5i32), vec![Wrapping(5), Wrapping(0), Wrapping(-3), Wrapping(-4)], ); eq(Wrapping(0i32), vec![]); } #[test] fn vecs() { eq( { let it: Vec = vec![]; it }, vec![], ); eq( { let it: Vec> = vec![vec![]]; it }, vec![vec![]], ); eq(vec![1isize], vec![vec![], vec![0]]); eq(vec![11isize], vec![vec![], vec![0], vec![6], vec![9], vec![10]]); eq( vec![3isize, 5], vec![ vec![], vec![5], vec![3], vec![0, 5], vec![2, 5], vec![3, 0], vec![3, 3], vec![3, 4], ], ); } macro_rules! map_tests { ($name:ident, $ctor:expr) => { #[test] fn $name() { ordered_eq($ctor, vec![]); { let mut map = $ctor; map.insert(1usize, 1isize); let shrinks = vec![ $ctor, { let mut m = $ctor; m.insert(0, 1); m }, { let mut m = $ctor; m.insert(1, 0); m }, ]; ordered_eq(map, shrinks); } } }; } map_tests!(btreemap, BTreeMap::::new()); map_tests!(hashmap, HashMap::::new()); macro_rules! list_tests { ($name:ident, $ctor:expr, $push:ident) => { #[test] fn $name() { ordered_eq($ctor, vec![]); { let mut list = $ctor; list.$push(2usize); let shrinks = vec![ $ctor, { let mut m = $ctor; m.$push(0); m }, { let mut m = $ctor; m.$push(1); m }, ]; ordered_eq(list, shrinks); } } }; } list_tests!(btreesets, BTreeSet::::new(), insert); list_tests!(hashsets, HashSet::::new(), insert); list_tests!(linkedlists, LinkedList::::new(), push_back); list_tests!(vecdeques, VecDeque::::new(), push_back); #[test] fn binaryheaps() { ordered_eq( BinaryHeap::::new().into_iter().collect::>(), vec![], ); { let mut heap = BinaryHeap::::new(); heap.push(2usize); let shrinks = vec![vec![], vec![0], vec![1]]; ordered_eq(heap.into_iter().collect::>(), shrinks); } } #[test] fn chars() { eq('\x00', vec![]); } // All this jazz is for testing set equality on the results of a shrinker. fn eq(s: A, v: Vec) { let (left, right) = (shrunk(s), set(v)); assert_eq!(left, right); } fn shrunk(s: A) -> HashSet { set(s.shrink().collect()) } fn set(xs: Vec) -> HashSet { xs.into_iter().collect() } fn ordered_eq(s: A, v: Vec) { let (left, right) = (s.shrink().collect::>(), v); assert_eq!(left, right); } #[test] fn bounds() { use std::ops::Bound::*; for i in -5..=5 { ordered_eq(Included(i), i.shrink().map(Included).collect()); ordered_eq(Excluded(i), i.shrink().map(Excluded).collect()); } eq(Unbounded::, vec![]); } #[test] fn ranges() { ordered_eq(0..0, vec![]); ordered_eq(1..1, vec![0..1, 1..0]); ordered_eq(3..5, vec![0..5, 2..5, 3..0, 3..3, 3..4]); ordered_eq(5..3, vec![0..3, 3..3, 4..3, 5..0, 5..2]); ordered_eq(3.., vec![0.., 2..]); ordered_eq(..3, vec![..0, ..2]); ordered_eq(.., vec![]); } #[test] fn pathbuf() { ordered_eq( PathBuf::from("/home/foo//.././bar"), vec![ PathBuf::from("/home/foo//.."), PathBuf::from("/home/foo/../bar"), ], ); } } quickcheck-0.9.0/src/lib.rs010064400017500000144000000045221353051526500137620ustar0000000000000000//! This crate is a port of //! [Haskell's QuickCheck](http://hackage.haskell.org/package/QuickCheck). //! //! For detailed examples, please see the //! [README](https://github.com/BurntSushi/quickcheck). #![cfg_attr(feature = "i128", feature(i128_type, i128))] #[cfg(feature = "use_logging")] extern crate env_logger; #[cfg(feature = "use_logging")] #[macro_use] extern crate log; extern crate rand; extern crate rand_core; pub use crate::arbitrary::{ empty_shrinker, single_shrinker, Arbitrary, Gen, StdGen, StdThreadGen, }; pub use crate::tester::{quickcheck, QuickCheck, TestResult, Testable}; pub use rand_core::RngCore; /// A macro for writing quickcheck tests. /// /// This macro takes as input one or more property functions to test, and /// produces a proper `#[test]` function for each property. If the property /// fails, the behavior is as if `quickcheck` were called on the property /// (i.e., it panics and fails the test). /// /// Note that this macro doesn't support `mut` or patterns in parameters. /// /// # Example /// /// ```rust /// # #[macro_use] extern crate quickcheck; fn main() { /// quickcheck! { /// fn prop_reverse_reverse(xs: Vec) -> bool { /// let rev: Vec<_> = xs.clone().into_iter().rev().collect(); /// let revrev: Vec<_> = rev.into_iter().rev().collect(); /// xs == revrev /// } /// }; /// # } /// ``` #[macro_export] macro_rules! quickcheck { (@as_items $($i:item)*) => ($($i)*); { $( $(#[$m:meta])* fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { $($code:tt)* } )* } => ( $crate::quickcheck! { @as_items $( #[test] $(#[$m])* fn $fn_name() { fn prop($($arg_name: $arg_ty),*) -> $ret { $($code)* } $crate::quickcheck(prop as fn($($arg_ty),*) -> $ret); } )* } ) } #[cfg(feature = "use_logging")] fn env_logger_init() -> Result<(), log::SetLoggerError> { env_logger::try_init() } #[cfg(not(feature = "use_logging"))] fn env_logger_init() {} #[cfg(not(feature = "use_logging"))] macro_rules! info { ($($_ignore:tt)*) => { () }; } mod arbitrary; mod tester; #[cfg(test)] mod tests; quickcheck-0.9.0/src/tester.rs010064400017500000144000000343531353051526500145270ustar0000000000000000use std::cmp; use std::env; use std::fmt::Debug; use std::panic; use crate::tester::Status::{Discard, Fail, Pass}; use crate::{Arbitrary, Gen, StdThreadGen}; /// The main QuickCheck type for setting configuration and running QuickCheck. pub struct QuickCheck { tests: u64, max_tests: u64, min_tests_passed: u64, gen: G, } fn qc_tests() -> u64 { let default = 100; match env::var("QUICKCHECK_TESTS") { Ok(val) => val.parse().unwrap_or(default), Err(_) => default, } } fn qc_max_tests() -> u64 { let default = 10_000; match env::var("QUICKCHECK_MAX_TESTS") { Ok(val) => val.parse().unwrap_or(default), Err(_) => default, } } fn qc_gen_size() -> usize { let default = 100; match env::var("QUICKCHECK_GENERATOR_SIZE") { Ok(val) => val.parse().unwrap_or(default), Err(_) => default, } } fn qc_min_tests_passed() -> u64 { let default = 0; match env::var("QUICKCHECK_MIN_TESTS_PASSED") { Ok(val) => val.parse().unwrap_or(default), Err(_) => default, } } impl QuickCheck { /// Creates a new QuickCheck value. /// /// This can be used to run QuickCheck on things that implement /// `Testable`. You may also adjust the configuration, such as /// the number of tests to run. /// /// By default, the maximum number of passed tests is set to `100`, /// the max number of overall tests is set to `10000` and the generator /// is set to a `StdThreadGen` with a default size of `100`. pub fn new() -> QuickCheck { let gen_size = qc_gen_size(); QuickCheck::with_gen(StdThreadGen::new(gen_size)) } } impl QuickCheck { /// Set the number of tests to run. /// /// This actually refers to the maximum number of *passed* tests that /// can occur. Namely, if a test causes a failure, future testing on that /// property stops. Additionally, if tests are discarded, there may be /// fewer than `tests` passed. pub fn tests(mut self, tests: u64) -> QuickCheck { self.tests = tests; self } /// Create a new instance of `QuickCheck` using the given generator. pub fn with_gen(generator: G) -> QuickCheck { let tests = qc_tests(); let max_tests = cmp::max(tests, qc_max_tests()); let min_tests_passed = qc_min_tests_passed(); QuickCheck { tests: tests, max_tests: max_tests, min_tests_passed: min_tests_passed, gen: generator, } } /// Set the maximum number of tests to run. /// /// The number of invocations of a property will never exceed this number. /// This is necessary to cap the number of tests because QuickCheck /// properties can discard tests. pub fn max_tests(mut self, max_tests: u64) -> QuickCheck { self.max_tests = max_tests; self } /// Set the random number generator to be used by QuickCheck. pub fn gen(self, gen: N) -> QuickCheck { // unfortunately this is necessary because using QuickCheck{ ..self, gen } // wouldn't work due to mismatched types. let QuickCheck { tests, max_tests, min_tests_passed, .. } = self; QuickCheck { tests, max_tests, min_tests_passed, gen } } /// Set the minimum number of tests that needs to pass. /// /// This actually refers to the minimum number of *valid* *passed* tests /// that needs to pass for the property to be considered successful. pub fn min_tests_passed(mut self, min_tests_passed: u64) -> QuickCheck { self.min_tests_passed = min_tests_passed; self } /// Tests a property and returns the result. /// /// The result returned is either the number of tests passed or a witness /// of failure. /// /// (If you're using Rust's unit testing infrastructure, then you'll /// want to use the `quickcheck` method, which will `panic!` on failure.) pub fn quicktest(&mut self, f: A) -> Result where A: Testable, { let mut n_tests_passed = 0; for _ in 0..self.max_tests { if n_tests_passed >= self.tests { break; } match f.result(&mut self.gen) { TestResult { status: Pass, .. } => n_tests_passed += 1, TestResult { status: Discard, .. } => continue, r @ TestResult { status: Fail, .. } => return Err(r), } } Ok(n_tests_passed) } /// Tests a property and calls `panic!` on failure. /// /// The `panic!` message will include a (hopefully) minimal witness of /// failure. /// /// It is appropriate to use this method with Rust's unit testing /// infrastructure. /// /// Note that if the environment variable `RUST_LOG` is set to enable /// `info` level log messages for the `quickcheck` crate, then this will /// include output on how many QuickCheck tests were passed. /// /// # Example /// /// ```rust /// use quickcheck::QuickCheck; /// /// fn prop_reverse_reverse() { /// fn revrev(xs: Vec) -> bool { /// let rev: Vec<_> = xs.clone().into_iter().rev().collect(); /// let revrev: Vec<_> = rev.into_iter().rev().collect(); /// xs == revrev /// } /// QuickCheck::new().quickcheck(revrev as fn(Vec) -> bool); /// } /// ``` pub fn quickcheck(&mut self, f: A) where A: Testable, { // Ignore log init failures, implying it has already been done. let _ = crate::env_logger_init(); let n_tests_passed = match self.quicktest(f) { Ok(n_tests_passed) => n_tests_passed, Err(result) => panic!(result.failed_msg()), }; if n_tests_passed >= self.min_tests_passed { info!("(Passed {} QuickCheck tests.)", n_tests_passed) } else { panic!( "(Unable to generate enough tests, {} not discarded.)", n_tests_passed ) } } } /// Convenience function for running QuickCheck. /// /// This is an alias for `QuickCheck::new().quickcheck(f)`. pub fn quickcheck(f: A) { QuickCheck::new().quickcheck(f) } /// Describes the status of a single instance of a test. /// /// All testable things must be capable of producing a `TestResult`. #[derive(Clone, Debug)] pub struct TestResult { status: Status, arguments: Vec, err: Option, } /// Whether a test has passed, failed or been discarded. #[derive(Clone, Debug)] enum Status { Pass, Fail, Discard, } impl TestResult { /// Produces a test result that indicates the current test has passed. pub fn passed() -> TestResult { TestResult::from_bool(true) } /// Produces a test result that indicates the current test has failed. pub fn failed() -> TestResult { TestResult::from_bool(false) } /// Produces a test result that indicates failure from a runtime error. pub fn error>(msg: S) -> TestResult { let mut r = TestResult::from_bool(false); r.err = Some(msg.into()); r } /// Produces a test result that instructs `quickcheck` to ignore it. /// This is useful for restricting the domain of your properties. /// When a test is discarded, `quickcheck` will replace it with a /// fresh one (up to a certain limit). pub fn discard() -> TestResult { TestResult { status: Discard, arguments: vec![], err: None } } /// Converts a `bool` to a `TestResult`. A `true` value indicates that /// the test has passed and a `false` value indicates that the test /// has failed. pub fn from_bool(b: bool) -> TestResult { TestResult { status: if b { Pass } else { Fail }, arguments: vec![], err: None, } } /// Tests if a "procedure" fails when executed. The test passes only if /// `f` generates a task failure during its execution. pub fn must_fail(f: F) -> TestResult where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static, { let f = panic::AssertUnwindSafe(f); TestResult::from_bool(panic::catch_unwind(f).is_err()) } /// Returns `true` if and only if this test result describes a failing /// test. pub fn is_failure(&self) -> bool { match self.status { Fail => true, Pass | Discard => false, } } /// Returns `true` if and only if this test result describes a failing /// test as a result of a run time error. pub fn is_error(&self) -> bool { self.is_failure() && self.err.is_some() } fn failed_msg(&self) -> String { match self.err { None => format!( "[quickcheck] TEST FAILED. Arguments: ({})", self.arguments.join(", ") ), Some(ref err) => format!( "[quickcheck] TEST FAILED (runtime error). \ Arguments: ({})\nError: {}", self.arguments.join(", "), err ), } } } /// `Testable` describes types (e.g., a function) whose values can be /// tested. /// /// Anything that can be tested must be capable of producing a `TestResult` /// given a random number generator. This is trivial for types like `bool`, /// which are just converted to either a passing or failing test result. /// /// For functions, an implementation must generate random arguments /// and potentially shrink those arguments if they produce a failure. /// /// It's unlikely that you'll have to implement this trait yourself. pub trait Testable: Send + 'static { fn result(&self, _: &mut G) -> TestResult; } impl Testable for bool { fn result(&self, _: &mut G) -> TestResult { TestResult::from_bool(*self) } } impl Testable for () { fn result(&self, _: &mut G) -> TestResult { TestResult::passed() } } impl Testable for TestResult { fn result(&self, _: &mut G) -> TestResult { self.clone() } } impl Testable for Result where A: Testable, E: Debug + Send + 'static, { fn result(&self, g: &mut G) -> TestResult { match *self { Ok(ref r) => r.result(g), Err(ref err) => TestResult::error(format!("{:?}", err)), } } } /// Return a vector of the debug formatting of each item in `args` fn debug_reprs(args: &[&dyn Debug]) -> Vec { args.iter().map(|x| format!("{:?}", x)).collect() } macro_rules! testable_fn { ($($name: ident),*) => { impl Testable for fn($($name),*) -> T { #[allow(non_snake_case)] fn result(&self, g: &mut G_) -> TestResult { fn shrink_failure( g: &mut G_, self_: fn($($name),*) -> T, a: ($($name,)*), ) -> Option { for t in a.shrink() { let ($($name,)*) = t.clone(); let mut r_new = safe(move || {self_($($name),*)}).result(g); if r_new.is_failure() { { let ($(ref $name,)*) : ($($name,)*) = t; r_new.arguments = debug_reprs(&[$($name),*]); } // The shrunk value *does* witness a failure, so keep // trying to shrink it. let shrunk = shrink_failure(g, self_, t); // If we couldn't witness a failure on any shrunk value, // then return the failure we already have. return Some(shrunk.unwrap_or(r_new)) } } None } let self_ = *self; let a: ($($name,)*) = Arbitrary::arbitrary(g); let ( $($name,)* ) = a.clone(); let mut r = safe(move || {self_($($name),*)}).result(g); { let ( $(ref $name,)* ) = a; r.arguments = debug_reprs(&[$($name),*]); } match r.status { Pass|Discard => r, Fail => { shrink_failure(g, self_, a).unwrap_or(r) } } } }}} testable_fn!(); testable_fn!(A); testable_fn!(A, B); testable_fn!(A, B, C); testable_fn!(A, B, C, D); testable_fn!(A, B, C, D, E); testable_fn!(A, B, C, D, E, F); testable_fn!(A, B, C, D, E, F, G); testable_fn!(A, B, C, D, E, F, G, H); fn safe(fun: F) -> Result where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static, { panic::catch_unwind(panic::AssertUnwindSafe(fun)).map_err(|any_err| { // Extract common types of panic payload: // panic and assert produce &str or String if let Some(&s) = any_err.downcast_ref::<&str>() { s.to_owned() } else if let Some(s) = any_err.downcast_ref::() { s.to_owned() } else { "UNABLE TO SHOW RESULT OF PANIC.".to_owned() } }) } /// Convenient aliases. trait AShow: Arbitrary + Debug {} impl AShow for A {} #[cfg(test)] mod test { use crate::{QuickCheck, StdGen}; use rand::{self, rngs::OsRng}; #[test] fn shrinking_regression_issue_126() { fn thetest(vals: Vec) -> bool { vals.iter().filter(|&v| *v).count() < 2 } let failing_case = QuickCheck::new() .quicktest(thetest as fn(vals: Vec) -> bool) .unwrap_err(); let expected_argument = format!("{:?}", [true, true]); assert_eq!(failing_case.arguments, vec![expected_argument]); } #[test] fn size_for_small_types_issue_143() { fn t(_: i8) -> bool { true } QuickCheck::new() .gen(StdGen::new(rand::thread_rng(), 129)) .quickcheck(t as fn(i8) -> bool); } #[test] fn different_generator() { fn prop(_: i32) -> bool { true } QuickCheck::with_gen(StdGen::new(OsRng, 129)) .quickcheck(prop as fn(i32) -> bool); QuickCheck::new() .gen(StdGen::new(OsRng, 129)) .quickcheck(prop as fn(i32) -> bool); } } quickcheck-0.9.0/src/tests.rs010066400017500000144000000145061353051434200143560ustar0000000000000000use std::cmp::Ord; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; use std::hash::BuildHasherDefault; use std::path::PathBuf; use rand; use super::{quickcheck, QuickCheck, StdGen, TestResult}; #[test] fn prop_oob() { fn prop() -> bool { let zero: Vec = vec![]; zero[0] } match QuickCheck::new().quicktest(prop as fn() -> bool) { Ok(n) => panic!( "prop_oob should fail with a runtime error \ but instead it passed {} tests.", n ), _ => return, } } #[test] fn prop_reverse_reverse() { fn prop(xs: Vec) -> bool { let rev: Vec<_> = xs.clone().into_iter().rev().collect(); let revrev: Vec<_> = rev.into_iter().rev().collect(); xs == revrev } quickcheck(prop as fn(Vec) -> bool); } quickcheck! { fn prop_reverse_reverse_macro(xs: Vec) -> bool { let rev: Vec<_> = xs.clone().into_iter().rev().collect(); let revrev: Vec<_> = rev.into_iter().rev().collect(); xs == revrev } #[should_panic] fn prop_macro_panic(_x: u32) -> bool { assert!(false); false } } #[test] fn reverse_single() { fn prop(xs: Vec) -> TestResult { if xs.len() != 1 { TestResult::discard() } else { TestResult::from_bool( xs == xs.clone().into_iter().rev().collect::>(), ) } } quickcheck(prop as fn(Vec) -> TestResult); } #[test] fn reverse_app() { fn prop(xs: Vec, ys: Vec) -> bool { let mut app = xs.clone(); app.extend(ys.iter().cloned()); let app_rev: Vec = app.into_iter().rev().collect(); let rxs: Vec = xs.into_iter().rev().collect(); let mut rev_app = ys.into_iter().rev().collect::>(); rev_app.extend(rxs.into_iter()); app_rev == rev_app } quickcheck(prop as fn(Vec, Vec) -> bool); } #[test] fn max() { fn prop(x: isize, y: isize) -> TestResult { if x > y { TestResult::discard() } else { TestResult::from_bool(::std::cmp::max(x, y) == y) } } quickcheck(prop as fn(isize, isize) -> TestResult); } #[test] fn sort() { fn prop(mut xs: Vec) -> bool { xs.sort_by(|x, y| x.cmp(y)); for i in xs.windows(2) { if i[0] > i[1] { return false; } } true } quickcheck(prop as fn(Vec) -> bool); } fn sieve(n: usize) -> Vec { if n <= 1 { return vec![]; } let mut marked = vec![false; n + 1]; marked[0] = true; marked[1] = true; marked[2] = true; for p in 2..n { for i in (2 * p..n).filter(|&n| n % p == 0) { marked[i] = true; } } marked .iter() .enumerate() .filter_map(|(i, &m)| if m { None } else { Some(i) }) .collect() } fn is_prime(n: usize) -> bool { n != 0 && n != 1 && (2..).take_while(|i| i * i <= n).all(|i| n % i != 0) } #[test] #[should_panic] fn sieve_not_prime() { fn prop_all_prime(n: usize) -> bool { sieve(n).into_iter().all(is_prime) } quickcheck(prop_all_prime as fn(usize) -> bool); } #[test] #[should_panic] fn sieve_not_all_primes() { fn prop_prime_iff_in_the_sieve(n: usize) -> bool { sieve(n) == (0..(n + 1)).filter(|&i| is_prime(i)).collect::>() } quickcheck(prop_prime_iff_in_the_sieve as fn(usize) -> bool); } #[test] fn testable_result() { fn result() -> Result { Ok(true) } quickcheck(result as fn() -> Result); } #[test] #[should_panic] fn testable_result_err() { quickcheck(Err:: as fn(i32) -> Result); } #[test] fn testable_unit() { fn do_nothing() {} quickcheck(do_nothing as fn()); } #[test] fn testable_unit_panic() { fn panic() { panic!() } assert!(QuickCheck::new().quicktest(panic as fn()).is_err()); } #[test] fn regression_issue_83() { fn prop(_: u8) -> bool { true } QuickCheck::new() .gen(StdGen::new(rand::thread_rng(), 1024)) .quickcheck(prop as fn(u8) -> bool) } #[test] fn regression_issue_83_signed() { fn prop(_: i8) -> bool { true } QuickCheck::new() .gen(StdGen::new(rand::thread_rng(), 1024)) .quickcheck(prop as fn(i8) -> bool) } // Test that we can show the message after panic #[test] #[should_panic(expected = "foo")] fn panic_msg_1() { fn prop() -> bool { panic!("foo"); } quickcheck(prop as fn() -> bool); } #[test] #[should_panic(expected = "foo")] fn panic_msg_2() { fn prop() -> bool { assert!("foo" == "bar"); true } quickcheck(prop as fn() -> bool); } #[test] #[should_panic(expected = "foo")] fn panic_msg_3() { fn prop() -> bool { assert_eq!("foo", "bar"); true } quickcheck(prop as fn() -> bool); } #[test] #[should_panic] fn regression_issue_107_hang() { fn prop(a: Vec) -> bool { a.contains(&1) } quickcheck(prop as fn(_) -> bool); } #[test] #[should_panic( expected = "(Unable to generate enough tests, 0 not discarded.)" )] fn all_tests_discarded_min_tests_passed_set() { fn prop_discarded(_: u8) -> TestResult { TestResult::discard() } QuickCheck::new() .tests(16) .min_tests_passed(8) .quickcheck(prop_discarded as fn(u8) -> TestResult) } #[test] fn all_tests_discarded_min_tests_passed_missing() { fn prop_discarded(_: u8) -> TestResult { TestResult::discard() } QuickCheck::new().quickcheck(prop_discarded as fn(u8) -> TestResult) } quickcheck! { /// The following is a very simplistic test, which only verifies /// that our PathBuf::arbitrary does not panic. Still, that's /// something! :) fn pathbuf(_p: PathBuf) -> bool { true } fn basic_hashset(_set: HashSet) -> bool { true } fn basic_hashmap(_map: HashMap) -> bool { true } fn substitute_hashset( _set: HashSet> ) -> bool { true } fn substitute_hashmap( _map: HashMap> ) -> bool { true } } quickcheck-0.9.0/.cargo_vcs_info.json0000644000000001120000000000000132050ustar00{ "git": { "sha1": "7845a988894e3e02233bf2115b3d5ce91a914ad9" } } quickcheck-0.9.0/Cargo.lock0000644000000160150000000000000111710ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getrandom" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ppv-lite86" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quickcheck" version = "0.9.0" dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasi" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" "checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7"