diff --git a/Cargo.toml b/Cargo.toml index 2cc1c40..7d6ebeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ build = "build.rs" exclude = ["/ci/*", "/.travis.yml", "/bors.toml"] [package.metadata.docs.rs] -features = ["std", "bigint-std", "serde"] +features = ["std", "bigint-std", "serde", "quickcheck"] [dependencies] @@ -36,6 +36,11 @@ optional = true version = "1.0.0" default-features = false +[dependencies.quickcheck] +optional = true +version = "0.9.0" +default-features = false + [features] default = ["bigint-std", "std"] i128 = ["num-integer/i128", "num-traits/i128"] diff --git a/ci/test_full.sh b/ci/test_full.sh index 29ff03d..ea33d2c 100755 --- a/ci/test_full.sh +++ b/ci/test_full.sh @@ -5,9 +5,12 @@ set -ex echo Testing num-rational on rustc ${TRAVIS_RUST_VERSION} FEATURES="std bigint-std serde" -if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.26.0)$ ]]; then +if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.26.0|1.31.0)$ ]]; then FEATURES="$FEATURES i128" fi +if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then + FEATURES="$FEATURES quickcheck" +fi # num-rational should build and test everywhere. cargo build --verbose diff --git a/src/lib.rs b/src/lib.rs index 87380d2..8ddc41b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,8 @@ #[cfg(feature = "bigint")] extern crate num_bigint as bigint; +#[cfg(feature = "quickcheck")] +extern crate quickcheck; #[cfg(feature = "serde")] extern crate serde; @@ -47,6 +49,9 @@ use traits::{ Pow, Signed, Zero, }; +#[cfg(feature = "quickcheck")] +use quickcheck::{Arbitrary, Gen}; + /// Represents the ratio between two numbers. #[derive(Copy, Clone, Debug)] #[allow(missing_docs)] @@ -254,6 +259,28 @@ impl Ratio { } } +#[cfg(feature = "quickcheck")] +impl Arbitrary for Ratio { + fn arbitrary(g: &mut G) -> Ratio { + let mut denom = T::arbitrary(g); + while denom.is_zero() { + denom = T::arbitrary(g); + } + Ratio::new(T::arbitrary(g), denom) + } + + #[cfg(feature = "std")] + fn shrink(&self) -> std::boxed::Box>> { + let numer = self.numer.shrink().next().unwrap_or(T::zero()); + let denom = if self.denom.is_one() { + self.denom.clone() + } else { + self.denom.shrink().next().unwrap_or(T::one()) + }; + std::boxed::Box::new(std::iter::once(Ratio::new(numer, denom))) + } +} + impl> Ratio { /// Raises the `Ratio` to the power of an exponent. #[inline]