quickcheck icon indicating copy to clipboard operation
quickcheck copied to clipboard

How to combine quickcheck 1+ with fake?

Open marktani opened this issue 2 years ago • 3 comments

Following the zero2production book With quickcheck = "0.9.2", quickcheck_macros = "0.9.1" and fake = "~2.3", the following works, because the function Arbitrary::arbitrary expected a Gen trait, and Gen used to be a trait:

#[derive(Debug, Clone)]
struct ValidEmailFixture(pub String);

impl quickcheck::Arbitrary for ValidEmailFixture {
    fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
        let email = SafeEmail().fake_with_rng(g);
        Self(email)
    }
}

#[quickcheck_macros::quickcheck]
fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool {
    SubscriberEmail::parse(valid_email.0).is_ok()
}

Then we pass the mutable reference g into SafeEmail().fake_with_rng(g); and it works - fake generates random valid emails.

However, in quickcheck = "1", quickcheck::Gen is no trait anymore, only a struct. I haven't found out how to access the inner rng: rand::rngs::SmallRng of Gen to pass it into SafeEmail().fake_with_rng and get fake to work with quickcheck.

How is it still possible in 1+?

marktani avatar Sep 01 '23 15:09 marktani

I've encountered the same issue. I solved it in a hacky way by reimplementing SafeEmail.

#[cfg(test)]
mod tests {
    use fake::locales::{self, Data};
    use quickcheck::{Arbitrary, Gen};

    #[derive(Debug, Clone)]
    struct ValidEmailFixture(pub String);

    impl Arbitrary for ValidEmailFixture {
        fn arbitrary(g: &mut Gen) -> Self {
            let username = g
                .choose(locales::EN::NAME_FIRST_NAME)
                .unwrap()
                .to_lowercase();
            let domain = g.choose(&["com", "net", "org"]).unwrap();
            let email = format!("{username}@example.{domain}");
            Self(email)
        }
    }

    #[quickcheck_macros::quickcheck]
    fn valid_emails_are_parsed_successfully(email: ValidEmailFixture) -> bool {
        SubscriberEmail::parse(email.0).is_ok()
    }
}

Not ideal but also not too bad.

Zero to Production's author, Luca Palmieri, posted an excerpt that covers OP's code above if anyone wants to follow along.

joshuamegnauth54 avatar Dec 23 '23 06:12 joshuamegnauth54

Same issue here @BurntSushi. How to use quickcheck together with other tools like fake which needs an RNG

npuichigo avatar Jan 25 '24 13:01 npuichigo

I've encountered the same issue. I solved it in a hacky way by reimplementing SafeEmail.

#[cfg(test)]
mod tests {
    use fake::locales::{self, Data};
    use quickcheck::{Arbitrary, Gen};

    #[derive(Debug, Clone)]
    struct ValidEmailFixture(pub String);

    impl Arbitrary for ValidEmailFixture {
        fn arbitrary(g: &mut Gen) -> Self {
            let username = g
                .choose(locales::EN::NAME_FIRST_NAME)
                .unwrap()
                .to_lowercase();
            let domain = g.choose(&["com", "net", "org"]).unwrap();
            let email = format!("{username}@example.{domain}");
            Self(email)
        }
    }

    #[quickcheck_macros::quickcheck]
    fn valid_emails_are_parsed_successfully(email: ValidEmailFixture) -> bool {
        SubscriberEmail::parse(email.0).is_ok()
    }
}

Not ideal but also not too bad.

Zero to Production's author, Luca Palmieri, posted an excerpt that covers OP's code above if anyone wants to follow along.

An extension for more context if you came here from the same book - This is exactly how fake is implmenting the safeEmail function.

impl<L: Data + Copy> Dummy<SafeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &SafeEmail<L>, rng: &mut R) -> Self {
        let username: String = FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase();
        let domain = ["com", "net", "org"].choose(rng).unwrap();
        format!("{}@example.{}", username, domain)
    }
}

For more information, there is #265 to read for why rng is no longer a dependency.

Enough Digging, Enjoy coding :3

choco-green avatar Apr 30 '24 12:04 choco-green