blob: a9e7b04b52566076ddea7f1b048f7e08bb38f00d [file] [log] [blame] [edit]
#![cfg(feature = "quickcheck")]
#![cfg(feature = "quickcheck_macros")]
extern crate num_bigint;
extern crate num_integer;
extern crate num_traits;
extern crate quickcheck;
#[macro_use]
extern crate quickcheck_macros;
use num_bigint::{BigInt, BigUint};
use num_integer::Integer;
use num_traits::{Num, One, Pow, Signed, Zero};
use quickcheck::{QuickCheck, StdThreadGen, TestResult};
#[quickcheck]
fn quickcheck_unsigned_eq_reflexive(a: BigUint) -> bool {
a == a
}
#[quickcheck]
fn quickcheck_signed_eq_reflexive(a: BigInt) -> bool {
a == a
}
#[quickcheck]
fn quickcheck_unsigned_eq_symmetric(a: BigUint, b: BigUint) -> bool {
if a == b {
b == a
} else {
b != a
}
}
#[quickcheck]
fn quickcheck_signed_eq_symmetric(a: BigInt, b: BigInt) -> bool {
if a == b {
b == a
} else {
b != a
}
}
#[test]
fn quickcheck_arith_primitive() {
let gen = StdThreadGen::new(usize::max_value());
let mut qc = QuickCheck::with_gen(gen);
fn test_unsigned_add_primitive(a: usize, b: usize) -> TestResult {
let actual = BigUint::from(a) + BigUint::from(b);
match a.checked_add(b) {
None => TestResult::discard(),
Some(expected) => TestResult::from_bool(BigUint::from(expected) == actual),
}
}
fn test_signed_add_primitive(a: isize, b: isize) -> TestResult {
let actual = BigInt::from(a) + BigInt::from(b);
match a.checked_add(b) {
None => TestResult::discard(),
Some(expected) => TestResult::from_bool(BigInt::from(expected) == actual),
}
}
fn test_unsigned_mul_primitive(a: u64, b: u64) -> bool {
//maximum value of u64 means no overflow
BigUint::from(a as u128 * b as u128) == BigUint::from(a) * BigUint::from(b)
}
fn test_signed_mul_primitive(a: i64, b: i64) -> bool {
//maximum value of i64 means no overflow
BigInt::from(a as i128 * b as i128) == BigInt::from(a) * BigInt::from(b)
}
fn test_unsigned_sub_primitive(a: u128, b: u128) -> bool {
if b < a {
BigUint::from(a - b) == BigUint::from(a) - BigUint::from(b)
} else {
BigUint::from(b - a) == BigUint::from(b) - BigUint::from(a)
}
}
fn test_signed_sub_primitive(a: i128, b: i128) -> bool {
if b < a {
BigInt::from(a - b) == BigInt::from(a) - BigInt::from(b)
} else {
BigInt::from(b - a) == BigInt::from(b) - BigInt::from(a)
}
}
fn test_unsigned_div_primitive(a: u128, b: u128) -> TestResult {
if b == 0 {
TestResult::discard()
} else {
TestResult::from_bool(BigUint::from(a / b) == BigUint::from(a) / BigUint::from(b))
}
}
fn test_signed_div_primitive(a: i128, b: i128) -> TestResult {
if b == 0 {
TestResult::discard()
} else {
TestResult::from_bool(BigInt::from(a / b) == BigInt::from(a) / BigInt::from(b))
}
}
qc.quickcheck(test_unsigned_add_primitive as fn(usize, usize) -> TestResult);
qc.quickcheck(test_signed_add_primitive as fn(isize, isize) -> TestResult);
qc.quickcheck(test_unsigned_mul_primitive as fn(u64, u64) -> bool);
qc.quickcheck(test_signed_mul_primitive as fn(i64, i64) -> bool);
qc.quickcheck(test_unsigned_sub_primitive as fn(u128, u128) -> bool);
qc.quickcheck(test_signed_sub_primitive as fn(i128, i128) -> bool);
qc.quickcheck(test_unsigned_div_primitive as fn(u128, u128) -> TestResult);
qc.quickcheck(test_signed_div_primitive as fn(i128, i128) -> TestResult);
}
#[quickcheck]
fn quickcheck_unsigned_add_commutative(a: BigUint, b: BigUint) -> bool {
&a + &b == b + a
}
#[quickcheck]
fn quickcheck_signed_add_commutative(a: BigInt, b: BigInt) -> bool {
&a + &b == b + a
}
#[quickcheck]
fn quickcheck_unsigned_add_zero(a: BigUint) -> bool {
a == &a + BigUint::zero()
}
#[quickcheck]
fn quickcheck_signed_add_zero(a: BigInt) -> bool {
a == &a + BigInt::zero()
}
#[quickcheck]
fn quickcheck_unsigned_add_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
(&a + &b) + &c == a + (b + c)
}
#[quickcheck]
fn quickcheck_signed_add_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
(&a + &b) + &c == a + (b + c)
}
#[quickcheck]
fn quickcheck_unsigned_mul_zero(a: BigUint) -> bool {
a * BigUint::zero() == BigUint::zero()
}
#[quickcheck]
fn quickcheck_signed_mul_zero(a: BigInt) -> bool {
a * BigInt::zero() == BigInt::zero()
}
#[quickcheck]
fn quickcheck_unsigned_mul_one(a: BigUint) -> bool {
&a * BigUint::one() == a
}
#[quickcheck]
fn quickcheck_signed_mul_one(a: BigInt) -> bool {
&a * BigInt::one() == a
}
#[quickcheck]
fn quickcheck_unsigned_mul_commutative(a: BigUint, b: BigUint) -> bool {
&a * &b == b * a
}
#[quickcheck]
fn quickcheck_signed_mul_commutative(a: BigInt, b: BigInt) -> bool {
&a * &b == b * a
}
#[quickcheck]
fn quickcheck_unsigned_mul_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
(&a * &b) * &c == a * (b * c)
}
#[quickcheck]
fn quickcheck_signed_mul_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
(&a * &b) * &c == a * (b * c)
}
#[quickcheck]
fn quickcheck_unsigned_distributive(a: BigUint, b: BigUint, c: BigUint) -> bool {
&a * (&b + &c) == &a * b + a * c
}
#[quickcheck]
fn quickcheck_signed_distributive(a: BigInt, b: BigInt, c: BigInt) -> bool {
&a * (&b + &c) == &a * b + a * c
}
#[quickcheck]
///Tests that exactly one of a<b a>b a=b is true
fn quickcheck_unsigned_ge_le_eq_mut_exclusive(a: BigUint, b: BigUint) -> bool {
let gt_lt_eq = vec![a > b, a < b, a == b];
gt_lt_eq
.iter()
.fold(0, |acc, e| if *e { acc + 1 } else { acc })
== 1
}
#[quickcheck]
///Tests that exactly one of a<b a>b a=b is true
fn quickcheck_signed_ge_le_eq_mut_exclusive(a: BigInt, b: BigInt) -> bool {
let gt_lt_eq = vec![a > b, a < b, a == b];
gt_lt_eq
.iter()
.fold(0, |acc, e| if *e { acc + 1 } else { acc })
== 1
}
#[quickcheck]
/// Tests correctness of subtraction assuming addition is correct
fn quickcheck_unsigned_sub(a: BigUint, b: BigUint) -> bool {
if b < a {
&a - &b + b == a
} else {
&b - &a + a == b
}
}
#[quickcheck]
/// Tests correctness of subtraction assuming addition is correct
fn quickcheck_signed_sub(a: BigInt, b: BigInt) -> bool {
if b < a {
&a - &b + b == a
} else {
&b - &a + a == b
}
}
#[quickcheck]
fn quickcheck_unsigned_pow_zero(a: BigUint) -> bool {
a.pow(0_u32) == BigUint::one()
}
#[quickcheck]
fn quickcheck_unsigned_pow_one(a: BigUint) -> bool {
a.pow(1_u32) == a
}
#[quickcheck]
fn quickcheck_unsigned_sqrt(a: BigUint) -> bool {
(&a * &a).sqrt() == a
}
#[quickcheck]
fn quickcheck_unsigned_cbrt(a: BigUint) -> bool {
(&a * &a * &a).cbrt() == a
}
#[quickcheck]
fn quickcheck_signed_cbrt(a: BigInt) -> bool {
(&a * &a * &a).cbrt() == a
}
#[quickcheck]
fn quickcheck_unsigned_conversion(a: BigUint, radix: u8) -> TestResult {
let radix = radix as u32;
if radix > 36 || radix < 2 {
return TestResult::discard();
}
let string = a.to_str_radix(radix);
TestResult::from_bool(a == BigUint::from_str_radix(&string, radix).unwrap())
}
#[quickcheck]
fn quickcheck_signed_conversion(a: BigInt, radix: u8) -> TestResult {
let radix = radix as u32;
if radix > 36 || radix < 2 {
return TestResult::discard();
}
let string = a.to_str_radix(radix);
TestResult::from_bool(a == BigInt::from_str_radix(&string, radix).unwrap())
}
#[test]
fn quicktest_shift() {
let gen = StdThreadGen::new(usize::max_value());
let mut qc = QuickCheck::with_gen(gen);
fn test_shr_unsigned(a: u64, shift: u8) -> TestResult {
let shift = (shift % 64) as usize; //shift at most 64 bits
let big_a = BigUint::from(a);
TestResult::from_bool(BigUint::from(a >> shift) == big_a >> shift)
}
fn test_shr_signed(a: i64, shift: u8) -> TestResult {
let shift = (shift % 64) as usize; //shift at most 64 bits
let big_a = BigInt::from(a);
TestResult::from_bool(BigInt::from(a >> shift) == big_a >> shift)
}
fn test_shl_unsigned(a: u32, shift: u8) -> TestResult {
let shift = (shift % 32) as usize; //shift at most 32 bits
let a = a as u64; //leave room for the shifted bits
let big_a = BigUint::from(a);
TestResult::from_bool(BigUint::from(a >> shift) == big_a >> shift)
}
fn test_shl_signed(a: i32, shift: u8) -> TestResult {
let shift = (shift % 32) as usize;
let a = a as u64; //leave room for the shifted bits
let big_a = BigInt::from(a);
TestResult::from_bool(BigInt::from(a >> shift) == big_a >> shift)
}
qc.quickcheck(test_shr_unsigned as fn(u64, u8) -> TestResult);
qc.quickcheck(test_shr_signed as fn(i64, u8) -> TestResult);
qc.quickcheck(test_shl_unsigned as fn(u32, u8) -> TestResult);
qc.quickcheck(test_shl_signed as fn(i32, u8) -> TestResult);
}
#[test]
fn quickcheck_modpow() {
let gen = StdThreadGen::new(usize::max_value());
let mut qc = QuickCheck::with_gen(gen);
fn simple_modpow(base: &BigInt, exponent: &BigInt, modulus: &BigInt) -> BigInt {
assert!(!exponent.is_negative());
let mut result = BigInt::one().mod_floor(modulus);
let mut base = base.mod_floor(modulus);
let mut exponent = exponent.clone();
while !exponent.is_zero() {
if exponent.is_odd() {
result = (result * &base).mod_floor(modulus);
}
base = (&base * &base).mod_floor(modulus);
exponent >>= 1;
}
result
}
fn test_modpow(base: i128, exponent: u128, modulus: i128) -> TestResult {
if modulus.is_zero() {
TestResult::discard()
} else {
let base = BigInt::from(base);
let exponent = BigInt::from(exponent);
let modulus = BigInt::from(modulus);
let modpow = base.modpow(&exponent, &modulus);
let simple = simple_modpow(&base, &exponent, &modulus);
if modpow != simple {
eprintln!("{}.modpow({}, {})", base, exponent, modulus);
eprintln!(" expected {}", simple);
eprintln!(" actual {}", modpow);
TestResult::failed()
} else {
TestResult::passed()
}
}
}
qc.quickcheck(test_modpow as fn(i128, u128, i128) -> TestResult);
}