BurntSushi / quickcheck

Automated property based testing for Rust (with shrinking).
The Unlicense
2.4k stars 149 forks source link

Allow scaling size up or down for downstream Arbitrary impls #173

Closed sunshowers closed 4 years ago

sunshowers commented 7 years ago

While trying to use QuickCheck for testing my code, I've several times found the need to scale size up or down (to get better coverage for larger inputs, or for performance reasons). While creating more complex test inputs consisting of data stitched across several crates, I've also found the need to scale size up or down depending on how big I want a subpart to be.

It would be great if Gen provided a method which looked something like:

pub fn wrap_size(&mut self, new_size: usize) -> GenWrapper<&mut Self>

which returned a wrapper with new_size to pass to generators for subparts.

BurntSushi commented 7 years ago

Why doesn't the existing StdGen::new method do what you want?

sunshowers commented 7 years ago

That would mean that I would be overriding the choice of generator/Rng passed down to me. Is that OK?

On Mon, Apr 24, 2017 at 03:57 Andrew Gallant notifications@github.com wrote:

Why doesn't the existing StdGen::new method https://docs.rs/quickcheck/0.4.2/quickcheck/struct.StdGen.html#method.new do what you want?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/BurntSushi/quickcheck/issues/173#issuecomment-296618885, or mute the thread https://github.com/notifications/unsubscribe-auth/AALBihQggox51IzmS1s_rZiHy7Qg9-eFks5rzIAGgaJpZM4NFsqf .

bluss commented 7 years ago

You can use it to adapt the generator passed to you (it's an Rng)

I use this helper type for making smaller graphs in petgraph:

use quickcheck::{Arbitrary, Gen, StdGen};
use std::ops::Deref;

#[derive(Copy, Clone, Debug)]
/// quickcheck Arbitrary adaptor - half the size of `T` on average
pub struct Small<T>(pub T);

impl<T> Deref for Small<T> {
    type Target = T;
    fn deref(&self) -> &T { &self.0 }
}

impl<T> Arbitrary for Small<T>
    where T: Arbitrary
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let sz = g.size() / 2;
        Small(T::arbitrary(&mut StdGen::new(g, sz)))
    }

    fn shrink(&self) -> Box<Iterator<Item=Self>> {
        Box::new((**self).shrink().map(Small))
    }
}