Property testing using Chrono

Hi all, I'm after some advice. I've used both quickcheck and proptest to good effect, but I trip over when I want to generate chrono types (e.g. NativeDateTime).

The problem comes down to the fact that both quickcheck and proptest define their own Arbitrary traits which are different from the Arbitrary trait from the arbitrary crate(!).

chrono does implement arbitrary::Arbitrary but I can't see how to plug the gap between arbitrary::Arbitrary and either quickcheck's or proptest's Arbitrary trait. This feels like such a common thing to want to do that I must be missing something...

For example, what magic do I need to get the following to work (NOTE: dependencies rather than dev-dependencies just to eliminate scoping issues):

# Cargo.toml
[dependencies]
chrono = {version = "0.4", features = ["arbitrary"]}
quickcheck = "1"
arbitrary = "1.3"

src/main:

fn main() {
    println!("Hello, world!");
}

use chrono::NaiveDate;
use arbitrary::{Arbitrary};

#[derive(Arbitrary, Debug, Clone)]
pub struct MyStruct {
    d: NaiveDate
}

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

#[cfg(test)]
mod tests {
    quickcheck! {
      fn prop(xs: Vec<super::MyStruct>) -> bool {
          true
      }
  }
}

results in:

➜  chrono-arbitrary git:(master) ✗ cargo test
   Compiling chrono-arbitrary v0.1.0 (/Users/coliny/RustroverProjects/chrono-arbitrary)
error[E0277]: the trait bound `MyStruct: quickcheck::Arbitrary` is not satisfied
   --> src/main.rs:19:5
    |
19  | /     quickcheck! {
20  | |       fn prop(xs: Vec<super::MyStruct>) -> bool {
21  | |           true
22  | |       }
23  | |   }
    | |   ^
    | |   |
    | |___the trait `quickcheck::Arbitrary` is not implemented for `MyStruct`
    |     required by a bound introduced by this call
    |
    = help: the following other types implement trait `quickcheck::Arbitrary`:
              bool
              char
              isize
              i8
              i16
              i32
              i64
              i128
            and 55 others
    = note: required for `Vec<MyStruct>` to implement `quickcheck::Arbitrary`
    = note: required for `fn(Vec<MyStruct>) -> bool` to implement `Testable`
note: required by a bound in `quickcheck`
   --> /Users/coliny/.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/src/tester.rs:182:22
    |
182 | pub fn quickcheck<A: Testable>(f: A) {
    |                      ^^^^^^^^ required by this bound in `quickcheck`
    = note: this error originates in the macro `quickcheck` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `chrono-arbitrary` (bin "chrono-arbitrary" test) due to previous error
➜  chrono-arbitrary git:(master) ✗ 

Now this makes sense, because I'm deriving arbitrary::Arbitrary and not quickcheck::Arbitrary, but surely this is a really common thing to want to do, so I'm sure I'm missing some glue...

Am I the first person who wants to do this (use arbitrary::Arbitrary in quickcheck or proptest)?

Thanks!

1 Like

If it’s any use, I found this conversation on the arbitrary issue tracker: Use same `Arbitrary` trait as quickcheck? · Issue #61 · rust-fuzz/arbitrary · GitHub

Looks like the short answer is there is currently no way to use the trait with quickcheck or proptest.

It should be possible to create your own proptest strategies using public chrono constructors, regardless.

2 Likes

FWIW I think I'm going to stick with arbitrary::Arbitrary, arbtest - Rust and cargo fuzz.

The APIs aren't too dissimilar, I think it would be possible to build an adapter type library between them. This compiles, but I don't know if it behaves correctly:

use quickcheck::Gen;
use arbitrary::Unstructured;

#[derive(Clone)]
struct A<T>(T);

impl<'a, T: arbitrary::Arbitrary<'a> + Clone + 'static> quickcheck::Arbitrary for A<T> {
    fn arbitrary(gen: &mut Gen) -> Self {
        let bytes: &'static [u8] = Vec::arbitrary(gen).leak();
        let mut u = Unstructured::new(&bytes);
        let t = u.arbitrary().unwrap();
        A(t)
    }
}
1 Like

I also found this for proptest: Provide a proper strategy for dates using chrono · Issue #109 · proptest-rs/proptest (github.com)

And the way I am currently generating timestamps is based on impl Arbitrary for SystemTime.

1 Like

for future travellers:

(although I'm really rocking vanilla arbitrary and arbtest right now :wink:

2 Likes