BurntSushi / quickcheck

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

Macro for quickchecks #131

Closed bluss closed 8 years ago

bluss commented 8 years ago

This macro reduces boilerplate (and removes the need for the compiler plugin). It could be a nice thing to include into the crate.

Limitations:

Sample usage:

quickcheck! {
    fn equal_stride(data: Vec<u8>, stride: i8) -> bool {
        let mut stride = stride;
        if stride == 0 {
            // never zero
            stride += 1;
        }
        if stride > 0 {
            itertools::equal(Stride::from_slice(&data, stride as isize),
                             data.iter().step(stride as usize))
        } else {
            itertools::equal(Stride::from_slice(&data, stride as isize),
                             data.iter().rev().step(-stride as usize))
        }
    }

    fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
        correct_size_hint(a.cartesian_product(b))
    }
    fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
        correct_size_hint(iproduct!(a, b, c))
    }
}

implementation:

macro_rules! quickcheck {
    (@as_items $($i:item)*) => ($($i)*);
    {
    $(fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { $($code:tt)* })*} => (
        quickcheck!{@as_items
        $(
            #[test]
            fn $fn_name() {
                fn prop($($arg_name: $arg_ty),*) -> $ret {
                    $($code)*
                }
                ::quickcheck::quickcheck(prop as fn($($arg_ty),*) -> $ret);
            }
        )*
        }
    )
}
BurntSushi commented 8 years ago

This seems really nice. I remember trying to achieve something like this but failing---maybe I got too caught up on missing the pattern support. I suppose that's less important now, since we have lots of arity impls on Testable now, reducing the need for using tuples as a hack.

Getting rid of those fn casts is glorious.