From 8964eb9887cbfea4bc9efec78721276189dcf053 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 26 Feb 2018 22:13:25 -0800 Subject: [PATCH] Chop the tests up The test modules were getting huge, and some of its functions were actually a huge amount of code due to macros, causing tests to take a long time just to compile. They are now separated into a few different tests, and the scalar macros especially are now expanded more sparingly in just a few `check()` functions. Test compile times for me went from about 25 seconds to 1.5s in debug mode, and from 300 seconds (!) to about 8s in release mode. --- .gitignore | 2 + src/bigint.rs | 54 +++++- src/biguint.rs | 33 +++- src/lib.rs | 12 -- {src/tests => tests}/bigint.rs | 331 +++----------------------------- tests/bigint_scalar.rs | 146 ++++++++++++++ {src/tests => tests}/biguint.rs | 311 +++--------------------------- tests/biguint_scalar.rs | 103 ++++++++++ tests/consts/mod.rs | 65 +++++++ tests/macros/mod.rs | 53 +++++ tests/rand.rs | 112 +++++++++++ tests/torture.rs | 45 +++++ 12 files changed, 657 insertions(+), 610 deletions(-) rename {src/tests => tests}/bigint.rs (74%) create mode 100644 tests/bigint_scalar.rs rename {src/tests => tests}/biguint.rs (83%) create mode 100644 tests/biguint_scalar.rs create mode 100644 tests/consts/mod.rs create mode 100644 tests/macros/mod.rs create mode 100644 tests/rand.rs create mode 100644 tests/torture.rs diff --git a/.gitignore b/.gitignore index fa8d85a..6809567 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ Cargo.lock target +*.bk +*.orig diff --git a/src/bigint.rs b/src/bigint.rs index b820ffc..cdd6800 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -32,10 +32,6 @@ use biguint::BigUint; use UsizePromotion; use IsizePromotion; -#[cfg(test)] -#[path = "tests/bigint.rs"] -mod bigint_tests; - /// A Sign is a `BigInt`'s composing element. #[derive(PartialEq, PartialOrd, Eq, Ord, Copy, Clone, Debug, Hash)] pub enum Sign { @@ -1812,3 +1808,53 @@ fn twos_complement<'a, I>(digits: I) } } } + + +#[test] +fn test_from_biguint() { + fn check(inp_s: Sign, inp_n: usize, ans_s: Sign, ans_n: usize) { + let inp = BigInt::from_biguint(inp_s, FromPrimitive::from_usize(inp_n).unwrap()); + let ans = BigInt { + sign: ans_s, + data: FromPrimitive::from_usize(ans_n).unwrap(), + }; + assert_eq!(inp, ans); + } + check(Plus, 1, Plus, 1); + check(Plus, 0, NoSign, 0); + check(Minus, 1, Minus, 1); + check(NoSign, 1, NoSign, 0); +} + +#[test] +fn test_from_slice() { + fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) { + let inp = BigInt::from_slice(inp_s, &[inp_n]); + let ans = BigInt { + sign: ans_s, + data: FromPrimitive::from_u32(ans_n).unwrap(), + }; + assert_eq!(inp, ans); + } + check(Plus, 1, Plus, 1); + check(Plus, 0, NoSign, 0); + check(Minus, 1, Minus, 1); + check(NoSign, 1, NoSign, 0); +} + +#[test] +fn test_assign_from_slice() { + fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) { + let mut inp = BigInt::from_slice(Minus, &[2627_u32, 0_u32, 9182_u32, 42_u32]); + inp.assign_from_slice(inp_s, &[inp_n]); + let ans = BigInt { + sign: ans_s, + data: FromPrimitive::from_u32(ans_n).unwrap(), + }; + assert_eq!(inp, ans); + } + check(Plus, 1, Plus, 1); + check(Plus, 0, NoSign, 0); + check(Minus, 1, Minus, 1); + check(NoSign, 1, NoSign, 0); +} diff --git a/src/biguint.rs b/src/biguint.rs index df60d58..c7b0679 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -38,10 +38,6 @@ use UsizePromotion; use ParseBigIntError; -#[cfg(test)] -#[path = "tests/biguint.rs"] -mod biguint_tests; - /// A big unsigned integer type. /// /// A `BigUint`-typed value `BigUint { data: vec!(a, b, c) }` represents a number @@ -2277,3 +2273,32 @@ fn get_radix_base(radix: u32) -> (BigDigit, usize) { _ => panic!("Invalid bigdigit size") } } + + +#[test] +fn test_from_slice() { + fn check(slice: &[BigDigit], data: &[BigDigit]) { + assert!(BigUint::from_slice(slice).data == data); + } + check(&[1], &[1]); + check(&[0, 0, 0], &[]); + check(&[1, 2, 0, 0], &[1, 2]); + check(&[0, 0, 1, 2], &[0, 0, 1, 2]); + check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); + check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); +} + +#[test] +fn test_assign_from_slice() { + fn check(slice: &[BigDigit], data: &[BigDigit]) { + let mut p = BigUint::from_slice(&[2627_u32, 0_u32, 9182_u32, 42_u32]); + p.assign_from_slice(slice); + assert!(p.data == data); + } + check(&[1], &[1]); + check(&[0, 0, 0], &[]); + check(&[1, 2, 0, 0], &[1, 2]); + check(&[0, 0, 1, 2], &[0, 0, 1, 2]); + check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); + check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); +} diff --git a/src/lib.rs b/src/lib.rs index 6480653..57bbf10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,18 +127,6 @@ impl From for ParseBigIntError { } } -#[cfg(test)] -use std::hash; - -#[cfg(test)] -fn hash(x: &T) -> u64 { - use std::hash::{BuildHasher, Hasher}; - use std::collections::hash_map::RandomState; - let mut hasher = ::Hasher::new(); - x.hash(&mut hasher); - hasher.finish() -} - #[macro_use] mod macros; diff --git a/src/tests/bigint.rs b/tests/bigint.rs similarity index 74% rename from src/tests/bigint.rs rename to tests/bigint.rs index 386c3dd..eae9405 100644 --- a/src/tests/bigint.rs +++ b/tests/bigint.rs @@ -1,6 +1,11 @@ -use {BigDigit, BigUint, big_digit}; -use {Sign, BigInt, RandBigInt, ToBigInt}; -use Sign::{Minus, NoSign, Plus}; +extern crate num_bigint; +extern crate num_integer; +extern crate num_traits; +extern crate rand; + +use num_bigint::{BigDigit, BigUint, big_digit}; +use num_bigint::{BigInt, ToBigInt}; +use num_bigint::Sign::{Minus, NoSign, Plus}; use std::cmp::Ordering::{Less, Equal, Greater}; use std::{f32, f64}; @@ -8,89 +13,17 @@ use std::{i8, i16, i32, i64, isize}; use std::iter::repeat; use std::{u8, u16, u32, u64, usize}; use std::ops::Neg; +use std::hash::{BuildHasher, Hasher, Hash}; +use std::collections::hash_map::RandomState; -use rand::thread_rng; +use num_integer::Integer; +use num_traits::{Zero, One, Signed, ToPrimitive, FromPrimitive, Num, Float}; -use integer::Integer; -use traits::{Zero, One, Signed, ToPrimitive, FromPrimitive, Num, Float}; +mod consts; +use consts::*; -/// Assert that an op works for all val/ref combinations -macro_rules! assert_op { - ($left:ident $op:tt $right:ident == $expected:expr) => { - assert_eq!((&$left) $op (&$right), $expected); - assert_eq!((&$left) $op $right.clone(), $expected); - assert_eq!($left.clone() $op (&$right), $expected); - assert_eq!($left.clone() $op $right.clone(), $expected); - }; -} - -/// Assert that an op works for scalar left or right -macro_rules! assert_scalar_op { - (($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => { - $( - if let Some(left) = $left.$to() { - assert_op!(left $op $right == $expected); - } - if let Some(right) = $right.$to() { - assert_op!($left $op right == $expected); - } - )* - }; - ($left:ident $op:tt $right:ident == $expected:expr) => { - assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, - to_i8, to_i16, to_i32, to_i64, to_isize) - $left $op $right == $expected); - }; -} - -#[test] -fn test_from_biguint() { - fn check(inp_s: Sign, inp_n: usize, ans_s: Sign, ans_n: usize) { - let inp = BigInt::from_biguint(inp_s, FromPrimitive::from_usize(inp_n).unwrap()); - let ans = BigInt { - sign: ans_s, - data: FromPrimitive::from_usize(ans_n).unwrap(), - }; - assert_eq!(inp, ans); - } - check(Plus, 1, Plus, 1); - check(Plus, 0, NoSign, 0); - check(Minus, 1, Minus, 1); - check(NoSign, 1, NoSign, 0); -} - -#[test] -fn test_from_slice() { - fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) { - let inp = BigInt::from_slice(inp_s, &[inp_n]); - let ans = BigInt { - sign: ans_s, - data: FromPrimitive::from_u32(ans_n).unwrap(), - }; - assert_eq!(inp, ans); - } - check(Plus, 1, Plus, 1); - check(Plus, 0, NoSign, 0); - check(Minus, 1, Minus, 1); - check(NoSign, 1, NoSign, 0); -} - -#[test] -fn test_assign_from_slice() { - fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) { - let mut inp = BigInt::from_slice(Minus, &[2627_u32, 0_u32, 9182_u32, 42_u32]); - inp.assign_from_slice(inp_s, &[inp_n]); - let ans = BigInt { - sign: ans_s, - data: FromPrimitive::from_u32(ans_n).unwrap(), - }; - assert_eq!(inp, ans); - } - check(Plus, 1, Plus, 1); - check(Plus, 0, NoSign, 0); - check(Minus, 1, Minus, 1); - check(NoSign, 1, NoSign, 0); -} +#[macro_use] +mod macros; #[test] fn test_from_bytes_be() { @@ -271,11 +204,14 @@ fn test_cmp() { } } +fn hash(x: &T) -> u64 { + let mut hasher = ::Hasher::new(); + x.hash(&mut hasher); + hasher.finish() +} #[test] fn test_hash() { - use hash; - let a = BigInt::new(NoSign, vec![]); let b = BigInt::new(NoSign, vec![0]); let c = BigInt::new(Plus, vec![1]); @@ -569,21 +505,6 @@ fn test_convert_from_biguint() { BigInt::from_slice(Plus, &[1, 2, 3])); } -const N1: BigDigit = -1i32 as BigDigit; -const N2: BigDigit = -2i32 as BigDigit; - -const SUM_TRIPLES: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] = &[(&[], &[], &[]), - (&[], &[1], &[1]), - (&[1], &[1], &[2]), - (&[1], &[1, 1], &[2, 1]), - (&[1], &[N1], &[0, 1]), - (&[1], &[N1, N1], &[0, 0, 1]), - (&[N1, N1], &[N1, N1], &[N2, N1, 1]), - (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), - (&[2, 2, 1], &[N1, N2], &[1, 1, 2])]; - #[test] fn test_add() { for elm in SUM_TRIPLES.iter() { @@ -604,26 +525,6 @@ fn test_add() { } } -#[test] -fn test_scalar_add() { - for elm in SUM_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigInt::from_slice(Plus, a_vec); - let b = BigInt::from_slice(Plus, b_vec); - let c = BigInt::from_slice(Plus, c_vec); - let (na, nb, nc) = (-&a, -&b, -&c); - - assert_scalar_op!(a + b == c); - assert_scalar_op!(b + a == c); - assert_scalar_op!(c + na == b); - assert_scalar_op!(c + nb == a); - assert_scalar_op!(a + nc == nb); - assert_scalar_op!(b + nc == na); - assert_scalar_op!(na + nb == nc); - assert_scalar_op!(a + na == Zero::zero()); - } -} - #[test] fn test_sub() { for elm in SUM_TRIPLES.iter() { @@ -644,63 +545,6 @@ fn test_sub() { } } -#[test] -fn test_scalar_sub() { - for elm in SUM_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigInt::from_slice(Plus, a_vec); - let b = BigInt::from_slice(Plus, b_vec); - let c = BigInt::from_slice(Plus, c_vec); - let (na, nb, nc) = (-&a, -&b, -&c); - - assert_scalar_op!(c - a == b); - assert_scalar_op!(c - b == a); - assert_scalar_op!(nb - a == nc); - assert_scalar_op!(na - b == nc); - assert_scalar_op!(b - na == c); - assert_scalar_op!(a - nb == c); - assert_scalar_op!(nc - na == nb); - assert_scalar_op!(a - a == Zero::zero()); - } -} - -const M: u32 = ::std::u32::MAX; -static MUL_TRIPLES: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] = &[(&[], &[], &[]), - (&[], &[1], &[]), - (&[2], &[], &[]), - (&[1], &[1], &[1]), - (&[2], &[3], &[6]), - (&[1], &[1, 1, 1], &[1, 1, 1]), - (&[1, 2, 3], &[3], &[3, 6, 9]), - (&[1, 1, 1], &[N1], &[N1, N1, N1]), - (&[1, 2, 3], &[N1], &[N1, N2, N2, 2]), - (&[1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]), - (&[N1], &[N1], &[1, N2]), - (&[N1, N1], &[N1], &[1, N1, N2]), - (&[N1, N1, N1], &[N1], &[1, N1, N1, N2]), - (&[N1, N1, N1, N1], &[N1], &[1, N1, N1, N1, N2]), - (&[M / 2 + 1], &[2], &[0, 1]), - (&[0, M / 2 + 1], &[2], &[0, 0, 1]), - (&[1, 2], &[1, 2, 3], &[1, 4, 7, 6]), - (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]), - (&[N1, N1, N1], - &[N1, N1, N1, N1], - &[1, 0, 0, N1, N2, N1, N1]), - (&[0, 0, 1], &[1, 2, 3], &[0, 0, 1, 2, 3]), - (&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1])]; - -static DIV_REM_QUADRUPLES: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] = &[(&[1], &[2], &[], &[1]), - (&[3], &[2], &[1], &[1]), - (&[1, 1], &[2], &[M / 2 + 1], &[1]), - (&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]), - (&[0, 1], &[N1], &[1], &[1]), - (&[N1, N1], &[N2], &[2, 1], &[3])]; - #[test] fn test_mul() { for elm in MUL_TRIPLES.iter() { @@ -730,30 +574,12 @@ fn test_mul() { } } -#[test] -fn test_scalar_mul() { - for elm in MUL_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigInt::from_slice(Plus, a_vec); - let b = BigInt::from_slice(Plus, b_vec); - let c = BigInt::from_slice(Plus, c_vec); - let (na, nb, nc) = (-&a, -&b, -&c); - - assert_scalar_op!(a * b == c); - assert_scalar_op!(b * a == c); - assert_scalar_op!(na * nb == c); - - assert_scalar_op!(na * b == nc); - assert_scalar_op!(nb * a == nc); - } -} - #[test] fn test_div_mod_floor() { fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) { let (d, m) = a.div_mod_floor(b); if !m.is_zero() { - assert_eq!(m.sign, b.sign); + assert_eq!(m.sign(), b.sign()); } assert!(m.abs() <= b.abs()); assert!(*a == b * &d + &m); @@ -809,7 +635,7 @@ fn test_div_rem() { fn check_sub(a: &BigInt, b: &BigInt, ans_q: &BigInt, ans_r: &BigInt) { let (q, r) = a.div_rem(b); if !r.is_zero() { - assert_eq!(r.sign, a.sign); + assert_eq!(r.sign(), a.sign()); } assert!(r.abs() <= b.abs()); assert!(*a == b * &q + &r); @@ -854,65 +680,6 @@ fn test_div_rem() { } } -#[test] -fn test_scalar_div_rem() { - fn check_sub(a: &BigInt, b: BigDigit, ans_q: &BigInt, ans_r: &BigInt) { - let (q, r) = (a / b, a % b); - if !r.is_zero() { - assert_eq!(r.sign, a.sign); - } - assert!(r.abs() <= From::from(b)); - assert!(*a == b * &q + &r); - assert!(q == *ans_q); - assert!(r == *ans_r); - - let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone()); - assert_op!(a / b == ans_q); - assert_op!(a % b == ans_r); - - if b <= i32::max_value() as u32 { - let nb = -(b as i32); - assert_op!(a / nb == -ans_q.clone()); - assert_op!(a % nb == ans_r); - } - } - - fn check(a: &BigInt, b: BigDigit, q: &BigInt, r: &BigInt) { - check_sub(a, b, q, r); - check_sub(&a.neg(), b, &q.neg(), &r.neg()); - } - - for elm in MUL_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigInt::from_slice(Plus, a_vec); - let b = BigInt::from_slice(Plus, b_vec); - let c = BigInt::from_slice(Plus, c_vec); - - if a_vec.len() == 1 && a_vec[0] != 0 { - let a = a_vec[0]; - check(&c, a, &b, &Zero::zero()); - } - - if b_vec.len() == 1 && b_vec[0] != 0 { - let b = b_vec[0]; - check(&c, b, &a, &Zero::zero()); - } - } - - for elm in DIV_REM_QUADRUPLES.iter() { - let (a_vec, b_vec, c_vec, d_vec) = *elm; - let a = BigInt::from_slice(Plus, a_vec); - let c = BigInt::from_slice(Plus, c_vec); - let d = BigInt::from_slice(Plus, d_vec); - - if b_vec.len() == 1 && b_vec[0] != 0 { - let b = b_vec[0]; - check(&a, b, &c, &d); - } - } - -} - #[test] fn test_checked_add() { for elm in SUM_TRIPLES.iter() { @@ -1144,55 +911,6 @@ fn test_neg() { assert_eq!(-&zero, zero); } -#[test] -fn test_rand() { - let mut rng = thread_rng(); - let _n: BigInt = rng.gen_bigint(137); - assert!(rng.gen_bigint(0).is_zero()); -} - -#[test] -fn test_rand_range() { - let mut rng = thread_rng(); - - for _ in 0..10 { - assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(), - &FromPrimitive::from_usize(237).unwrap()), - FromPrimitive::from_usize(236).unwrap()); - } - - fn check(l: BigInt, u: BigInt) { - let mut rng = thread_rng(); - for _ in 0..1000 { - let n: BigInt = rng.gen_bigint_range(&l, &u); - assert!(n >= l); - assert!(n < u); - } - } - let l: BigInt = FromPrimitive::from_usize(403469000 + 2352).unwrap(); - let u: BigInt = FromPrimitive::from_usize(403469000 + 3513).unwrap(); - check(l.clone(), u.clone()); - check(-l.clone(), u.clone()); - check(-u.clone(), -l.clone()); -} - -#[test] -#[should_panic] -fn test_zero_rand_range() { - thread_rng().gen_bigint_range(&FromPrimitive::from_isize(54).unwrap(), - &FromPrimitive::from_isize(54).unwrap()); -} - -#[test] -#[should_panic] -fn test_negative_rand_range() { - let mut rng = thread_rng(); - let l = FromPrimitive::from_usize(2352).unwrap(); - let u = FromPrimitive::from_usize(3513).unwrap(); - // Switching u and l should fail: - let _n: BigInt = rng.gen_bigint_range(&u, &l); -} - #[test] fn test_negative_shr() { assert_eq!(BigInt::from(-1) >> 1, BigInt::from(-1)); @@ -1204,7 +922,7 @@ fn test_negative_shr() { #[test] fn test_random_shr() { use rand::Rng; - let mut rng = thread_rng(); + let mut rng = rand::thread_rng(); for p in rng.gen_iter::().take(1000) { let big = BigInt::from(p); @@ -1217,6 +935,7 @@ fn test_random_shr() { } } } + #[test] fn test_iter_sum() { let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap(); diff --git a/tests/bigint_scalar.rs b/tests/bigint_scalar.rs new file mode 100644 index 0000000..bd80f99 --- /dev/null +++ b/tests/bigint_scalar.rs @@ -0,0 +1,146 @@ +extern crate num_bigint; +extern crate num_traits; + +use num_bigint::{BigDigit, BigInt}; +use num_bigint::Sign::Plus; +use num_traits::{Zero, Signed, ToPrimitive}; + +use std::ops::Neg; + +mod consts; +use consts::*; + +#[macro_use] +mod macros; + +#[test] +fn test_scalar_add() { + fn check(x: &BigInt, y: &BigInt, z: &BigInt) { + let (x, y, z) = (x.clone(), y.clone(), z.clone()); + assert_signed_scalar_op!(x + y == z); + } + + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + let (na, nb, nc) = (-&a, -&b, -&c); + + check(&a, &b, &c); + check(&b, &a, &c); + check(&c, &na, &b); + check(&c, &nb, &a); + check(&a, &nc, &nb); + check(&b, &nc, &na); + check(&na, &nb, &nc); + check(&a, &na, &Zero::zero()); + } +} + +#[test] +fn test_scalar_sub() { + fn check(x: &BigInt, y: &BigInt, z: &BigInt) { + let (x, y, z) = (x.clone(), y.clone(), z.clone()); + assert_signed_scalar_op!(x - y == z); + } + + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + let (na, nb, nc) = (-&a, -&b, -&c); + + check(&c, &a, &b); + check(&c, &b, &a); + check(&nb, &a, &nc); + check(&na, &b, &nc); + check(&b, &na, &c); + check(&a, &nb, &c); + check(&nc, &na, &nb); + check(&a, &a, &Zero::zero()); + } +} + +#[test] +fn test_scalar_mul() { + fn check(x: &BigInt, y: &BigInt, z: &BigInt) { + let (x, y, z) = (x.clone(), y.clone(), z.clone()); + assert_signed_scalar_op!(x * y == z); + } + + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + let (na, nb, nc) = (-&a, -&b, -&c); + + check(&a, &b, &c); + check(&b, &a, &c); + check(&na, &nb, &c); + + check(&na, &b, &nc); + check(&nb, &a, &nc); + } +} + +#[test] +fn test_scalar_div_rem() { + fn check_sub(a: &BigInt, b: BigDigit, ans_q: &BigInt, ans_r: &BigInt) { + let (q, r) = (a / b, a % b); + if !r.is_zero() { + assert_eq!(r.sign(), a.sign()); + } + assert!(r.abs() <= From::from(b)); + assert!(*a == b * &q + &r); + assert!(q == *ans_q); + assert!(r == *ans_r); + + let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone()); + assert_op!(a / b == ans_q); + assert_op!(a % b == ans_r); + + if b <= i32::max_value() as u32 { + let nb = -(b as i32); + assert_op!(a / nb == -ans_q.clone()); + assert_op!(a % nb == ans_r); + } + } + + fn check(a: &BigInt, b: BigDigit, q: &BigInt, r: &BigInt) { + check_sub(a, b, q, r); + check_sub(&a.neg(), b, &q.neg(), &r.neg()); + } + + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + + if a_vec.len() == 1 && a_vec[0] != 0 { + let a = a_vec[0]; + check(&c, a, &b, &Zero::zero()); + } + + if b_vec.len() == 1 && b_vec[0] != 0 { + let b = b_vec[0]; + check(&c, b, &a, &Zero::zero()); + } + } + + for elm in DIV_REM_QUADRUPLES.iter() { + let (a_vec, b_vec, c_vec, d_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let c = BigInt::from_slice(Plus, c_vec); + let d = BigInt::from_slice(Plus, d_vec); + + if b_vec.len() == 1 && b_vec[0] != 0 { + let b = b_vec[0]; + check(&a, b, &c, &d); + } + } + +} diff --git a/src/tests/biguint.rs b/tests/biguint.rs similarity index 83% rename from src/tests/biguint.rs rename to tests/biguint.rs index 9ff4469..fe2111f 100644 --- a/src/tests/biguint.rs +++ b/tests/biguint.rs @@ -1,7 +1,12 @@ -use integer::Integer; -use {BigDigit, BigUint, ToBigUint, big_digit}; -use {BigInt, RandBigInt, ToBigInt}; -use Sign::Plus; +extern crate num_bigint; +extern crate num_integer; +extern crate num_traits; +extern crate rand; + +use num_integer::Integer; +use num_bigint::{BigDigit, BigUint, ToBigUint, big_digit}; +use num_bigint::{BigInt, ToBigInt}; +use num_bigint::Sign::Plus; use std::cmp::Ordering::{Less, Equal, Greater}; use std::{f32, f64}; @@ -9,79 +14,17 @@ use std::i64; use std::iter::repeat; use std::str::FromStr; use std::{u8, u16, u32, u64, usize}; +use std::hash::{BuildHasher, Hasher, Hash}; +use std::collections::hash_map::RandomState; -use rand::thread_rng; -use traits::{Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, ToPrimitive, - FromPrimitive, Float}; +use num_traits::{Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, ToPrimitive, + FromPrimitive, Float}; +mod consts; +use consts::*; -/// Assert that an op works for all val/ref combinations -macro_rules! assert_op { - ($left:ident $op:tt $right:ident == $expected:expr) => { - assert_eq!((&$left) $op (&$right), $expected); - assert_eq!((&$left) $op $right.clone(), $expected); - assert_eq!($left.clone() $op (&$right), $expected); - assert_eq!($left.clone() $op $right.clone(), $expected); - }; -} -/// Assert that an assign-op works for all val/ref combinations -macro_rules! assert_assign_op { - ($left:ident $op:tt $right:ident == $expected:expr) => { - { - let mut tmp12384 = $left.clone(); - assert_eq!({ tmp12384 $op &$right; tmp12384}, $expected); - - let mut tmp12384 = $left.clone(); - assert_eq!({ tmp12384 $op $right.clone(); tmp12384}, $expected); - } - }; -} - -/// Assert that an op works for scalar left or right -macro_rules! assert_scalar_op { - (($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => { - $( - if let Some(left) = $left.$to() { - assert_op!(left $op $right == $expected); - } - if let Some(right) = $right.$to() { - assert_op!($left $op right == $expected); - } - )* - }; - ($left:ident $op:tt $right:ident == $expected:expr) => { - assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize) - $left $op $right == $expected); - }; -} - -#[test] -fn test_from_slice() { - fn check(slice: &[BigDigit], data: &[BigDigit]) { - assert!(BigUint::from_slice(slice).data == data); - } - check(&[1], &[1]); - check(&[0, 0, 0], &[]); - check(&[1, 2, 0, 0], &[1, 2]); - check(&[0, 0, 1, 2], &[0, 0, 1, 2]); - check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); - check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); -} - -#[test] -fn test_assign_from_slice() { - fn check(slice: &[BigDigit], data: &[BigDigit]) { - let mut p = BigUint::from_slice(&[2627_u32, 0_u32, 9182_u32, 42_u32]); - p.assign_from_slice(slice); - assert!(p.data == data); - } - check(&[1], &[1]); - check(&[0, 0, 0], &[]); - check(&[1, 2, 0, 0], &[1, 2]); - check(&[0, 0, 1, 2], &[0, 0, 1, 2]); - check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); - check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); -} +#[macro_use] +mod macros; #[test] fn test_from_bytes_be() { @@ -182,6 +125,12 @@ fn test_cmp() { } } +fn hash(x: &T) -> u64 { + let mut hasher = ::Hasher::new(); + x.hash(&mut hasher); + hasher.finish() +} + #[test] fn test_hash() { use hash; @@ -510,9 +459,6 @@ fn test_shr() { "88887777666655554444333322221111"); } -const N1: BigDigit = -1i32 as BigDigit; -const N2: BigDigit = -2i32 as BigDigit; - // `DoubleBigDigit` size dependent #[test] fn test_convert_i64() { @@ -527,9 +473,9 @@ fn test_convert_i64() { check(i64::MAX.to_biguint().unwrap(), i64::MAX); check(BigUint::new(vec![]), 0); - check(BigUint::new(vec![1]), (1 << (0 * big_digit::BITS))); + check(BigUint::new(vec![1]), 1 << (0 * big_digit::BITS)); check(BigUint::new(vec![N1]), (1 << (1 * big_digit::BITS)) - 1); - check(BigUint::new(vec![0, 1]), (1 << (1 * big_digit::BITS))); + check(BigUint::new(vec![0, 1]), 1 << (1 * big_digit::BITS)); check(BigUint::new(vec![N1, N1 >> 1]), i64::MAX); assert_eq!(i64::MIN.to_biguint(), None); @@ -553,9 +499,9 @@ fn test_convert_u64() { check(u64::MAX.to_biguint().unwrap(), u64::MAX); check(BigUint::new(vec![]), 0); - check(BigUint::new(vec![1]), (1 << (0 * big_digit::BITS))); + check(BigUint::new(vec![1]), 1 << (0 * big_digit::BITS)); check(BigUint::new(vec![N1]), (1 << (1 * big_digit::BITS)) - 1); - check(BigUint::new(vec![0, 1]), (1 << (1 * big_digit::BITS))); + check(BigUint::new(vec![0, 1]), 1 << (1 * big_digit::BITS)); check(BigUint::new(vec![N1, N1]), u64::MAX); assert_eq!(BigUint::new(vec![0, 0, 1]).to_u64(), None); @@ -728,18 +674,6 @@ fn test_convert_from_uint() { check!(usize, BigUint::from(usize::MAX as u64)); } -const SUM_TRIPLES: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] = &[(&[], &[], &[]), - (&[], &[1], &[1]), - (&[1], &[1], &[2]), - (&[1], &[1, 1], &[2, 1]), - (&[1], &[N1], &[0, 1]), - (&[1], &[N1, N1], &[0, 0, 1]), - (&[N1, N1], &[N1, N1], &[N2, N1, 1]), - (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), - (&[2, 2, 1], &[N1, N2], &[1, 1, 2])]; - #[test] fn test_add() { for elm in SUM_TRIPLES.iter() { @@ -755,19 +689,6 @@ fn test_add() { } } -#[test] -fn test_scalar_add() { - for elm in SUM_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigUint::from_slice(a_vec); - let b = BigUint::from_slice(b_vec); - let c = BigUint::from_slice(c_vec); - - assert_scalar_op!(a + b == c); - assert_scalar_op!(b + a == c); - } -} - #[test] fn test_sub() { for elm in SUM_TRIPLES.iter() { @@ -783,19 +704,6 @@ fn test_sub() { } } -#[test] -fn test_scalar_sub() { - for elm in SUM_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigUint::from_slice(a_vec); - let b = BigUint::from_slice(b_vec); - let c = BigUint::from_slice(c_vec); - - assert_scalar_op!(c - a == b); - assert_scalar_op!(c - b == a); - } -} - #[test] #[should_panic] fn test_sub_fail_on_underflow() { @@ -803,43 +711,6 @@ fn test_sub_fail_on_underflow() { a - b; } -const M: u32 = ::std::u32::MAX; -const MUL_TRIPLES: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] = &[(&[], &[], &[]), - (&[], &[1], &[]), - (&[2], &[], &[]), - (&[1], &[1], &[1]), - (&[2], &[3], &[6]), - (&[1], &[1, 1, 1], &[1, 1, 1]), - (&[1, 2, 3], &[3], &[3, 6, 9]), - (&[1, 1, 1], &[N1], &[N1, N1, N1]), - (&[1, 2, 3], &[N1], &[N1, N2, N2, 2]), - (&[1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]), - (&[N1], &[N1], &[1, N2]), - (&[N1, N1], &[N1], &[1, N1, N2]), - (&[N1, N1, N1], &[N1], &[1, N1, N1, N2]), - (&[N1, N1, N1, N1], &[N1], &[1, N1, N1, N1, N2]), - (&[M / 2 + 1], &[2], &[0, 1]), - (&[0, M / 2 + 1], &[2], &[0, 0, 1]), - (&[1, 2], &[1, 2, 3], &[1, 4, 7, 6]), - (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]), - (&[N1, N1, N1], - &[N1, N1, N1, N1], - &[1, 0, 0, N1, N2, N1, N1]), - (&[0, 0, 1], &[1, 2, 3], &[0, 0, 1, 2, 3]), - (&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1])]; - -const DIV_REM_QUADRUPLES: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] = &[(&[1], &[2], &[], &[1]), - (&[3], &[2], &[1], &[1]), - (&[1, 1], &[2], &[M / 2 + 1], &[1]), - (&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]), - (&[0, 1], &[N1], &[1], &[1]), - (&[N1, N1], &[N2], &[2, 1], &[3])]; - #[test] fn test_mul() { for elm in MUL_TRIPLES.iter() { @@ -866,19 +737,6 @@ fn test_mul() { } } -#[test] -fn test_scalar_mul() { - for elm in MUL_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigUint::from_slice(a_vec); - let b = BigUint::from_slice(b_vec); - let c = BigUint::from_slice(c_vec); - - assert_scalar_op!(a * b == c); - assert_scalar_op!(b * a == c); - } -} - #[test] fn test_div_rem() { for elm in MUL_TRIPLES.iter() { @@ -920,39 +778,6 @@ fn test_div_rem() { } } -#[test] -fn test_scalar_div_rem() { - for elm in MUL_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let a = BigUint::from_slice(a_vec); - let b = BigUint::from_slice(b_vec); - let c = BigUint::from_slice(c_vec); - - if !a.is_zero() { - assert_scalar_op!(c / a == b); - assert_scalar_op!(c % a == Zero::zero()); - } - - if !b.is_zero() { - assert_scalar_op!(c / b == a); - assert_scalar_op!(c % b == Zero::zero()); - } - } - - for elm in DIV_REM_QUADRUPLES.iter() { - let (a_vec, b_vec, c_vec, d_vec) = *elm; - let a = BigUint::from_slice(a_vec); - let b = BigUint::from_slice(b_vec); - let c = BigUint::from_slice(c_vec); - let d = BigUint::from_slice(d_vec); - - if !b.is_zero() { - assert_scalar_op!(a / b == c); - assert_scalar_op!(a % b == d); - } - } -} - #[test] fn test_checked_add() { for elm in SUM_TRIPLES.iter() { @@ -1595,88 +1420,6 @@ fn test_bits() { assert_eq!((one << 426).bits(), 427); } -#[test] -fn test_rand() { - let mut rng = thread_rng(); - let _n: BigUint = rng.gen_biguint(137); - assert!(rng.gen_biguint(0).is_zero()); -} - -#[test] -fn test_rand_range() { - let mut rng = thread_rng(); - - for _ in 0..10 { - assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(), - &FromPrimitive::from_usize(237).unwrap()), - FromPrimitive::from_usize(236).unwrap()); - } - - let l = FromPrimitive::from_usize(403469000 + 2352).unwrap(); - let u = FromPrimitive::from_usize(403469000 + 3513).unwrap(); - for _ in 0..1000 { - let n: BigUint = rng.gen_biguint_below(&u); - assert!(n < u); - - let n: BigUint = rng.gen_biguint_range(&l, &u); - assert!(n >= l); - assert!(n < u); - } -} - -#[test] -#[should_panic] -fn test_zero_rand_range() { - thread_rng().gen_biguint_range(&FromPrimitive::from_usize(54).unwrap(), - &FromPrimitive::from_usize(54).unwrap()); -} - -#[test] -#[should_panic] -fn test_negative_rand_range() { - let mut rng = thread_rng(); - let l = FromPrimitive::from_usize(2352).unwrap(); - let u = FromPrimitive::from_usize(3513).unwrap(); - // Switching u and l should fail: - let _n: BigUint = rng.gen_biguint_range(&u, &l); -} - -fn test_mul_divide_torture_count(count: usize) { - use rand::{SeedableRng, StdRng, Rng}; - - let bits_max = 1 << 12; - let seed: &[_] = &[1, 2, 3, 4]; - let mut rng: StdRng = SeedableRng::from_seed(seed); - - for _ in 0..count { - // Test with numbers of random sizes: - let xbits = rng.gen_range(0, bits_max); - let ybits = rng.gen_range(0, bits_max); - - let x = rng.gen_biguint(xbits); - let y = rng.gen_biguint(ybits); - - if x.is_zero() || y.is_zero() { - continue; - } - - let prod = &x * &y; - assert_eq!(&prod / &x, y); - assert_eq!(&prod / &y, x); - } -} - -#[test] -fn test_mul_divide_torture() { - test_mul_divide_torture_count(1000); -} - -#[test] -#[ignore] -fn test_mul_divide_torture_long() { - test_mul_divide_torture_count(1000000); -} - #[test] fn test_iter_sum() { let result: BigUint = FromPrimitive::from_isize(1234567).unwrap(); diff --git a/tests/biguint_scalar.rs b/tests/biguint_scalar.rs new file mode 100644 index 0000000..28461b6 --- /dev/null +++ b/tests/biguint_scalar.rs @@ -0,0 +1,103 @@ +extern crate num_bigint; +extern crate num_traits; + +use num_bigint::BigUint; +use num_traits::{Zero, ToPrimitive}; + +mod consts; +use consts::*; + +#[macro_use] +mod macros; + +#[test] +fn test_scalar_add() { + fn check(x: &BigUint, y: &BigUint, z: &BigUint) { + let (x, y, z) = (x.clone(), y.clone(), z.clone()); + assert_unsigned_scalar_op!(x + y == z); + } + + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); + + check(&a, &b, &c); + check(&b, &a, &c); + } +} + +#[test] +fn test_scalar_sub() { + fn check(x: &BigUint, y: &BigUint, z: &BigUint) { + let (x, y, z) = (x.clone(), y.clone(), z.clone()); + assert_unsigned_scalar_op!(x - y == z); + } + + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); + + check(&c, &a, &b); + check(&c, &b, &a); + } +} + +#[test] +fn test_scalar_mul() { + fn check(x: &BigUint, y: &BigUint, z: &BigUint) { + let (x, y, z) = (x.clone(), y.clone(), z.clone()); + assert_unsigned_scalar_op!(x * y == z); + } + + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); + + check(&a, &b, &c); + check(&b, &a, &c); + } +} + +#[test] +fn test_scalar_div_rem() { + fn check(x: &BigUint, y: &BigUint, z: &BigUint, r: &BigUint) { + let (x, y, z, r) = (x.clone(), y.clone(), z.clone(), r.clone()); + assert_unsigned_scalar_op!(x / y == z); + assert_unsigned_scalar_op!(x % y == r); + } + + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); + + if !a.is_zero() { + check(&c, &a, &b, &Zero::zero()); + } + + if !b.is_zero() { + check(&c, &b, &a, &Zero::zero()); + } + } + + for elm in DIV_REM_QUADRUPLES.iter() { + let (a_vec, b_vec, c_vec, d_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); + let d = BigUint::from_slice(d_vec); + + if !b.is_zero() { + check(&a, &b, &c, &d); + assert_unsigned_scalar_op!(a / b == c); + assert_unsigned_scalar_op!(a % b == d); + } + } +} diff --git a/tests/consts/mod.rs b/tests/consts/mod.rs new file mode 100644 index 0000000..72ea786 --- /dev/null +++ b/tests/consts/mod.rs @@ -0,0 +1,65 @@ +#![allow(unused)] + +use num_bigint::BigDigit; + +pub const N1: BigDigit = -1i32 as BigDigit; +pub const N2: BigDigit = -2i32 as BigDigit; + +pub const SUM_TRIPLES: &'static [( + &'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit], +)] = &[ + (&[], &[], &[]), + (&[], &[1], &[1]), + (&[1], &[1], &[2]), + (&[1], &[1, 1], &[2, 1]), + (&[1], &[N1], &[0, 1]), + (&[1], &[N1, N1], &[0, 0, 1]), + (&[N1, N1], &[N1, N1], &[N2, N1, 1]), + (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), + (&[2, 2, 1], &[N1, N2], &[1, 1, 2]), +]; + +pub const M: u32 = ::std::u32::MAX; +pub const MUL_TRIPLES: &'static [( + &'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit], +)] = &[ + (&[], &[], &[]), + (&[], &[1], &[]), + (&[2], &[], &[]), + (&[1], &[1], &[1]), + (&[2], &[3], &[6]), + (&[1], &[1, 1, 1], &[1, 1, 1]), + (&[1, 2, 3], &[3], &[3, 6, 9]), + (&[1, 1, 1], &[N1], &[N1, N1, N1]), + (&[1, 2, 3], &[N1], &[N1, N2, N2, 2]), + (&[1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]), + (&[N1], &[N1], &[1, N2]), + (&[N1, N1], &[N1], &[1, N1, N2]), + (&[N1, N1, N1], &[N1], &[1, N1, N1, N2]), + (&[N1, N1, N1, N1], &[N1], &[1, N1, N1, N1, N2]), + (&[M / 2 + 1], &[2], &[0, 1]), + (&[0, M / 2 + 1], &[2], &[0, 0, 1]), + (&[1, 2], &[1, 2, 3], &[1, 4, 7, 6]), + (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]), + (&[N1, N1, N1], &[N1, N1, N1, N1], &[1, 0, 0, N1, N2, N1, N1]), + (&[0, 0, 1], &[1, 2, 3], &[0, 0, 1, 2, 3]), + (&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]), +]; + +pub const DIV_REM_QUADRUPLES: &'static [( + &'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit], +)] = &[ + (&[1], &[2], &[], &[1]), + (&[3], &[2], &[1], &[1]), + (&[1, 1], &[2], &[M / 2 + 1], &[1]), + (&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]), + (&[0, 1], &[N1], &[1], &[1]), + (&[N1, N1], &[N2], &[2, 1], &[3]), +]; diff --git a/tests/macros/mod.rs b/tests/macros/mod.rs new file mode 100644 index 0000000..9b4391d --- /dev/null +++ b/tests/macros/mod.rs @@ -0,0 +1,53 @@ +#![allow(unused)] + +/// Assert that an op works for all val/ref combinations +macro_rules! assert_op { + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_eq!((&$left) $op (&$right), $expected); + assert_eq!((&$left) $op $right.clone(), $expected); + assert_eq!($left.clone() $op (&$right), $expected); + assert_eq!($left.clone() $op $right.clone(), $expected); + }; +} + +/// Assert that an assign-op works for all val/ref combinations +macro_rules! assert_assign_op { + ($left:ident $op:tt $right:ident == $expected:expr) => { + { + let mut left = $left.clone(); + assert_eq!({ left $op &$right; left}, $expected); + + let mut left = $left.clone(); + assert_eq!({ left $op $right.clone(); left}, $expected); + } + }; +} + +/// Assert that an op works for scalar left or right +macro_rules! assert_scalar_op { + (($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => { + $( + if let Some(left) = $left.$to() { + assert_op!(left $op $right == $expected); + } + if let Some(right) = $right.$to() { + assert_op!($left $op right == $expected); + } + )* + }; +} + +macro_rules! assert_unsigned_scalar_op { + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize) + $left $op $right == $expected); + }; +} + +macro_rules! assert_signed_scalar_op { + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, + to_i8, to_i16, to_i32, to_i64, to_isize) + $left $op $right == $expected); + }; +} diff --git a/tests/rand.rs b/tests/rand.rs new file mode 100644 index 0000000..a6fae3f --- /dev/null +++ b/tests/rand.rs @@ -0,0 +1,112 @@ +#![cfg(feature = "rand")] + +extern crate num_bigint; +extern crate num_traits; +extern crate rand; + +mod biguint { + use rand::thread_rng; + use num_bigint::{BigUint, RandBigInt}; + use num_traits::{FromPrimitive, Zero}; + + #[test] + fn test_rand() { + let mut rng = thread_rng(); + let _n: BigUint = rng.gen_biguint(137); + assert!(rng.gen_biguint(0).is_zero()); + } + + #[test] + fn test_rand_range() { + let mut rng = thread_rng(); + + for _ in 0..10 { + assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(), + &FromPrimitive::from_usize(237).unwrap()), + FromPrimitive::from_usize(236).unwrap()); + } + + let l = FromPrimitive::from_usize(403469000 + 2352).unwrap(); + let u = FromPrimitive::from_usize(403469000 + 3513).unwrap(); + for _ in 0..1000 { + let n: BigUint = rng.gen_biguint_below(&u); + assert!(n < u); + + let n: BigUint = rng.gen_biguint_range(&l, &u); + assert!(n >= l); + assert!(n < u); + } + } + + #[test] + #[should_panic] + fn test_zero_rand_range() { + thread_rng().gen_biguint_range(&FromPrimitive::from_usize(54).unwrap(), + &FromPrimitive::from_usize(54).unwrap()); + } + + #[test] + #[should_panic] + fn test_negative_rand_range() { + let mut rng = thread_rng(); + let l = FromPrimitive::from_usize(2352).unwrap(); + let u = FromPrimitive::from_usize(3513).unwrap(); + // Switching u and l should fail: + let _n: BigUint = rng.gen_biguint_range(&u, &l); + } +} + +mod bigint { + use rand::thread_rng; + use num_bigint::{BigInt, RandBigInt}; + use num_traits::{FromPrimitive, Zero}; + + #[test] + fn test_rand() { + let mut rng = thread_rng(); + let _n: BigInt = rng.gen_bigint(137); + assert!(rng.gen_bigint(0).is_zero()); + } + + #[test] + fn test_rand_range() { + let mut rng = thread_rng(); + + for _ in 0..10 { + assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(), + &FromPrimitive::from_usize(237).unwrap()), + FromPrimitive::from_usize(236).unwrap()); + } + + fn check(l: BigInt, u: BigInt) { + let mut rng = thread_rng(); + for _ in 0..1000 { + let n: BigInt = rng.gen_bigint_range(&l, &u); + assert!(n >= l); + assert!(n < u); + } + } + let l: BigInt = FromPrimitive::from_usize(403469000 + 2352).unwrap(); + let u: BigInt = FromPrimitive::from_usize(403469000 + 3513).unwrap(); + check(l.clone(), u.clone()); + check(-l.clone(), u.clone()); + check(-u.clone(), -l.clone()); + } + + #[test] + #[should_panic] + fn test_zero_rand_range() { + thread_rng().gen_bigint_range(&FromPrimitive::from_isize(54).unwrap(), + &FromPrimitive::from_isize(54).unwrap()); + } + + #[test] + #[should_panic] + fn test_negative_rand_range() { + let mut rng = thread_rng(); + let l = FromPrimitive::from_usize(2352).unwrap(); + let u = FromPrimitive::from_usize(3513).unwrap(); + // Switching u and l should fail: + let _n: BigInt = rng.gen_bigint_range(&u, &l); + } +} diff --git a/tests/torture.rs b/tests/torture.rs new file mode 100644 index 0000000..6ae1b8d --- /dev/null +++ b/tests/torture.rs @@ -0,0 +1,45 @@ +#![cfg(feature = "rand")] + +extern crate num_bigint; +extern crate num_traits; +extern crate rand; + +use num_bigint::RandBigInt; +use num_traits::Zero; +use rand::{SeedableRng, StdRng, Rng}; + +fn test_mul_divide_torture_count(count: usize) { + + let bits_max = 1 << 12; + let seed: &[_] = &[1, 2, 3, 4]; + let mut rng: StdRng = SeedableRng::from_seed(seed); + + for _ in 0..count { + // Test with numbers of random sizes: + let xbits = rng.gen_range(0, bits_max); + let ybits = rng.gen_range(0, bits_max); + + let x = rng.gen_biguint(xbits); + let y = rng.gen_biguint(ybits); + + if x.is_zero() || y.is_zero() { + continue; + } + + let prod = &x * &y; + assert_eq!(&prod / &x, y); + assert_eq!(&prod / &y, x); + } +} + +#[test] +fn test_mul_divide_torture() { + test_mul_divide_torture_count(1000); +} + +#[test] +#[ignore] +fn test_mul_divide_torture_long() { + test_mul_divide_torture_count(1000000); +} +