Giter Site home page Giter Site logo

quickcheck's Introduction

quickcheck

QuickCheck 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.)

Build status

Dual-licensed under MIT or the UNLICENSE.

Documentation

The API is fully documented: https://docs.rs/quickcheck.

Simple example

Here's an example that tests a function that reverses a vector:

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
    let mut rev = vec!();
    for x in xs.iter() {
        rev.insert(0, x.clone())
    }
    rev
}

#[cfg(test)]
mod tests {
  quickcheck! {
      fn prop(xs: Vec<u32>) -> bool {
          xs == reverse(&reverse(&xs))
      }
  }
}

This example uses the quickcheck! macro, which is backwards compatible with old versions of Rust.

The #[quickcheck] attribute

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:

#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[macro_use(quickcheck)]
extern crate quickcheck_macros;

#[cfg(test)]
mod tests {
    fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
        let mut rev = vec!();
        for x in xs {
            rev.insert(0, x.clone())
        }
        rev
    }

    #[quickcheck]
    fn double_reversal_is_identity(xs: Vec<isize>) -> bool {
        xs == reverse(&reverse(&xs))
    }
}

Installation

quickcheck is on crates.io, so you can include it in your project like so:

[dependencies]
quickcheck = "1"

If you're only using quickcheck in your test code, then you can add it as a development dependency instead:

[dev-dependencies]
quickcheck = "1"

If you want to use the #[quickcheck] attribute, then add quickcheck_macros

[dev-dependencies]
quickcheck = "1"
quickcheck_macros = "1"

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:

  • "use_logging": (Enabled by default.) Enables the log messages governed RUST_LOG.
  • "regex": (Enabled by default.) Enables the use of regexes with env_logger.

Minimum Rust version policy

This crate's minimum supported rustc version is 1.65.0.

The current policy is that the minimum Rust version required to use this crate can be increased in minor version updates. For example, if crate 1.0 requires Rust 1.20.0, then crate 1.0.z for all values of z will also require Rust 1.20.0 or newer. However, crate 1.y for y > 0 may require a newer minimum version of Rust.

In general, this crate will be conservative with respect to the minimum supported version of Rust.

With all of that said, currently, rand is a public dependency of quickcheck. Therefore, the MSRV policy above only applies when it is more aggressive than rand's MSRV policy. Otherwise, quickcheck will defer to rand's MSRV policy.

Compatibility

In general, this crate considers the Arbitrary implementations provided as implementation details. Strategies may or may not change over time, which may cause new test failures, presumably due to the discovery of new bugs due to a new kind of witness being generated. These sorts of changes may happen in semver compatible releases.

Alternative Rust crates for property testing

The proptest crate is inspired by the Hypothesis framework for Python. You can read a comparison between proptest and quickcheck here and here. 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!

Alternatives for fuzzing

Please see the Rust Fuzz Book and the arbitrary crate.

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:

pub fn quickcheck<A: Testable>(f: A) {
    // elided
}

So quickcheck can test any value with a type that satisfies the Testable trait. Great, so what is this Testable business?

pub trait Testable {
    fn result(&self, &mut Gen) -> 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:

impl Testable for bool {
    fn result(&self, _: &mut Gen) -> TestResult {
        TestResult::from_bool(*self)
    }
}

But in the example, we gave a function to quickcheck. Yes, functions can satisfy Testable too!

impl<A: Arbitrary + Debug, B: Testable> Testable for fn(A) -> B {
    fn result(&self, g: &mut Gen) -> 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:

impl Testable for TestResult {
    fn result(&self, _: &mut Gen) -> 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.

fn prop(xs: Vec<isize>) -> TestResult {
    if xs.len() != 1 {
        return TestResult::discard()
    }
    TestResult::from_bool(xs == reverse(&xs))
}
quickcheck(prop as fn(Vec<isize>) -> TestResult);

(A full working program for this example is in 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. 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 and QuickCheck::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)

fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
    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)):

fn prop(xs: Vec<isize>) -> bool {
    xs == reverse(&reverse(&xs))
}
quickcheck(prop as fn(Vec<isize>) -> 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, 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.

#!/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() 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.

Generating Structs

It is very simple to generate structs in QuickCheck. Consider the following example, where the struct Point is defined:

struct Point {
    x: i32,
    y: i32,
}

In order to generate a random Point instance, you need to implement the trait Arbitrary for the struct Point:

use quickcheck::{Arbitrary, Gen};

impl Arbitrary for Point {
    fn arbitrary(g: &mut Gen) -> Point {
        Point {
            x: i32::arbitrary(g),
            y: i32::arbitrary(g),
        }
    }
}

Case study: The Sieve of Eratosthenes

The 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:

fn sieve(n: usize) -> Vec<usize> {
    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:

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:

fn prop_all_prime(n: usize) -> bool {
    sieve(n).into_iter().all(is_prime)
}

And finally, we need to invoke quickcheck with our property:

fn main() {
    quickcheck(prop_all_prime as fn(usize) -> bool);
}

A fully working source file with this code is in 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:

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:

fn prop_prime_iff_in_the_sieve(n: usize) -> bool {
    sieve(n) == (0..(n + 1)).filter(|&i| is_prime(i)).collect::<Vec<_>>()
}

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:

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:

  • 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. It's unlikely that it ever will.
  • Arbitrary is not implemented for closures. See issue #56 for more details on why.

quickcheck's People

Contributors

andersk avatar apasel422 avatar atouchet avatar badboy avatar blt avatar bluss avatar burntsushi avatar danburkert avatar emallson avatar erickt avatar flying-sheep avatar habnabit avatar hcpl avatar huonw avatar jturner314 avatar lopopolo avatar maxbla avatar milibopp avatar nathantypanski avatar notriddle avatar oherrala avatar pseitz avatar remexre avatar rozbb avatar seanrburton avatar sgrif avatar sobolevn avatar tari avatar tokenrove avatar vi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quickcheck's Issues

Provide some way to fail the unit test if all the quickcheck tests were discarded

Sometimes I write too many "discard conditions" (along with too many arguments), or sometimes I get those conditions wrong, and quickcheck ends up discarding all the 10k tests, and flagging the unit test as passed. IMO, either case is a bug, because I'm not actually testing anything, and I should fix the discard conditions.

Right now, the only way to detect this issue is to use RUST_LOG=quickcheck and look out for "Passed 0 Quickcheck tests" messages.

I would like to see some way to fail the unit test if too few quickcheck tests passed. Preferably, using a environment variable, say QC_PASSED_TESTS_THRESHOLD=25 cargo test will fail the unit test if less than 25 quickcheck tests passed, if the variable is unset, the threshold will be zero, which is the current behavior.

Thoughts @BurntSushi ?

'Rng.gen_range called with low >= high'

This can happen due to invalid casts from quickcheck::Gen::size of type usize to various other integer types with a value range smaller than usize (cf. quickcheck::arbitrary::unsigned_arbitrary).

Test case:

#[test]
fn test() {
    fn prop(_: u8) -> bool { true }

    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 1024))
        .quickcheck(prop as fn(u8) -> bool)
}

Write own Arbitrary impls

I wanted to write my own Arbitrary impls but apparently I cannot access the quickcheck::arbitrary module?

Feature request: Add auto-derivators for structs and enums

I want quickcheck to have a compiler plugin that automatically generates Arbitrary impl for structs and enums composed of Arbitrary types, like with serialisation.

That should shrink

extern crate quickcheck;

use quickcheck::Arbitrary;

#[derive(Clone,Debug)]
struct Mumu {
    a : u32,
    b : String,
}

#[derive(Clone,Debug)]
enum Qqq {
    Lol,
    Ror,
    Kokoko(Mumu),
    Totot(u32),
}

impl Arbitrary for Mumu {
    fn arbitrary<G : quickcheck::Gen>(g:&mut G) -> Mumu {
        Mumu {a : Arbitrary::arbitrary(g), b : Arbitrary::arbitrary(g) }
    }
    fn shrink(&self) -> Box<Iterator<Item=Self>> {
        Box::new ( (self.a.clone(), self.b.clone()).shrink().map(|(aa,bb)| Mumu { a: aa, b:bb}))
    }
}

impl Arbitrary for Qqq {
    fn arbitrary<G : quickcheck::Gen>(g:&mut G) -> Qqq {
        let y = g.next_u32() % 4;
        match y {
            0 => Qqq::Lol,
            1 => Qqq::Ror,
            2 => Qqq::Kokoko(Arbitrary::arbitrary(g)),
            3 => Qqq::Totot(Arbitrary::arbitrary(g)),
            _ => panic!(),
        }
    }
    fn shrink(&self) -> Box<Iterator<Item=Self>> {
        match self {
            &Qqq::Totot(ref x) => Box::new(x.shrink().map(|s| Qqq::Totot(s))),
            &Qqq::Kokoko(ref x) => Box::new(x.shrink().map(|s| Qqq::Kokoko(s))),
            _ => quickcheck::empty_shrinker(),
        }
    }
}



#[test]
fn it_works() {
    fn qqq(x : Qqq) -> bool {
        if let Qqq::Kokoko(Mumu { a : v, b: _ }) = x {
            return v != 4
        }
        true
    }

    quickcheck::QuickCheck::new().tests(1000_000_000).quickcheck(qqq as fn(Qqq) -> bool);
}

to

extern crate quickcheck;

use quickcheck::Arbitrary;

#[derive(Clone,Debug,Arbitrary)]
struct Mumu {
    a : u32,
    b : String,
}

#[derive(Clone,Debug,Arbitrary)]
enum Qqq {
    Lol,
    Ror,
    Kokoko(Mumu),
    Totot(u32),
}

#[test]
fn it_works() {
    fn qqq(x : Qqq) -> bool {
        if let Qqq::Kokoko(Mumu { a : v, b: _ }) = x {
            return v != 4
        }
        true
    }

    quickcheck::QuickCheck::new().tests(1000_000_000).quickcheck(qqq as fn(Qqq) -> bool);
}

Add a way to export failing test cases

It would be very convenient to add a way to export failing test cases to allow to reproduce them and make a regression test suite.

The failing test should be exported either as:

  • a test function (with the #[test] attribute) you can just copy-paste inside your code or
  • a file containing the test cases with a way to rerun these test case automatically

This feature is more or less presented in the following video:
https://www.youtube.com/watch?v=x7O2Hkq983Y
And is used on:
http://www.quickcheck-ci.com/

Seed and print the value of seed used on failure

I have tests that fail very rarely. When this happens on Travis, I'd really like to reproduce the issue locally.

If quickcheck randomly chose a seed, but printed that seed value on failure, then I could replicate test failures.

source trait is private (Rng)

Please consider this test case:

extern crate quickcheck;

use quickcheck::{Arbitrary, Gen};

#[derive(Clone)]
pub struct Foo(u8);

impl Arbitrary for Foo {
    fn arbitrary<G: Gen>(g: &mut G) -> Foo {
        Foo(g.gen())
    }
}

Compilation with rustc 1.3.0-nightly (0c052199b 2015-07-11) gives:

src/lib.rs:10:13: 10:20 error: source trait is private
src/lib.rs:10         Foo(g.gen())
                          ^~~~~~~

I think it is necessary to export not only Gen but also it's parent trait Rng:

diff --git a/src/lib.rs b/src/lib.rs
index f13fcdc..ab1698b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,7 @@
 #[macro_use] extern crate log;
 extern crate rand;

+pub use rand::Rng;
 pub use arbitrary::{
     Arbitrary, Gen, StdGen,
     empty_shrinker, single_shrinker,

Does not compile with latest nightly (2015-02-19)

There's more than a few compile errors resulting from using the latest nightly:

$ rustc --version
rustc 1.0.0-nightly (dfc5c0f1e 2015-02-18) (built 2015-02-19)
$ cargo build
   Compiling quickcheck v0.1.39 (file:///home/caspar/src/rust-quickcheck)
src/arbitrary.rs:150:29: 150:44 error: the parameter type `A` may not live long enough [E0310]
src/arbitrary.rs:150                 let chain = single_shrinker(None).chain(x.shrink().map(Some));
                                                 ^~~~~~~~~~~~~~~
src/arbitrary.rs:150:29: 150:44 help: consider adding an explicit lifetime bound `A: 'static`...
src/arbitrary.rs:150                 let chain = single_shrinker(None).chain(x.shrink().map(Some));
                                                 ^~~~~~~~~~~~~~~
src/arbitrary.rs:150:29: 150:44 note: ...so that the type `core::option::Option<A>` will meet its required lifetime bounds
src/arbitrary.rs:150                 let chain = single_shrinker(None).chain(x.shrink().map(Some));

* etc etc for another 85 lifetime-related error messages *

src/tester.rs:189:30: 189:36 error: type `core::result::Result<std::thread::JoinGuard<'_, T>, std::io::error::Error>` does not implement any method in scope named `join`
src/tester.rs:189                             .join()
                                               ^~~~~~
src/tester.rs:446:29: 446:35 error: type `core::result::Result<std::thread::JoinGuard<'_, T>, std::io::error::Error>` does not implement any method in scope named `join`
src/tester.rs:446         match t.scoped(fun).join() {
                                              ^~~~~~
error: aborting due to 88 previous errors
Could not compile `quickcheck`.

I had a shot at fixing it without any success (still getting my head around lifetimes and associated syntax) so I figured the next best thing is reporting it.

Related: maybe it'd be worth fixing up http://www.rust-ci.org/BurntSushi/quickcheck ? Seems like it hasn't kicked off a new build in almost a year; it's not particularly clear on that page but on the main rust-ci.org page it claims it was unable to build and needs the owner to authenticate, or something along those lines.

RUST_LOG has no effect

README.md:

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.

RUST_LOG no longer controls the output of the log crate itself. The old behavior can be replicated with env_logger, or the logging behavior can be changed (and the documentation be updated).

`cargo test` fails

make test succeeds, but cargo test fails to compile with quickcheck macro dependency issues. I spent a few minute poking around, but couldn't figure out how to fix the issues.

$ cargo test
       Fresh quickcheck_macros v0.1.0 (file:///Users/dan/src/rust/quickcheck)
   Compiling quickcheck v0.1.0 (file:///Users/dan/src/rust/quickcheck)
src/lib.rs:23:1: 23:25 error: can't find crate for `quickcheck`
src/lib.rs:23 extern crate quickcheck;
              ^~~~~~~~~~~~~~~~~~~~~~~~

Using the function traits would improve usability.

At the moment when passing a function to quickcheck, its type has to specified:

fn prop() -> bool {
    true
}

quickcheck(prop as fn() -> bool);

However, bare functions can be passed as generic items implementing Fn traits without any casting:

fn run<F, T>(f: F) -> T where F: Fn() -> T {
    f()
}

fn prop() -> bool {
    true
}

fn main() {
    let t = run(prop);
    println!("{}", t);
}

If we implemented the Testable trait for F where F: Fn(A, ...) -> T instead of the concrete fn(A, ...) - T types, it would be possible to just do:

quickcheck(function);

I think this is a usability win, especially with #[quickcheck] unusable under 1.0 (people are likely to be writing quickcheck quite a bit).

I had a quick go at implementing this, but ran into trouble with the Fun trait. I couldn't work out a way to call the function (passed as &self) in a move closure passed to safe. It may be possible, or else more extensive restructuring may be required.

Document that String is ASCII alphanumerics-only, maybe have a way of generating more Unicode?

Right now, Strings only have ASCII alphanumeric characters. I tried to use it to generate strings with spaces in it and was surprised when my code was never called 😺

It would be cool if there were more of the Unicode set included. Even awesomer might be if we had some tuning knobs where we could say "more punctuation, less letters", perhaps using the Unicode character classes?

Thanks for the fun-to-use library!

Error with quickcheck_macros

Running cargo test in the quickcheck_macros directory with the latest rust nightly 4874ca36f.

   Compiling quickcheck_macros v0.1.30 (file:///Users/sam/Dropbox/Projects/quickcheck/quickcheck_macros)
tests/macro.rs:9:1: 9:14 error: functions used as tests must have signature fn() -> ()
tests/macro.rs:9 #[quickcheck]
                 ^~~~~~~~~~~~~
tests/macro.rs:18:1: 18:14 error: functions used as tests must have signature fn() -> ()
tests/macro.rs:18 #[quickcheck]
                  ^~~~~~~~~~~~~
tests/macro.rs:22:1: 22:14 error: functions used as tests must have signature fn() -> ()
tests/macro.rs:22 #[quickcheck]
                  ^~~~~~~~~~~~~
tests/macro.rs:25:1: 25:14 error: functions used as tests must have signature fn() -> ()
tests/macro.rs:25 #[quickcheck]
                  ^~~~~~~~~~~~~
error: aborting due to 4 previous errors
Could not compile `quickcheck_macros`.

To learn more, run the command again with --verbose.

Would it be a good idea to update the .travis.yml file to also test the macros?

implement Testable for Fn*

Using rustc 1.0.0-nightly (3d0d9bb6f 2015-01-12 22:56:20 +0000):

fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
    let mut rev = vec!();
    for x in xs.iter() {
        rev.insert(0, x.clone())
    }
    rev
}

#[test]
fn reverse_identity() {
  fn prop(xs: Vec<i32>) -> bool {
    xs == reverse(reverse(xs.as_slice()).as_slice())
  }
  quickcheck(prop);
}

produces

error: the trait `quickcheck::tester::Testable` is not implemented for the type `fn(collections::vec::Vec<i32>) -> bool {tests::reverse_identity::prop}`

quickcheck(false) compiles; this appears to be specific to the fn impls, including the zero-arg fn.

Is there any way to run a single test

I'm having errors for one test. I'm changing code and running cargo test, but it's including the 300 other tests. Is there any way to flag the test to be the only one run? Something like #[only(quickcheck)]?

How to test a function `fn(&str, &str) -> bool`?

This is a question issue, and I hope that's an acceptable use in this project.

I try to use quickcheck to write tests for function accepting two strings. I haven't been able to adapt the example test to my use case. This is what I have. Is quickcheck able to provide random parameters for strings (or &strs)?

extern crate quickcheck;
// at least difference of the sizes of a and b
#[test]
fn prop_test_() {
    use quickcheck::quickcheck;

    fn at_least_size_difference(a: &str, b: &str) -> bool {
        let size_a = a.chars().count() as i32;
        let size_b = b.chars().count() as i32;
        let diff = (size_a - size_b).abs();

        edit_distance::edit_distance(a, b) > diff;
    }

    quickcheck(at_least_size_difference as fn(a: &str, b: &str) -> bool);
}

Edge cases

Is it possible to also define edge cases beside the random data without implementing my own Arbitrary type?

Of course for such cases I could just use normal testing…

Build failure with recent rust nightly (rustc 79a5448f4)

When I try to compile quickcheck_macros as a Cargo dependency for something else, I get:

Build failed, waiting for other jobs to finish...
Could not compile `quickcheck_macros`.

--- stderr
src\lib.rs:29:48: 29:70 error: mismatched types: expected `Box<syntax::ext::base
::ItemModifier+'static>`, found `fn(&mut syntax::ext::base::ExtCtxt<'_>, syntax:
:codemap::Span, Gc<syntax::codemap::Spanned<syntax::ast::MetaItem_>>, Gc<syntax:
:ast::Item>) -> Gc<syntax::ast::Item>` (expected box, found extern fn)
src\lib.rs:29                                   ItemModifier(expand_meta_quickch
eck));

rustc version is rustc 0.12.0-pre-nightly (79a5448f4 2014-09-13 20:36:02 +0000), quickcheck_macros version is v0.1.0 (https://github.com/BurntSushi/quickcheck#c5a719a3). Windows 64-bit (hence the unwieldy line breaks, blame the Win32 console!).

Thanks!

make vector shrinking lazy

Currently, a vector is shrunk by producing all possible shrunk values immediately. It would be much better if they were generated lazily with an iterator.

Perhaps std::iter::Unfold will be useful for this.

Recursive shrink implementation requiring Clone on sub-iterators.

Ok, so my problem is wanting to implement shrink() for a type made up of other Arbitrary types:

struct Foo {
    bar: Bar,
    baz: Baz,
}

impl Arbitrary for Foo {
    fn arbitrary<G: Gen>(gen: &mut Gen) -> Foo {
        Foo {
            bar: Bar::arbitrary(),
            baz: Baz::arbitrary(),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item=Foo>> {
        let bars = self.bar.shrink().chain(Some(self.bar));
        let bazs = self.baz.shrink().chain(Some(self.baz));
        Box::new(bars.cartesian_product(bazs).map(|(bar, baz)| Foo { bar: bar, baz: baz }))
    }
}

I think this shrink() impl is very elegant, but it doesn't work because cartesian_product (from itertools) requires Clone on the second iterator (of course). This is a well known problem with trait objects; making shrink() return Box<Iterator + Clone> isn't a very satisfying solution, since there's a question of "where do I stop? what about Sync + Send etc?. Furthermore, closures are neverClone` :(. Making the iterator type of shrink an associated type

pub trait Arbitrary {
  type Shrink: Iterator<Item=Self>;
  fn shrink(&self) -> Self::Shrink;
  /* ... */
}

means a default impl can't be provided (at least not without specialisation), but it would solve the issue. I know I can implement a shrink iterator by storing bar and baz itself, and creating new iterators all the time, but that is a lot of boilerplate. Is there some general solution to this problem of composing Arbitrary types?

Implement Wrapping<integer type> for Arbitrary

It would be nice to be able to use quickcheck with (e.g.) Wrapping<u8>. I'm not sure I can fix this in my own code, adding

impl Arbitrary for Wrapping<u8> {
    fn arbitrary<G: Gen>(g: &mut G) -> Wrapping<u8> {
        Wrapping(Arbitrary::arbitrary(g))
    }
}

generates a compile error because neither Arbitrary nor Wrapping were defined by me.

Failing build with most recent Rust

Looks like the most recent Rust broke things. Building my repo https://github.com/FranklinChen/type-directed-tdd-rust which uses quickcheck resulted in

src/arbitrary.rs:60:29: 60:40 error: explicit lifetime bound required
src/arbitrary.rs:60 impl<A> Iterator<A> for Box<Shrinker<A>> {
                                                ^~~~~~~~~~~
src/arbitrary.rs:75:35: 75:46 error: explicit lifetime bound required
src/arbitrary.rs:75 pub fn empty_shrinker<A>() -> Box<Shrinker<A>> {
                                                      ^~~~~~~~~~~
src/arbitrary.rs:89:44: 89:55 error: explicit lifetime bound required
src/arbitrary.rs:89 pub fn single_shrinker<A>(value: A) -> Box<Shrinker<A>> {
                                                               ^~~~~~~~~~~
src/arbitrary.rs:372:25: 372:36 error: explicit lifetime bound required
src/arbitrary.rs:372     fn new(x: A) -> Box<Shrinker<A>> {
                                             ^~~~~~~~~~~
src/arbitrary.rs:407:25: 407:36 error: explicit lifetime bound required
src/arbitrary.rs:407     fn new(x: A) -> Box<Shrinker<A>> {
                                             ^~~~~~~~~~~

add more examples

It would be great to have an example for implementing shrink with a custom type.

get rid of `Shrinker` proxy trait

In a bygone era, I invented the Shrinker trait as a proxy so the shrink method of Arbitrary could return any iterator without regard to its underlying type. This was because Box<Iterator<A>> didn't itself implement Iterator<A>.

Now that DST is here and Rust has a more coherent story regarding trait object safety, it would be nice to remove this proxy trait and return Box<Iterator> instead.

I started working on this, but I ran into some bugs: rust-lang/rust#20605 and rust-lang/rust#20953. Once those are fixed, I think we can drop Shrinker.

`#[quickcheck]` doesn't work when `quickcheck` isn't in crate root

The #[quickcheck] macro doesn't work when the quickcheck crate is linked as a path other than ::quickcheck:

#![feature(plugin)]
#![plugin(quickcheck_macros)]

#[cfg(test)]
mod test {
    extern crate quickcheck;

    #[quickcheck]
    fn bar() -> bool { true }
}

Errors:

src/lib.rs:8:5: 8:15 error: failed to resolve. Maybe a missing `extern crate quickcheck`?
src/lib.rs:8     #[quickcheck]
                 ^~~~~~~~~~
src/lib.rs:8:5: 8:18 error: unresolved name `quickcheck::quickcheck`
src/lib.rs:8     #[quickcheck]
                 ^~~~~~~~~~~~~

It's clear why this is happening from the macro's implementation, but it would be nice for it to be supported. One solution would be to pass arguments to the #[quickcheck] macro like

#[quickcheck(self, quickcheck)]
fn bar() -> foo { true }

and turn the sequence of identifiers into a path, defaulting to ::quickcheck when none are given. It should also work when quickcheck is used under a different name:

extern crate "quickcheck" as baz;
#[quickcheck(self, baz)]
fn bar() -> foo { true }

This would involve making use of the third argument (the &ast::MetaItem) passed to expand_meta_quickcheck, which is currently ignored.

quickcheck depends on WinAPI?

 Downloading rand v0.3.11 (reasonable - quickcheck is a randomized test)
 Downloading log v0.3.2 (reasonable - it's omnipresent)
 Downloading winapi v0.2.4 ( ??? )
 Downloading quickcheck v0.2.24

Idea: Testing `fail!`ures with `TestResult::must_fail`

Currently, quickcheck doesn't provide a way to test properties that must trigger a task failure to pass. For example, if you want to test that bound checking is working, you would write the following property:

#[quickcheck]
fn out_of_bounds(length: uint, index: uint) -> TestResult {
    let v = Vec::from_elem(length, 0u8);

    if index < length {
        TestResult::discard()
    } else {
        // v[index] ?
    }
}

But you are missing a piece: You need some function that returns TestResult::passed() if v[index] triggers a task failure, or TestResult::failed() if v[index] succeeded.

That's why I propose adding the must_fail function to the library, where must_fail is defined as:

use quickcheck::TestResult;
use std::comm;
use std::io::ChanWriter;
use std::task::TaskBuilder;

// This should be a `TestResult` static method
fn must_fail<T: Send>(f: proc(): Send -> T) -> TestResult {
    // A "/dev/null" sink for the stderr of the child task
    let (tx, _) = comm::channel();
    let dev_null = box ChanWriter::new(tx) as Box<Writer + Send>;

    let failed =
        TaskBuilder::new().
            // Redirect the stderr of the child task to "/dev/null"
            stderr(dev_null).
            try(f).
            is_err();

    TestResult::from_bool(failed)
}

This function provides the missing functionality to complete the out_of_bounds property:

#[quickcheck]
fn out_of_bounds(length: uint, index: uint) -> TestResult {
    let v = Vec::from_elem(length, 0u8);

    if index < length {
        TestResult::discard()
    } else {
        must_fail(proc() v[index])
    }
}

Which now can be tested:

running 1 test
test out_of_bounds ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

And if you wrongly implement the test, for example by reversing the index < length condition, then the test would fail as expected:

running 1 test
test out_of_bounds ... FAILED

failures:

---- out_of_bounds stdout ----
        task 'out_of_bounds' failed at '[quickcheck] TEST FAILED. Arguments: (1, 0)', src/lib.rs:83



failures:
    out_of_bounds

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured

@BurntSushi What do you think? Should this functionality be added to quickcheck?

quickcheck_macros does not work on stable (or beta)

Using stable Rust trying to install quickcheck_macros gives:

Compiling quickcheck_macros v0.2.24
/home/users/russel/.cargo/registry/src/github.com-0a35038f75765ae4/quickcheck_macros-0.2.24/src/lib.rs:8:1: 8:45 error: #[feature] may not be used on the stable release channel
/home/users/russel/.cargo/registry/src/github.com-0a35038f75765ae4/quickcheck_macros-0.2.24/src/lib.rs:8 #![feature(plugin_registrar, rustc_private)]

which more or less makes this potentially wonderful testing tool useless. Or have I missed something?

The random selection doesn't appear to be very random

I have a type which wraps an i32, and wrote an Arbitrary impl like so:

trait Arbitrary<PgDate> {
    fn arbitrary<G: Gen>() -> Self {
          PgDate(i32::arbitrary())
    }
}

When I actually output what it's running with, the values are only ranging from 100 to -100, instead of 100 completely random numbers as I'd expect. Additionally, shrink appears to be flawed on these types. My understanding was that quickcheck would test for known problematic values for a given type. For i32 I'd expect that to at minimum be 1, 0, -1, i32::MAX and i32::MIN, but when I add the shrink like so:

fn shrink(&self) -> Box<Iterator<Item=Self>> {
    Box::new(self.0.shrink().map(PgDate))

I just see the same range of -100 to 100. This caused a critical bug that occurs for any values less than -2451545 to go unnoticed.

Strings generated by default should have more usual characters

Strings typically generted look like this:

򒽹򪬛򘌟󥫹񕘼򟶹񍀝󿡥񰫩􂒡𻘒򅇪򍸈򁑙򟪆󴥏􅲴󩇇Ք𡫗󼺆򺩪𾺗𵅟𻎚񦎅񳜿󔈐ᘤ񜾊񺥿򍔛󆬭𙚹񃃣񥊆򇆗򂤇􀑬󨍏󉨫򺌑񽙕񷗮󻐉𿞊񹩵򖬊񣁇󘅛󖛉𼄠󄚷򽕎

񡰎𣒌󹣵

􅘤󀞶񼮳𮕇򀁕񗎰򀇦򹖻񚂫󚾪򃢛ൾ𬫤񘖤􇾷򇍤񮅈弅򥅽񨭴󶈡񫯭𧚼䝠Ᏼ􌷞󻃃񛑓󵎍𯭜􄼧򛷺񚂛񊪧󯱩񩴝𛭑𨀒񡥍󛢘񺐢𵑌眻󖙞񅉊򛻨񆷮󸧖󵔸񎽔򡚥񂼮򆼤񄓭񷬗􂭡򼠀񥉑󓊢򡽍􀟞񮆀񿫇񿌝򒋏񜎀񢝒򋯼񹌈􃔪򈟙󟬠󀧸󀉖𠥤񌡭𧆼񦛼񶰆񂠑𻗛򙄒

򁂺󶼀𰷹𾏉򮘭򈝥󓞤򫚁󙖘󆖙𰻟񇫙𴋅𠈼󹌀凾𖙟𠓕𾭭𗢐񥂡񇫘򫯝󨃖僧󰲺򘳑𛉏񡴶􏹊򔌇ᘼ􎜅󇆯󈤟󷃚􎞎񦖄봄򬩘񎩭򓲜󍥊𰀈􍆔񥝖򅈳𿴛􌆗񍏰񛯚􏡩򵆠񝭆􍘣򅕜򞙄󬍦񜟩󐮐򊽛󘉏񔀊񎇝󞏏񥍇󕎎𑝩񡨭򋡠򪙃󆂵𫟯񩽗𕡫򞠇𤷸򙺛򄎩򍮂򒹣䴒𻉜󸅩􎬙𷆊񲎀񪨌򌀀􄻖񇋒󹜅

񒢩򊟗𥁿򌅞񬕧𞎂񮕄򞿮ҙ󐢉󠢜񭈑󕓴󅸛򕎅𳞇񪉩񞢜򭧘󛦦󎪦󱏚홀񍋧篬󦲫򈧹񍔿񚣪򛍾𡚙󫬴򽉫񈝗񔁯󹕩񦟠󼝹𦼄󹆲񜋑񠇒񇽖􋤋񤔇󐂚񼛍􄼀󮀯𔯀󦃂񵒵򄯎󩎅򓊕򯠎񌬆롇񘺊񵺾𕧨񚾓򍚬󷈮󠢧򦂼𹥞󮾛򼢁􀏜򸬟󮃣򪾂򬁷񯕞񋓝󞭤󰥔񐮃󲏫󻞻򻬒􄑎򉗭򄫛󨶇󔽟򹑹򼹨򨵖񰊅񻣊

񕂍􌥩񵉗񶗖𬉞魊񞦹󙤵𦪀𒮡󄮽𕗠񥽕􂥦􈲹󙁡򞞌𵄐𳎩뚲󄬥򶰂񷷢򝬉񞝟򃹪腎󑍭򒋀򔲙󉺿񲥓𝹯󩬑

񾧍󝫮򎿛窯񕓨􈲶񽶛򩪣򁹡􂏔򛘎򘇀𠷺񎂦񭭸񽎊𐊊𨺿򆊺𗞩􌽂񁸶輬񄃸񅙜񐢳񔧏񈙄𝐳𪉛

𥹠𼞳󾢙𔅿􊭷񾣐򎕊񭳖򕸌󎀛򶃣𜿉􀢛󶄿𲊊񪟛񈘉񲻦񭩂󳄒𾺲𯆊񏸆񌼠񭳒񷞈򁓎􈋖𚜸󿒲򁔀𰤫򫥑򞼲𥐸񥾥󓮿򳖱𗋕󳉋􉠨𖍳󷕝򝘊򏩰󁺱񍰉崳󀁈𒯻򿮥𯙇񥻂󓿭򫙎񄦽񠷎𞸁񵳳󿧻􂯓󹗄򇪾󽘝󉵷򗚫񸐄󘁳񏶌񥵾󧒟򮫰𖪄񞼗􏾢𶕘򊮴𗰼򄌋񺿭򣘸

򵑆򢀍򯪂񏁾𧔥󼖈򬿚󰖓􁯌򁆙񎠤񬴞𝒲󹩝򾜣񰢝󭙯񠵛񹘦󒳼񡫉󺲢񘾥񿔷󾣎埙󊽑򼪐򊰭񠮺禹󾣣𼵝򒹐񓪊󫨬򫄒󦉂񇫄󬆿򻃃񯟶󜚓𷗚𲦂󻔴񮏂򶰎񥊢񰵪񢔀򁻢喒󢷅󟽄񚐚񓼈򭶸􅇆󭏂𜯃𨖉󑶧򪌿𨌽򄔖𱢼򩱼򫮴

𻥻򖿄󎰁𔱷𑒂𼟊􇼅𲂄􈔜󉄘􋫢𖔄񋺆𬎽򛖢򠬔􃸫􀵆𮘜󛥺􂶐򵄤𺐅񀕛񟥠􏽑󹫠򡧄󒸡򰎜򊎰񥑌񇇣𩔒򰅈򵄯񓣏󓢍򑛛򉨸𾓊𷅣𵼤𦌘򓀞𽣟򞴍

񒚞񙶴󫃔񀹮񣍯𵘣󾈣򐜴󄌿𦶞󯛫󄊁񳍮񚶨󡷣𸫂𞳊񏜪󜮶𺾆㮄񆡐󓶭﯈󊎊󿧺􏋔󤍄󁾒򣎦񛦋򯠖􍓙񜠔򇺱𓆦񟣤󝢧򱁕񗽳󶱮󶊼󿓊򾚓򵵆򼫏󄈬򜒕󱦡񘗏򮑏󔼋򂄸󺺘𨛽󚲁񶗜󖿭󣠯򆱩񰊫憎񳥒񼷵𠗆񍻠󽖾𿂆󑓓񎚯򦉠𘊲

𳸈򋸴󂩗񽰋񄨪񏉙򀤵󕳷𚱲򵚑󓶵񀐡󈁡򮖵񜬃񫡵񠬳񬶊𡱭񅼺򝙾񞬁ꈺ𹖉𵌛ロ񒁭􉫒󋟑񔊢򽲓񿨈񑜰񇿴򢣖􍟣򰮍󿘱󄡣󹉚𬥿񋘙𔭦򡎑

󰺿󶄔𬆷󱂌󉬞󾪢񖖖񮊕񝧃򾽼񨤳𸾂𣑌󸕖󹴌𬜄𑼦􌷱򩔤𖌸񥺼񗎱񗱐󲣑𴒨󴹒𹒪󋊌󨴖򙀁򁿵񫘕󐇯򂯲񵕌񁢜󹤨򙢄񨓩򄠑񻨸𻍦󦩒񬪸󻴴񜀛򝇩񼗕򣚉󵏛󣹥򉭞򦚎񀺲񆛜󮟏񟒫𲹇򋼡򷧘񿩬󎭝򪆀𛑛񻉞󝫨𡞱㆒

򼋡󯻭􁤛񎔝󸴭󜈰񱚱픦󎍆𢐻򷟝񞮵蘪󖣢𫭪𲊺󿜚񈅗򿧙󿴞񫌱衯򉕭򊞴қ󴙠𱜯񙐰򍊌񮨬󪾪򮝂𾨆񱘾񡠇팢򗡗򽑶򴸟𙅡򎋎𐠮󶖉򄡏󟛿􏠰򟿢񚨬憲򭫉􉌞񘮝󗕖񡏤𮺀񫐀𔚈񷋭𙪢򇬣򛡡񗚡򓛏򘌶𦷴񶵍򮵔숥𲟪

񘿘𛀦򵊻󠑜󼾐𙈨󹲃𸯕𜆦淅󍵮𰂘񛦑󛫌󝌲󔕇󹙮񧃷񧈵񠶄򙹫󓰆򒈐􃎢邮򣻖񩹖𓋱𥥫񩘆

It fails (or takes long) to find simple case like a when something starts with a space, special character or like this.

I think normal characters should be preferred to deeply Unicode things.

I think by default there should be tiers of characters classes:

  1. Bug-prone characters: whitespace, punctuation, control characters, maybe up to 5 selected Unicode queeries like zero-width space;
  2. [a-zA-Z0-9_];
  3. Unicode characters in the first plane;
  4. Everything else.

And character generator may aim for, for example, 10% of buggy chars, 40% of [a-zA-Z0-9_], 40% of basic Unicode characters, 10% of everything else.

Compilation flow arrested on ARM using 1.8 dinghy

Compiling quickcheck_macros v0.2.26
     Running `rustc /tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs --crate-name quickcheck_macros --crate-type dylib -C prefer-dynamic -C opt-level=3 -C metadata=df62799bae73490e -C extra-filename=-df62799bae73490e --out-dir /tmp/ramp-master/target/release/deps --emit=dep-info,link -L dependency=/tmp/ramp-master/target/release/deps -L dependency=/tmp/ramp-master/target/release/deps --extern quickcheck=/tmp/ramp-master/target/release/deps/libquickcheck-ef66e0544cfbee5c.rlib --cap-lints allow`
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10:1: 10:21 error: found possibly newer version of crate `std` which `syntax` depends on [E0460]
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10 extern crate syntax;
                                                                                            ^~~~~~~~~~~~~~~~~~~~
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10:1: 10:21 note: perhaps this crate needs to be recompiled?
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10 extern crate syntax;
                                                                                            ^~~~~~~~~~~~~~~~~~~~
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10:1: 10:21 note: crate `std` path #1: /home/odroid/rust-1.8.0-system-alloc-LFS/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libstd-db5a760f.rlib
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10:1: 10:21 note: crate `std` path #2: /home/odroid/rust-1.8.0-system-alloc-LFS/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libstd-db5a760f.so
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10:1: 10:21 note: crate `syntax` path #1: /home/odroid/rust-1.8.0-system-alloc-LFS/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libsyntax-db5a760f.so
/tmp/.cargo/registry/src/github.com-48ad6e4054423464/quickcheck_macros-0.2.26/src/lib.rs:10:1: 10:21 note: crate `syntax` path #2: /home/odroid/rust-1.8.0-system-alloc-LFS/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libsyntax-db5a760f.rlib
error: aborting due to previous error
Could not compile `quickcheck_macros`.

Dinghy is almost two nights old.

quickcheck-macros doesn't build on the latest nightly

When building on the latest nightly, I get the following error message:

$ cargo test
 Downloading rand v0.3.12
 Downloading log v0.3.4
 Downloading quickcheck v0.2.24
 Downloading winapi v0.2.5
 Downloading libc v0.2.2
 Downloading quickcheck_macros v0.2.24
   Compiling winapi v0.2.5
   Compiling libc v0.2.2
   Compiling log v0.3.4
   Compiling advapi32-sys v0.1.2
   Compiling rand v0.3.12
   Compiling quickcheck v0.2.24
   Compiling quickcheck_macros v0.2.24
/Users/hawk/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/quickcheck_macros-0.2.24/src/lib.rs:23:5: 23:28 error: unresolved import `rustc::plugin::Registry`. Could not find `plugin` in `rustc` [E0432]
/Users/hawk/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/quickcheck_macros-0.2.24/src/lib.rs:23 use rustc::plugin::Registry;
                                                                                                                                    ^~~~~~~~~~~~~~~~~~~~~~~
/Users/hawk/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/quickcheck_macros-0.2.24/src/lib.rs:23:5: 23:28 help: run `rustc --explain E0432` to see a detailed explanation
error: aborting due to previous error
Could not compile `quickcheck_macros`.

To learn more, run the command again with --verbose.

On the latest nightly:

$ rustc --version
rustc 1.7.0-nightly (81ae8be71 2015-12-09)
$ cargo --version
cargo 0.7.0-nightly (1af03be 2015-12-08)

Debug trait somehow getting lost (?) making debugging difficult

Expected

Details about why my my data structure failed.

Actual

UNABLE TO SHOW RESULT OF PANIC.

Details

(I am still learning Rust, so bear with me if my code is dumb or I miss something obvious.)

I am trying to define simple, stable-compatible quickcheck tests for a trait, that can be reused to test different data structures that implement it. In this case, I am trying to test a persistent heap.

Data structure + generic test.

Unfortunately, one of my two implementations is broken somewhere, but the only information I get out of quickcheck is Error: "UNABLE TO SHOW RESULT OF PANIC."', <path>/quickcheck-0.2.21/src/tester.rs:113.

Link to broken build.

Link to broken usage location

The data structure in question has #[derive(Debug)] and I have tested that println("{:?}", s) works for this instance of the data structure, so I don't know why I am not getting any other information about the panic, and I don't know what to do to make the situation better.

make number shrinking lazy

Currently, shrinking numbers is done by filling up a vector with all possibilities and returning it as an iterator. It would be great if this were changed so that each shrunk value wasn't generated until the iterator advanced.

How to make generated parameters test certain cases

I have another question about writing QuickCheck tests.

My function under test, edit_distance, has another property, which I want to quickcheck.

It is zero if and only if the strings are equal.

This requires that both parameters reasonably often are equal. I have a naive implementation here:

febeling/edit-distance@30532c2#diff-475a9530a9c1e888d097445199b74c2fR75

But when I run it and prepare the code a bit, I have seen that the the condition 'strings are equal' is never met. I guess that's a common problem in quickcheck test. Is there a good way to deal with this case?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.