From d0f74995d0bcf7fa10dbaf42ebc68708fe84118a Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 17 Nov 2021 19:19:18 +0100 Subject: [PATCH] Update to quickcheck 1.0 New in 1.0 is that integers now generate values in their whole range. That creates a different situation for the tests taking isize than before. Shrink their accepted values for now, and leave as fixmes to investigate and improve. In some cases, the tests are slow to execute. In other cases, the tests fail with large values (probably overflow), and following that, the case shrinking is extremely slow. --- Cargo.toml | 2 +- ndarray-rand/Cargo.toml | 4 ++-- ndarray-rand/src/lib.rs | 2 +- ndarray-rand/tests/tests.rs | 29 +++++++++++++++++++---------- src/dimension/mod.rs | 28 ++++++++++++++++++++++------ 5 files changed, 45 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 75875d619..44dd52fb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ rawpointer = { version = "0.2" } [dev-dependencies] defmac = "0.2" -quickcheck = { version = "0.9", default-features = false } +quickcheck = { version = "1.0", default-features = false } approx = "0.4" itertools = { version = "0.10.0", default-features = false, features = ["use_std"] } diff --git a/ndarray-rand/Cargo.toml b/ndarray-rand/Cargo.toml index 4127d5631..4e9bf265f 100644 --- a/ndarray-rand/Cargo.toml +++ b/ndarray-rand/Cargo.toml @@ -16,7 +16,7 @@ keywords = ["multidimensional", "matrix", "rand", "ndarray"] [dependencies] ndarray = { version = "0.15", path = ".." } rand_distr = "0.4.0" -quickcheck = { version = "0.9", default-features = false, optional = true } +quickcheck = { version = "1.0", default-features = false, optional = true } [dependencies.rand] version = "0.8.0" @@ -24,7 +24,7 @@ features = ["small_rng"] [dev-dependencies] rand_isaac = "0.3.0" -quickcheck = { version = "0.9", default-features = false } +quickcheck = { version = "1.0", default-features = false } [package.metadata.release] no-dev-version = true diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs index d9edabfdb..448eb10d9 100644 --- a/ndarray-rand/src/lib.rs +++ b/ndarray-rand/src/lib.rs @@ -304,7 +304,7 @@ pub enum SamplingStrategy { // `Arbitrary` enables `quickcheck` to generate random `SamplingStrategy` values for testing. #[cfg(feature = "quickcheck")] impl Arbitrary for SamplingStrategy { - fn arbitrary(g: &mut G) -> Self { + fn arbitrary(g: &mut Gen) -> Self { if bool::arbitrary(g) { SamplingStrategy::WithReplacement } else { diff --git a/ndarray-rand/tests/tests.rs b/ndarray-rand/tests/tests.rs index d8b18fe56..5a0cd6c1b 100644 --- a/ndarray-rand/tests/tests.rs +++ b/ndarray-rand/tests/tests.rs @@ -5,7 +5,7 @@ use ndarray_rand::rand::{distributions::Distribution, thread_rng}; use ndarray::ShapeBuilder; use ndarray_rand::rand_distr::Uniform; use ndarray_rand::{RandomExt, SamplingStrategy}; -use quickcheck::quickcheck; +use quickcheck::{quickcheck, TestResult}; #[test] fn test_dim() { @@ -51,7 +51,8 @@ fn oversampling_without_replacement_should_panic() { } quickcheck! { - fn oversampling_with_replacement_is_fine(m: usize, n: usize) -> bool { + fn oversampling_with_replacement_is_fine(m: u8, n: u8) -> TestResult { + let (m, n) = (m as usize, n as usize); let a = Array::random((m, n), Uniform::new(0., 2.)); // Higher than the length of both axes let n_samples = m + n + 1; @@ -59,24 +60,28 @@ quickcheck! { // We don't want to deal with sampling from 0-length axes in this test if m != 0 { if !sampling_works(&a, SamplingStrategy::WithReplacement, Axis(0), n_samples) { - return false; + return TestResult::failed(); } + } else { + return TestResult::discard(); } // We don't want to deal with sampling from 0-length axes in this test if n != 0 { if !sampling_works(&a, SamplingStrategy::WithReplacement, Axis(1), n_samples) { - return false; + return TestResult::failed(); } + } else { + return TestResult::discard(); } - - true + TestResult::passed() } } #[cfg(feature = "quickcheck")] quickcheck! { - fn sampling_behaves_as_expected(m: usize, n: usize, strategy: SamplingStrategy) -> bool { + fn sampling_behaves_as_expected(m: u8, n: u8, strategy: SamplingStrategy) -> TestResult { + let (m, n) = (m as usize, n as usize); let a = Array::random((m, n), Uniform::new(0., 2.)); let mut rng = &mut thread_rng(); @@ -84,19 +89,23 @@ quickcheck! { if m != 0 { let n_row_samples = Uniform::from(1..m+1).sample(&mut rng); if !sampling_works(&a, strategy.clone(), Axis(0), n_row_samples) { - return false; + return TestResult::failed(); } + } else { + return TestResult::discard(); } // We don't want to deal with sampling from 0-length axes in this test if n != 0 { let n_col_samples = Uniform::from(1..n+1).sample(&mut rng); if !sampling_works(&a, strategy, Axis(1), n_col_samples) { - return false; + return TestResult::failed(); } + } else { + return TestResult::discard(); } - true + TestResult::passed() } } diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 7bb92892c..948c76f9c 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -920,12 +920,16 @@ mod test { } quickcheck! { - fn extended_gcd_solves_eq(a: isize, b: isize) -> bool { + // FIXME: This test can't handle larger values at the moment + fn extended_gcd_solves_eq(a: i16, b: i16) -> bool { + let (a, b) = (a as isize, b as isize); let (g, (x, y)) = extended_gcd(a, b); a * x + b * y == g } - fn extended_gcd_correct_gcd(a: isize, b: isize) -> bool { + // FIXME: This test can't handle larger values at the moment + fn extended_gcd_correct_gcd(a: i16, b: i16) -> bool { + let (a, b) = (a as isize, b as isize); let (g, _) = extended_gcd(a, b); g == gcd(a, b) } @@ -941,9 +945,12 @@ mod test { } quickcheck! { + // FIXME: This test can't handle larger values at the moment fn solve_linear_diophantine_eq_solution_existence( - a: isize, b: isize, c: isize + a: i16, b: i16, c: i16 ) -> TestResult { + let (a, b, c) = (a as isize, b as isize, c as isize); + if a == 0 || b == 0 { TestResult::discard() } else { @@ -953,9 +960,12 @@ mod test { } } + // FIXME: This test can't handle larger values at the moment fn solve_linear_diophantine_eq_correct_solution( - a: isize, b: isize, c: isize, t: isize + a: i16, b: i16, c: i8, t: i8 ) -> TestResult { + let (a, b, c, t) = (a as isize, b as isize, c as isize, t as isize); + if a == 0 || b == 0 { TestResult::discard() } else { @@ -972,17 +982,23 @@ mod test { } quickcheck! { + // FIXME: This test is extremely slow, even with i16 values, investigate fn arith_seq_intersect_correct( - first1: isize, len1: isize, step1: isize, - first2: isize, len2: isize, step2: isize + first1: i8, len1: i8, step1: i8, + first2: i8, len2: i8, step2: i8 ) -> TestResult { use std::cmp; + let (len1, len2) = (len1 as isize, len2 as isize); + let (first1, step1) = (first1 as isize, step1 as isize); + let (first2, step2) = (first2 as isize, step2 as isize); + if len1 == 0 || len2 == 0 { // This case is impossible to reach in `arith_seq_intersect()` // because the `min*` and `max*` arguments are inclusive. return TestResult::discard(); } + let len1 = len1.abs(); let len2 = len2.abs();