diff --git a/src/distribution/bernoulli.rs b/src/distribution/bernoulli.rs index 21e3e27f..d6283761 100644 --- a/src/distribution/bernoulli.rs +++ b/src/distribution/bernoulli.rs @@ -272,9 +272,9 @@ impl Discrete for Bernoulli { #[rustfmt::skip] #[cfg(test)] -mod testing { +mod test { use super::*; - use crate::testing_boiler; + use crate::distribution::internal::testing_boiler; testing_boiler!(p: f64; Bernoulli; BinomialError); diff --git a/src/distribution/beta.rs b/src/distribution/beta.rs index 32fae678..7a98ed4b 100644 --- a/src/distribution/beta.rs +++ b/src/distribution/beta.rs @@ -384,14 +384,12 @@ impl Continuous for Beta { } } -#[rustfmt::skip] #[cfg(test)] mod tests { use super::*; - use super::super::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; - testing_boiler!(a: f64, b: f64; Beta; BetaError); + crate::distribution::internal::testing_boiler!(a: f64, b: f64; Beta; BetaError); #[test] fn test_create() { @@ -506,7 +504,7 @@ mod tests { ((5.0, 100.0), 0.0, 0.0), ((5.0, 100.0), 0.5, 4.534102298350337661e-23), ((5.0, 100.0), 1.0, 0.0), - ((5.0, 100.0), 1.0, 0.0) + ((5.0, 100.0), 1.0, 0.0), ]; for ((a, b), x, expect) in test { test_relative(a, b, expect, f(x)); @@ -611,8 +609,8 @@ mod tests { ((5.0, 100.0), 1.0, 1.0), ]; for ((a, b), x, expect) in test { - test_relative(a, b, expect, func(x)); - }; + test_relative(a, b, expect, func(x)); + } } #[test] @@ -641,7 +639,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1.2, 3.4), 0.0, 1.0); - test::check_continuous_distribution(&create_ok(4.5, 6.7), 0.0, 1.0); + density_util::check_continuous_distribution(&create_ok(1.2, 3.4), 0.0, 1.0); + density_util::check_continuous_distribution(&create_ok(4.5, 6.7), 0.0, 1.0); } } diff --git a/src/distribution/binomial.rs b/src/distribution/binomial.rs index fe716334..1555511b 100644 --- a/src/distribution/binomial.rs +++ b/src/distribution/binomial.rs @@ -357,10 +357,8 @@ impl Discrete for Binomial { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - - testing_boiler!(p: f64, n: u64; Binomial; BinomialError); + use crate::distribution::internal::density_util; + crate::distribution::internal::testing_boiler!(p: f64, n: u64; Binomial; BinomialError); #[test] fn test_create() { @@ -580,7 +578,7 @@ mod tests { #[test] fn test_discrete() { - test::check_discrete_distribution(&create_ok(0.3, 5), 5); - test::check_discrete_distribution(&create_ok(0.7, 10), 10); + density_util::check_discrete_distribution(&create_ok(0.3, 5), 5); + density_util::check_discrete_distribution(&create_ok(0.7, 10), 10); } } diff --git a/src/distribution/categorical.rs b/src/distribution/categorical.rs index c213a818..c9abfd6a 100644 --- a/src/distribution/categorical.rs +++ b/src/distribution/categorical.rs @@ -410,8 +410,8 @@ fn test_binary_index() { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(prob_mass: &[f64]; Categorical; CategoricalError); @@ -575,7 +575,7 @@ mod tests { #[test] fn test_discrete() { - test::check_discrete_distribution(&create_ok(&[1.0, 2.0, 3.0, 4.0]), 4); - test::check_discrete_distribution(&create_ok(&[0.0, 1.0, 2.0, 3.0, 4.0]), 5); + density_util::check_discrete_distribution(&create_ok(&[1.0, 2.0, 3.0, 4.0]), 4); + density_util::check_discrete_distribution(&create_ok(&[0.0, 1.0, 2.0, 3.0, 4.0]), 5); } } diff --git a/src/distribution/cauchy.rs b/src/distribution/cauchy.rs index 7353f02d..1bee3d77 100644 --- a/src/distribution/cauchy.rs +++ b/src/distribution/cauchy.rs @@ -280,10 +280,8 @@ impl Continuous for Cauchy { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - - testing_boiler!(location: f64, scale: f64; Cauchy; CauchyError); + use crate::distribution::internal::density_util; + crate::distribution::internal::testing_boiler!(location: f64, scale: f64; Cauchy; CauchyError); #[test] fn test_create() { @@ -513,7 +511,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(-1.2, 3.4), -1500.0, 1500.0); - test::check_continuous_distribution(&create_ok(-4.5, 6.7), -5000.0, 5000.0); + density_util::check_continuous_distribution(&create_ok(-1.2, 3.4), -1500.0, 1500.0); + density_util::check_continuous_distribution(&create_ok(-4.5, 6.7), -5000.0, 5000.0); } } diff --git a/src/distribution/chi.rs b/src/distribution/chi.rs index bf39a3ff..4eaf284b 100644 --- a/src/distribution/chi.rs +++ b/src/distribution/chi.rs @@ -338,10 +338,8 @@ impl Continuous for Chi { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - - testing_boiler!(freedom: u64; Chi; ChiError); + use crate::distribution::internal::density_util; + crate::distribution::internal::testing_boiler!(freedom: u64; Chi; ChiError); #[test] fn test_create() { @@ -510,8 +508,8 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(2), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(5), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(1), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(2), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(5), 0.0, 10.0); } } diff --git a/src/distribution/chi_squared.rs b/src/distribution/chi_squared.rs index e0cd1d41..2c650176 100644 --- a/src/distribution/chi_squared.rs +++ b/src/distribution/chi_squared.rs @@ -307,10 +307,8 @@ impl Continuous for ChiSquared { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - - testing_boiler!(freedom: f64; ChiSquared; GammaError); + use crate::distribution::internal::density_util; + crate::distribution::internal::testing_boiler!(freedom: f64; ChiSquared; GammaError); #[test] fn test_median() { @@ -325,8 +323,8 @@ mod tests { #[test] fn test_continuous() { // TODO: figure out why this test fails: - //test::check_continuous_distribution(&create_ok(1.0), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(2.0), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(5.0), 0.0, 50.0); + //check_continuous_distribution(&create_ok(1.0), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(2.0), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(5.0), 0.0, 50.0); } } diff --git a/src/distribution/dirac.rs b/src/distribution/dirac.rs index 8bd782f6..8c8d8fbe 100644 --- a/src/distribution/dirac.rs +++ b/src/distribution/dirac.rs @@ -213,7 +213,7 @@ impl Mode> for Dirac { #[cfg(test)] mod tests { use super::*; - use crate::testing_boiler; + use crate::distribution::internal::testing_boiler; testing_boiler!(v: f64; Dirac; DiracError); diff --git a/src/distribution/discrete_uniform.rs b/src/distribution/discrete_uniform.rs index b610b735..53f1f630 100644 --- a/src/distribution/discrete_uniform.rs +++ b/src/distribution/discrete_uniform.rs @@ -284,7 +284,7 @@ impl Discrete for DiscreteUniform { #[cfg(test)] mod tests { use super::*; - use crate::testing_boiler; + use crate::distribution::internal::testing_boiler; testing_boiler!(min: i64, max: i64; DiscreteUniform; DiscreteUniformError); diff --git a/src/distribution/erlang.rs b/src/distribution/erlang.rs index 74ef9536..0f6a4267 100644 --- a/src/distribution/erlang.rs +++ b/src/distribution/erlang.rs @@ -294,9 +294,8 @@ impl Continuous for Erlang { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(shape: u64, rate: f64; Erlang; GammaError); #[test] @@ -324,8 +323,8 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1, 2.5), 0.0, 20.0); - test::check_continuous_distribution(&create_ok(2, 1.5), 0.0, 20.0); - test::check_continuous_distribution(&create_ok(3, 0.5), 0.0, 20.0); + density_util::check_continuous_distribution(&create_ok(1, 2.5), 0.0, 20.0); + density_util::check_continuous_distribution(&create_ok(2, 1.5), 0.0, 20.0); + density_util::check_continuous_distribution(&create_ok(3, 0.5), 0.0, 20.0); } } diff --git a/src/distribution/exponential.rs b/src/distribution/exponential.rs index 556812a5..d99a23c0 100644 --- a/src/distribution/exponential.rs +++ b/src/distribution/exponential.rs @@ -301,8 +301,8 @@ impl Continuous for Exp { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(rate: f64; Exp; ExpError); @@ -504,8 +504,8 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(0.5), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(1.5), 0.0, 20.0); - test::check_continuous_distribution(&create_ok(2.5), 0.0, 50.0); + density_util::check_continuous_distribution(&create_ok(0.5), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(1.5), 0.0, 20.0); + density_util::check_continuous_distribution(&create_ok(2.5), 0.0, 50.0); } } diff --git a/src/distribution/fisher_snedecor.rs b/src/distribution/fisher_snedecor.rs index ae62abc4..8b1765a9 100644 --- a/src/distribution/fisher_snedecor.rs +++ b/src/distribution/fisher_snedecor.rs @@ -416,8 +416,8 @@ impl Continuous for FisherSnedecor { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(freedom_1: f64, freedom_2: f64; FisherSnedecor; FisherSnedecorError); @@ -620,6 +620,6 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(10.0, 10.0), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(10.0, 10.0), 0.0, 10.0); } } diff --git a/src/distribution/gamma.rs b/src/distribution/gamma.rs index 92a6ff22..77c0b38b 100644 --- a/src/distribution/gamma.rs +++ b/src/distribution/gamma.rs @@ -438,8 +438,8 @@ pub fn sample_unchecked(rng: &mut R, shape: f64, rate: #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(shape: f64, rate: f64; Gamma; GammaError); @@ -708,7 +708,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1.0, 0.5), 0.0, 20.0); - test::check_continuous_distribution(&create_ok(9.0, 2.0), 0.0, 20.0); + density_util::check_continuous_distribution(&create_ok(1.0, 0.5), 0.0, 20.0); + density_util::check_continuous_distribution(&create_ok(9.0, 2.0), 0.0, 20.0); } } diff --git a/src/distribution/geometric.rs b/src/distribution/geometric.rs index 21808450..c516bd91 100644 --- a/src/distribution/geometric.rs +++ b/src/distribution/geometric.rs @@ -304,11 +304,10 @@ impl Discrete for Geometric { #[cfg(test)] mod tests { use super::*; + use crate::distribution::internal::density_util; use crate::prec; - use crate::distribution::internal::*; - use crate::testing_boiler; - testing_boiler!(p: f64; Geometric; GeometricError); + crate::distribution::internal::testing_boiler!(p: f64; Geometric; GeometricError); #[test] fn test_create() { @@ -508,8 +507,8 @@ mod tests { #[test] fn test_discrete() { - test::check_discrete_distribution(&create_ok(0.3), 100); - test::check_discrete_distribution(&create_ok(0.6), 100); - test::check_discrete_distribution(&create_ok(1.0), 1); + density_util::check_discrete_distribution(&create_ok(0.3), 100); + density_util::check_discrete_distribution(&create_ok(0.6), 100); + density_util::check_discrete_distribution(&create_ok(1.0), 1); } } diff --git a/src/distribution/gumbel.rs b/src/distribution/gumbel.rs index ddd17e4e..d6662404 100644 --- a/src/distribution/gumbel.rs +++ b/src/distribution/gumbel.rs @@ -339,7 +339,7 @@ impl Continuous for Gumbel { #[cfg(test)] mod tests { use super::*; - use crate::testing_boiler; + use crate::distribution::internal::testing_boiler; testing_boiler!(location: f64, scale: f64; Gumbel; GumbelError); diff --git a/src/distribution/hypergeometric.rs b/src/distribution/hypergeometric.rs index e941512b..602a411e 100644 --- a/src/distribution/hypergeometric.rs +++ b/src/distribution/hypergeometric.rs @@ -424,8 +424,8 @@ impl Discrete for Hypergeometric { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(population: u64, successes: u64, draws: u64; Hypergeometric; HypergeometricError); @@ -596,7 +596,7 @@ mod tests { #[test] fn test_discrete() { - test::check_discrete_distribution(&create_ok(5, 4, 3), 4); - test::check_discrete_distribution(&create_ok(3, 2, 1), 2); + density_util::check_discrete_distribution(&create_ok(5, 4, 3), 4); + density_util::check_discrete_distribution(&create_ok(3, 2, 1), 2); } } diff --git a/src/distribution/internal.rs b/src/distribution/internal.rs index 868871d9..5466cdbf 100644 --- a/src/distribution/internal.rs +++ b/src/distribution/internal.rs @@ -37,315 +37,217 @@ pub fn integral_bisection_search( } } -#[macro_use] #[cfg(test)] -pub mod test { - use super::*; - use crate::distribution::{Continuous, ContinuousCDF, Discrete, DiscreteCDF}; - use crate::prec; - - #[macro_export] - macro_rules! testing_boiler { - ($($arg_name:ident: $arg_ty:ty),+; $dist:ty; $dist_err:ty) => { - fn make_param_text($($arg_name: $arg_ty),+) -> String { - // "" - let mut param_text = String::new(); - - // "shape=10.0, rate=NaN, " - $( - param_text.push_str( - &format!( - "{}={:?}, ", - stringify!($arg_name), - $arg_name, - ) - ); - )+ - - // "shape=10.0, rate=NaN" (removes trailing comma and whitespace) - param_text.pop(); - param_text.pop(); - - param_text - } - - /// Creates and returns a distribution with the given parameters, - /// panicking if `::new` fails. - fn create_ok($($arg_name: $arg_ty),+) -> $dist { - match <$dist>::new($($arg_name),+) { - Ok(d) => d, - Err(e) => panic!( - "{}::new was expected to succeed, but failed for {} with error: '{}'", - stringify!($dist), - make_param_text($($arg_name),+), - e - ) - } - } - - /// Returns the error when creating a distribution with the given parameters, - /// panicking if `::new` succeeds. - #[allow(dead_code)] - fn create_err($($arg_name: $arg_ty),+) -> $dist_err { - match <$dist>::new($($arg_name),+) { - Err(e) => e, - Ok(d) => panic!( - "{}::new was expected to fail, but succeeded for {} with result: {:?}", - stringify!($dist), - make_param_text($($arg_name),+), - d - ) - } - } - - /// Creates a distribution with the given parameters, calls the `get_fn` - /// function with the new distribution and returns the result of `get_fn`. - /// - /// Panics if `::new` fails. - fn create_and_get($($arg_name: $arg_ty),+, get_fn: F) -> T - where - F: Fn($dist) -> T, - { - let n = create_ok($($arg_name),+); - get_fn(n) - } - - /// Creates a distribution with the given parameters, calls the `get_fn` - /// function with the new distribution and compares the result of `get_fn` - /// to `expected` exactly. - /// - /// Panics if `::new` fails. - #[allow(dead_code)] - fn test_exact($($arg_name: $arg_ty),+, expected: T, get_fn: F) - where - F: Fn($dist) -> T, - T: ::core::cmp::PartialEq + ::core::fmt::Debug - { - let x = create_and_get($($arg_name),+, get_fn); - if x != expected { - panic!( - "Expected {:?}, got {:?} for {}", - expected, - x, - make_param_text($($arg_name),+) - ); - } - } - - /// Gets a value for the given parameters by calling `create_and_get` - /// and compares it to `expected`. - /// - /// Allows relative error of up to [`crate::prec::DEFAULT_RELATIVE_ACC`]. - /// - /// Panics if `::new` fails. - #[allow(dead_code)] - fn test_relative($($arg_name: $arg_ty),+, expected: f64, get_fn: F) - where - F: Fn($dist) -> f64, - { - let x = create_and_get($($arg_name),+, get_fn); - let max_relative = $crate::prec::DEFAULT_RELATIVE_ACC; - - if !$crate::prec::relative_eq!(expected, x, max_relative = max_relative) { - panic!( - "Expected {:?} to be almost equal to {:?} (max. relative error of {:?}), but wasn't for {}", - x, - expected, - max_relative, - make_param_text($($arg_name),+) - ); - } - } - - /// Gets a value for the given parameters by calling `create_and_get` - /// and compares it to `expected`. - /// - /// Allows absolute error of up to `acc`. - /// - /// Panics if `::new` fails. - #[allow(dead_code)] - fn test_absolute($($arg_name: $arg_ty),+, expected: f64, acc: f64, get_fn: F) - where - F: Fn($dist) -> f64, - { - let x = create_and_get($($arg_name),+, get_fn); - - // abs_diff_eq! cannot handle infinities, so we manually accept them here - if expected.is_infinite() && x == expected { - return; - } - - if !$crate::prec::abs_diff_eq!(expected, x, epsilon = acc) { - panic!( - "Expected {:?} to be almost equal to {:?} (max. absolute error of {:?}), but wasn't for {}", - x, - expected, - acc, - make_param_text($($arg_name),+) - ); - } - } - - /// Purposely fails creating a distribution with the given - /// parameters and compares the returned error to `expected`. - /// - /// Panics if `::new` succeeds. - #[allow(dead_code)] - fn test_create_err($($arg_name: $arg_ty),+, expected: $dist_err) - { - let err = create_err($($arg_name),+); - if err != expected { - panic!( - "{}::new was expected to fail with error {:?}, but failed with error {:?} for {}", - stringify!($dist), - expected, - err, - make_param_text($($arg_name),+) - ) - } - } - - /// Gets a value for the given parameters by calling `create_and_get` - /// and asserts that it is [`NAN`]. - /// - /// Panics if `::new` fails. - #[allow(dead_code)] - fn test_is_nan($($arg_name: $arg_ty),+, get_fn: F) - where - F: Fn($dist) -> f64 - { - let x = create_and_get($($arg_name),+, get_fn); - assert!(x.is_nan()); - } - - /// Gets a value for the given parameters by calling `create_and_get` - /// and asserts that it is [`None`]. - /// - /// Panics if `::new` fails. - #[allow(dead_code)] - fn test_none($($arg_name: $arg_ty),+, get_fn: F) - where - F: Fn($dist) -> Option, - T: ::core::fmt::Debug, - { - let x = create_and_get($($arg_name),+, get_fn); - - if let Some(inner) = x { - panic!( - "Expected None, got {:?} for {}", - inner, - make_param_text($($arg_name),+) +macro_rules! testing_boiler { + ($($arg_name:ident: $arg_ty:ty),+; $dist:ty; $dist_err:ty) => { + fn make_param_text($($arg_name: $arg_ty),+) -> String { + // "" + let mut param_text = String::new(); + + // "shape=10.0, rate=NaN, " + $( + param_text.push_str( + &format!( + "{}={:?}, ", + stringify!($arg_name), + $arg_name, ) - } - } + ); + )+ - /// Asserts that associated error type is Send and Sync - #[test] - fn test_error_is_sync_send() { - fn assert_sync_send() {} - assert_sync_send::<$dist_err>(); - } - }; - } + // "shape=10.0, rate=NaN" (removes trailing comma and whitespace) + param_text.pop(); + param_text.pop(); - pub mod boiler_tests { - use crate::distribution::{Beta, BetaError}; - use crate::statistics::*; - - testing_boiler!(shape_a: f64, shape_b: f64; Beta; BetaError); - - #[test] - fn create_ok_success() { - let b = create_ok(0.8, 1.2); - assert_eq!(b.shape_a(), 0.8); - assert_eq!(b.shape_b(), 1.2); + param_text } - #[test] - #[should_panic] - fn create_err_failure() { - create_err(0.8, 1.2); - } - - #[test] - fn create_err_success() { - let err = create_err(-0.5, 1.2); - assert_eq!(err, BetaError::ShapeAInvalid); + /// Creates and returns a distribution with the given parameters, + /// panicking if `::new` fails. + fn create_ok($($arg_name: $arg_ty),+) -> $dist { + match <$dist>::new($($arg_name),+) { + Ok(d) => d, + Err(e) => panic!( + "{}::new was expected to succeed, but failed for {} with error: '{}'", + stringify!($dist), + make_param_text($($arg_name),+), + e + ) + } } - #[test] - #[should_panic] - fn create_ok_failure() { - create_ok(-0.5, 1.2); + /// Returns the error when creating a distribution with the given parameters, + /// panicking if `::new` succeeds. + #[allow(dead_code)] + fn create_err($($arg_name: $arg_ty),+) -> $dist_err { + match <$dist>::new($($arg_name),+) { + Err(e) => e, + Ok(d) => panic!( + "{}::new was expected to fail, but succeeded for {} with result: {:?}", + stringify!($dist), + make_param_text($($arg_name),+), + d + ) + } } - #[test] - fn test_exact_success() { - test_exact(1.5, 1.5, 0.5, |dist| dist.mode().unwrap()); + /// Creates a distribution with the given parameters, calls the `get_fn` + /// function with the new distribution and returns the result of `get_fn`. + /// + /// Panics if `::new` fails. + fn create_and_get($($arg_name: $arg_ty),+, get_fn: F) -> T + where + F: Fn($dist) -> T, + { + let n = create_ok($($arg_name),+); + get_fn(n) } - #[test] - #[should_panic] - fn test_exact_failure() { - test_exact(1.2, 1.4, 0.333333333333, |dist| dist.mode().unwrap()); + /// Creates a distribution with the given parameters, calls the `get_fn` + /// function with the new distribution and compares the result of `get_fn` + /// to `expected` exactly. + /// + /// Panics if `::new` fails. + #[allow(dead_code)] + fn test_exact($($arg_name: $arg_ty),+, expected: T, get_fn: F) + where + F: Fn($dist) -> T, + T: ::core::cmp::PartialEq + ::core::fmt::Debug + { + let x = create_and_get($($arg_name),+, get_fn); + if x != expected { + panic!( + "Expected {:?}, got {:?} for {}", + expected, + x, + make_param_text($($arg_name),+) + ); + } } - #[test] - fn test_relative_success() { - test_relative(1.2, 1.4, 0.333333333333, |dist| dist.mode().unwrap()); + /// Gets a value for the given parameters by calling `create_and_get` + /// and compares it to `expected`. + /// + /// Allows relative error of up to [`crate::prec::DEFAULT_RELATIVE_ACC`]. + /// + /// Panics if `::new` fails. + #[allow(dead_code)] + fn test_relative($($arg_name: $arg_ty),+, expected: f64, get_fn: F) + where + F: Fn($dist) -> f64, + { + let x = create_and_get($($arg_name),+, get_fn); + let max_relative = $crate::prec::DEFAULT_RELATIVE_ACC; + + if !$crate::prec::relative_eq!(expected, x, max_relative = max_relative) { + panic!( + "Expected {:?} to be almost equal to {:?} (max. relative error of {:?}), but wasn't for {}", + x, + expected, + max_relative, + make_param_text($($arg_name),+) + ); + } } - #[test] - #[should_panic] - fn test_relative_failure() { - test_relative(1.2, 1.4, 0.333, |dist| dist.mode().unwrap()); - } + /// Gets a value for the given parameters by calling `create_and_get` + /// and compares it to `expected`. + /// + /// Allows absolute error of up to `acc`. + /// + /// Panics if `::new` fails. + #[allow(dead_code)] + fn test_absolute($($arg_name: $arg_ty),+, expected: f64, acc: f64, get_fn: F) + where + F: Fn($dist) -> f64, + { + let x = create_and_get($($arg_name),+, get_fn); - #[test] - fn test_absolute_success() { - test_absolute(1.2, 1.4, 0.333333333333, 1e-12, |dist| dist.mode().unwrap()); - } + // abs_diff_eq! cannot handle infinities, so we manually accept them here + if expected.is_infinite() && x == expected { + return; + } - #[test] - #[should_panic] - fn test_absolute_failure() { - test_absolute(1.2, 1.4, 0.333333333333, 1e-15, |dist| dist.mode().unwrap()); + if !$crate::prec::abs_diff_eq!(expected, x, epsilon = acc) { + panic!( + "Expected {:?} to be almost equal to {:?} (max. absolute error of {:?}), but wasn't for {}", + x, + expected, + acc, + make_param_text($($arg_name),+) + ); + } } - #[test] - fn test_create_err_success() { - test_create_err(0.0, 0.5, BetaError::ShapeAInvalid); + /// Purposely fails creating a distribution with the given + /// parameters and compares the returned error to `expected`. + /// + /// Panics if `::new` succeeds. + #[allow(dead_code)] + fn test_create_err($($arg_name: $arg_ty),+, expected: $dist_err) + { + let err = create_err($($arg_name),+); + if err != expected { + panic!( + "{}::new was expected to fail with error {:?}, but failed with error {:?} for {}", + stringify!($dist), + expected, + err, + make_param_text($($arg_name),+) + ) + } } - #[test] - #[should_panic] - fn test_create_err_failure() { - test_create_err(0.0, 0.5, BetaError::ShapeBInvalid); + /// Gets a value for the given parameters by calling `create_and_get` + /// and asserts that it is [`NAN`]. + /// + /// Panics if `::new` fails. + #[allow(dead_code)] + fn test_is_nan($($arg_name: $arg_ty),+, get_fn: F) + where + F: Fn($dist) -> f64 + { + let x = create_and_get($($arg_name),+, get_fn); + assert!(x.is_nan()); } - #[test] - fn test_is_nan_success() { - // Not sure that any Beta API can return a NaN, so we force the issue - test_is_nan(0.8, 1.2, |_| f64::NAN); + /// Gets a value for the given parameters by calling `create_and_get` + /// and asserts that it is [`None`]. + /// + /// Panics if `::new` fails. + #[allow(dead_code)] + fn test_none($($arg_name: $arg_ty),+, get_fn: F) + where + F: Fn($dist) -> Option, + T: ::core::fmt::Debug, + { + let x = create_and_get($($arg_name),+, get_fn); + + if let Some(inner) = x { + panic!( + "Expected None, got {:?} for {}", + inner, + make_param_text($($arg_name),+) + ) + } } + /// Asserts that associated error type is Send and Sync #[test] - #[should_panic] - fn test_is_nan_failure() { - test_is_nan(0.8, 1.2, |dist| dist.mean().unwrap()); + fn test_error_is_sync_send() { + fn assert_sync_send() {} + assert_sync_send::<$dist_err>(); } + }; +} - #[test] - fn test_is_none_success() { - test_none(0.5, 1.2, |dist| dist.mode()); - } +#[cfg(test)] +pub(super) use testing_boiler; - #[test] - #[should_panic] - fn test_is_none_failure() { - test_none(0.8, 1.2, |dist| dist.mean()); - } - } +#[cfg(test)] +pub mod density_util { + use crate::distribution::{Continuous, ContinuousCDF, Discrete, DiscreteCDF}; + use crate::prec; /// cdf should be the integral of the pdf fn check_integrate_pdf_is_cdf + Continuous>( @@ -492,7 +394,11 @@ pub mod test { check_sum_pmf_is_cdf(dist, x_max); } +} +#[cfg(test)] +mod test { + use super::integral_bisection_search; #[test] fn test_integer_bisection() { fn search(z: usize, data: &[usize]) -> Option { @@ -514,4 +420,102 @@ pub mod test { assert_eq!(infimum, found_element) } } + pub mod boiler_tests { + use crate::distribution::{Beta, BetaError}; + use crate::statistics::*; + + testing_boiler!(shape_a: f64, shape_b: f64; Beta; BetaError); + + #[test] + fn create_ok_success() { + let b = create_ok(0.8, 1.2); + assert_eq!(b.shape_a(), 0.8); + assert_eq!(b.shape_b(), 1.2); + } + + #[test] + #[should_panic] + fn create_err_failure() { + create_err(0.8, 1.2); + } + + #[test] + fn create_err_success() { + let err = create_err(-0.5, 1.2); + assert_eq!(err, BetaError::ShapeAInvalid); + } + + #[test] + #[should_panic] + fn create_ok_failure() { + create_ok(-0.5, 1.2); + } + + #[test] + fn test_exact_success() { + test_exact(1.5, 1.5, 0.5, |dist| dist.mode().unwrap()); + } + + #[test] + #[should_panic] + fn test_exact_failure() { + test_exact(1.2, 1.4, 0.333333333333, |dist| dist.mode().unwrap()); + } + + #[test] + fn test_relative_success() { + test_relative(1.2, 1.4, 0.333333333333, |dist| dist.mode().unwrap()); + } + + #[test] + #[should_panic] + fn test_relative_failure() { + test_relative(1.2, 1.4, 0.333, |dist| dist.mode().unwrap()); + } + + #[test] + fn test_absolute_success() { + test_absolute(1.2, 1.4, 0.333333333333, 1e-12, |dist| dist.mode().unwrap()); + } + + #[test] + #[should_panic] + fn test_absolute_failure() { + test_absolute(1.2, 1.4, 0.333333333333, 1e-15, |dist| dist.mode().unwrap()); + } + + #[test] + fn test_create_err_success() { + test_create_err(0.0, 0.5, BetaError::ShapeAInvalid); + } + + #[test] + #[should_panic] + fn test_create_err_failure() { + test_create_err(0.0, 0.5, BetaError::ShapeBInvalid); + } + + #[test] + fn test_is_nan_success() { + // Not sure that any Beta API can return a NaN, so we force the issue + test_is_nan(0.8, 1.2, |_| f64::NAN); + } + + #[test] + #[should_panic] + fn test_is_nan_failure() { + test_is_nan(0.8, 1.2, |dist| dist.mean().unwrap()); + } + + #[test] + fn test_is_none_success() { + test_none(0.5, 1.2, |dist| dist.mode()); + } + + #[test] + #[should_panic] + fn test_is_none_failure() { + test_none(0.8, 1.2, |dist| dist.mean()); + } + } } diff --git a/src/distribution/inverse_gamma.rs b/src/distribution/inverse_gamma.rs index 471616eb..af98b791 100644 --- a/src/distribution/inverse_gamma.rs +++ b/src/distribution/inverse_gamma.rs @@ -342,8 +342,8 @@ impl Continuous for InverseGamma { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(shape: f64, rate: f64; InverseGamma; InverseGammaError); @@ -468,7 +468,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1.0, 0.5), 0.0, 100.0); - test::check_continuous_distribution(&create_ok(9.0, 2.0), 0.0, 100.0); + density_util::check_continuous_distribution(&create_ok(1.0, 0.5), 0.0, 100.0); + density_util::check_continuous_distribution(&create_ok(9.0, 2.0), 0.0, 100.0); } } diff --git a/src/distribution/laplace.rs b/src/distribution/laplace.rs index 355d600d..64b6eda1 100644 --- a/src/distribution/laplace.rs +++ b/src/distribution/laplace.rs @@ -330,7 +330,7 @@ mod tests { use super::*; use crate::prec; - use crate::testing_boiler; + use crate::distribution::internal::testing_boiler; testing_boiler!(location: f64, scale: f64; Laplace; LaplaceError); diff --git a/src/distribution/levy.rs b/src/distribution/levy.rs index 5e061bce..2f5758f8 100644 --- a/src/distribution/levy.rs +++ b/src/distribution/levy.rs @@ -335,13 +335,10 @@ impl Continuous for Levy { #[rustfmt::skip] #[cfg(test)] mod tests { - use core::f64; - use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - - testing_boiler!(mu: f64, c: f64; Levy; LevyError); + use core::f64; + use crate::distribution::internal::density_util; + crate::distribution::internal::testing_boiler!(mu: f64, c: f64; Levy; LevyError); #[test] fn test_create() { @@ -712,32 +709,32 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution( + density_util::check_continuous_distribution( &create_ok(1.0, 0.05), 1.0, 319.2932192553111008237465284764766693115234375, ); - test::check_continuous_distribution( + density_util::check_continuous_distribution( &create_ok(3.0, 0.05), 3.0, 321.2932192553111008237465284764766693115234375, ); - test::check_continuous_distribution( + density_util::check_continuous_distribution( &create_ok(3.0, 0.05), 3.0, 321.2932192553111008237465284764766693115234375, ); - test::check_continuous_distribution( + density_util::check_continuous_distribution( &create_ok(1.0, 0.05), 1.0, 319.2932192553111008237465284764766693115234375, ); - test::check_continuous_distribution( + density_util::check_continuous_distribution( &create_ok(10.0, 0.05), 10.0, 328.2932192553111008237465284764766693115234375, ); - test::check_continuous_distribution( + density_util::check_continuous_distribution( &create_ok(10.0, 0.05), 10.0, 328.2932192553111008237465284764766693115234375, diff --git a/src/distribution/log_normal.rs b/src/distribution/log_normal.rs index 1ba8c41d..e033b6f7 100644 --- a/src/distribution/log_normal.rs +++ b/src/distribution/log_normal.rs @@ -334,8 +334,8 @@ impl Continuous for LogNormal { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(location: f64, scale: f64; LogNormal; LogNormalError); @@ -745,7 +745,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(0.0, 0.25), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(0.0, 0.5), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(0.0, 0.25), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(0.0, 0.5), 0.0, 10.0); } } diff --git a/src/distribution/negative_binomial.rs b/src/distribution/negative_binomial.rs index 1ca52b61..6c143c1a 100644 --- a/src/distribution/negative_binomial.rs +++ b/src/distribution/negative_binomial.rs @@ -321,8 +321,8 @@ impl Discrete for NegativeBinomial { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::test; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(r: f64, p: f64; NegativeBinomial; NegativeBinomialError); @@ -478,8 +478,8 @@ mod tests { #[test] fn test_discrete() { - test::check_discrete_distribution(&create_ok(5.0, 0.3), 35); - test::check_discrete_distribution(&create_ok(10.0, 0.7), 21); + density_util::check_discrete_distribution(&create_ok(5.0, 0.3), 35); + density_util::check_discrete_distribution(&create_ok(10.0, 0.7), 21); } #[test] diff --git a/src/distribution/normal.rs b/src/distribution/normal.rs index e2303ed5..7fc336ca 100644 --- a/src/distribution/normal.rs +++ b/src/distribution/normal.rs @@ -370,10 +370,8 @@ impl std::default::Default for Normal { mod tests { use super::*; use crate::prec; - use crate::distribution::internal::*; - use crate::testing_boiler; - - testing_boiler!(mean: f64, std_dev: f64; Normal; NormalError); + use crate::distribution::internal::density_util; + crate::distribution::internal::testing_boiler!(mean: f64, std_dev: f64; Normal; NormalError); #[test] fn test_create() { @@ -536,8 +534,8 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(0.0, 1.0), -10.0, 10.0); - test::check_continuous_distribution(&create_ok(20.0, 0.5), 10.0, 30.0); + density_util::check_continuous_distribution(&create_ok(0.0, 1.0), -10.0, 10.0); + density_util::check_continuous_distribution(&create_ok(20.0, 0.5), 10.0, 30.0); } #[test] diff --git a/src/distribution/pareto.rs b/src/distribution/pareto.rs index 11a816ab..94620be8 100644 --- a/src/distribution/pareto.rs +++ b/src/distribution/pareto.rs @@ -382,10 +382,9 @@ impl Continuous for Pareto { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; - testing_boiler!(scale: f64, shape: f64; Pareto; ParetoError); + crate::distribution::internal::testing_boiler!(scale: f64, shape: f64; Pareto; ParetoError); #[test] fn test_create() { @@ -547,7 +546,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1.0, 10.0), 1.0, 10.0); - test::check_continuous_distribution(&create_ok(0.1, 2.0), 0.1, 100.0); + density_util::check_continuous_distribution(&create_ok(1.0, 10.0), 1.0, 10.0); + density_util::check_continuous_distribution(&create_ok(0.1, 2.0), 0.1, 100.0); } } diff --git a/src/distribution/poisson.rs b/src/distribution/poisson.rs index e3751606..81bd54f3 100644 --- a/src/distribution/poisson.rs +++ b/src/distribution/poisson.rs @@ -340,9 +340,8 @@ pub fn sample_unchecked(rng: &mut R, lambda: f64) -> f6 #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; - + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(lambda: f64; Poisson; PoissonError); #[test] @@ -477,7 +476,7 @@ mod tests { #[test] fn test_discrete() { - test::check_discrete_distribution(&create_ok(0.3), 10); - test::check_discrete_distribution(&create_ok(4.5), 30); + density_util::check_discrete_distribution(&create_ok(0.3), 10); + density_util::check_discrete_distribution(&create_ok(4.5), 30); } } diff --git a/src/distribution/students_t.rs b/src/distribution/students_t.rs index 493097ed..27d579cb 100644 --- a/src/distribution/students_t.rs +++ b/src/distribution/students_t.rs @@ -458,11 +458,10 @@ impl Continuous for StudentsT { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; + use crate::distribution::internal::density_util; use crate::prec; - use crate::testing_boiler; - testing_boiler!(location: f64, scale: f64, freedom: f64; StudentsT; StudentsTError); + crate::distribution::internal::testing_boiler!(location: f64, scale: f64, freedom: f64; StudentsT; StudentsTError); #[test] fn test_create() { @@ -662,15 +661,14 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(0.0, 1.0, 3.0), -30.0, 30.0); - test::check_continuous_distribution(&create_ok(0.0, 1.0, 10.0), -10.0, 10.0); - test::check_continuous_distribution(&create_ok(20.0, 0.5, 10.0), 10.0, 30.0); + density_util::check_continuous_distribution(&create_ok(0.0, 1.0, 3.0), -30.0, 30.0); + density_util::check_continuous_distribution(&create_ok(0.0, 1.0, 10.0), -10.0, 10.0); + density_util::check_continuous_distribution(&create_ok(20.0, 0.5, 10.0), 10.0, 30.0); } #[test] fn test_inv_cdf() { let test = |x: f64, freedom: f64, expected: f64| { - use crate::prec; let d = StudentsT::new(0., 1., freedom).unwrap(); // Checks that left == right to 4 significant figures, unlike // test_almost() which uses decimal places diff --git a/src/distribution/triangular.rs b/src/distribution/triangular.rs index 6be868bb..c698164f 100644 --- a/src/distribution/triangular.rs +++ b/src/distribution/triangular.rs @@ -398,8 +398,8 @@ fn sample_unchecked(rng: &mut R, min: f64, max: f64, mo #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(min: f64, max: f64, mode: f64; Triangular; TriangularError); @@ -599,7 +599,7 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(-5.0, 5.0, 0.0), -5.0, 5.0); - test::check_continuous_distribution(&create_ok(-15.0, -2.0, -3.0), -15.0, -2.0); + density_util::check_continuous_distribution(&create_ok(-5.0, 5.0, 0.0), -5.0, 5.0); + density_util::check_continuous_distribution(&create_ok(-15.0, -2.0, -3.0), -15.0, -2.0); } } diff --git a/src/distribution/uniform.rs b/src/distribution/uniform.rs index 99d93975..84583ea2 100644 --- a/src/distribution/uniform.rs +++ b/src/distribution/uniform.rs @@ -317,8 +317,8 @@ impl Continuous for Uniform { mod tests { use super::*; use crate::prec; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(min: f64, max: f64; Uniform; UniformError); @@ -492,8 +492,8 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(0.0, 10.0), 0.0, 10.0); - test::check_continuous_distribution(&create_ok(-2.0, 15.0), -2.0, 15.0); + density_util::check_continuous_distribution(&create_ok(0.0, 10.0), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(-2.0, 15.0), -2.0, 15.0); } #[cfg(feature = "rand")] diff --git a/src/distribution/weibull.rs b/src/distribution/weibull.rs index 206de92c..44393fad 100644 --- a/src/distribution/weibull.rs +++ b/src/distribution/weibull.rs @@ -379,8 +379,8 @@ impl Continuous for Weibull { #[cfg(test)] mod tests { use super::*; - use crate::distribution::internal::*; - use crate::testing_boiler; + use crate::distribution::internal::density_util; + use crate::distribution::internal::testing_boiler; testing_boiler!(shape: f64, scale: f64; Weibull; WeibullError); @@ -552,6 +552,6 @@ mod tests { #[test] fn test_continuous() { - test::check_continuous_distribution(&create_ok(1.0, 0.2), 0.0, 10.0); + density_util::check_continuous_distribution(&create_ok(1.0, 0.2), 0.0, 10.0); } }