1 use num_bigint::BigInt;
2 use num_bigint::Sign::Plus;
3 use num_traits::{One, Signed, ToPrimitive, Zero};
4 
5 use std::ops::Neg;
6 use std::panic::catch_unwind;
7 
8 mod consts;
9 use crate::consts::*;
10 
11 #[macro_use]
12 mod macros;
13 
14 #[test]
test_scalar_add()15 fn test_scalar_add() {
16     fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
17         let (x, y, z) = (x.clone(), y.clone(), z.clone());
18         assert_signed_scalar_op!(x + y == z);
19         assert_signed_scalar_assign_op!(x += y == z);
20     }
21 
22     for elm in SUM_TRIPLES.iter() {
23         let (a_vec, b_vec, c_vec) = *elm;
24         let a = BigInt::from_slice(Plus, a_vec);
25         let b = BigInt::from_slice(Plus, b_vec);
26         let c = BigInt::from_slice(Plus, c_vec);
27         let (na, nb, nc) = (-&a, -&b, -&c);
28 
29         check(&a, &b, &c);
30         check(&b, &a, &c);
31         check(&c, &na, &b);
32         check(&c, &nb, &a);
33         check(&a, &nc, &nb);
34         check(&b, &nc, &na);
35         check(&na, &nb, &nc);
36         check(&a, &na, &Zero::zero());
37     }
38 }
39 
40 #[test]
test_scalar_sub()41 fn test_scalar_sub() {
42     fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
43         let (x, y, z) = (x.clone(), y.clone(), z.clone());
44         assert_signed_scalar_op!(x - y == z);
45         assert_signed_scalar_assign_op!(x -= y == z);
46     }
47 
48     for elm in SUM_TRIPLES.iter() {
49         let (a_vec, b_vec, c_vec) = *elm;
50         let a = BigInt::from_slice(Plus, a_vec);
51         let b = BigInt::from_slice(Plus, b_vec);
52         let c = BigInt::from_slice(Plus, c_vec);
53         let (na, nb, nc) = (-&a, -&b, -&c);
54 
55         check(&c, &a, &b);
56         check(&c, &b, &a);
57         check(&nb, &a, &nc);
58         check(&na, &b, &nc);
59         check(&b, &na, &c);
60         check(&a, &nb, &c);
61         check(&nc, &na, &nb);
62         check(&a, &a, &Zero::zero());
63     }
64 }
65 
66 #[test]
test_scalar_mul()67 fn test_scalar_mul() {
68     fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
69         let (x, y, z) = (x.clone(), y.clone(), z.clone());
70         assert_signed_scalar_op!(x * y == z);
71         assert_signed_scalar_assign_op!(x *= y == z);
72     }
73 
74     for elm in MUL_TRIPLES.iter() {
75         let (a_vec, b_vec, c_vec) = *elm;
76         let a = BigInt::from_slice(Plus, a_vec);
77         let b = BigInt::from_slice(Plus, b_vec);
78         let c = BigInt::from_slice(Plus, c_vec);
79         let (na, nb, nc) = (-&a, -&b, -&c);
80 
81         check(&a, &b, &c);
82         check(&b, &a, &c);
83         check(&na, &nb, &c);
84 
85         check(&na, &b, &nc);
86         check(&nb, &a, &nc);
87     }
88 }
89 
90 #[test]
test_scalar_div_rem()91 fn test_scalar_div_rem() {
92     fn check_sub(a: &BigInt, b: u32, ans_q: &BigInt, ans_r: &BigInt) {
93         let (q, r) = (a / b, a % b);
94         if !r.is_zero() {
95             assert_eq!(r.sign(), a.sign());
96         }
97         assert!(r.abs() <= BigInt::from(b));
98         assert!(*a == b * &q + &r);
99         assert!(q == *ans_q);
100         assert!(r == *ans_r);
101 
102         let b = BigInt::from(b);
103         let (a, ans_q, ans_r) = (a.clone(), ans_q.clone(), ans_r.clone());
104         assert_signed_scalar_op!(a / b == ans_q);
105         assert_signed_scalar_op!(a % b == ans_r);
106         assert_signed_scalar_assign_op!(a /= b == ans_q);
107         assert_signed_scalar_assign_op!(a %= b == ans_r);
108 
109         let nb = -b;
110         assert_signed_scalar_op!(a / nb == -ans_q.clone());
111         assert_signed_scalar_op!(a % nb == ans_r);
112         assert_signed_scalar_assign_op!(a /= nb == -ans_q.clone());
113         assert_signed_scalar_assign_op!(a %= nb == ans_r);
114     }
115 
116     fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {
117         check_sub(a, b, q, r);
118         check_sub(&a.neg(), b, &q.neg(), &r.neg());
119     }
120 
121     for elm in MUL_TRIPLES.iter() {
122         let (a_vec, b_vec, c_vec) = *elm;
123         let a = BigInt::from_slice(Plus, a_vec);
124         let b = BigInt::from_slice(Plus, b_vec);
125         let c = BigInt::from_slice(Plus, c_vec);
126 
127         if a_vec.len() == 1 && a_vec[0] != 0 {
128             let a = a_vec[0];
129             check(&c, a, &b, &Zero::zero());
130         }
131 
132         if b_vec.len() == 1 && b_vec[0] != 0 {
133             let b = b_vec[0];
134             check(&c, b, &a, &Zero::zero());
135         }
136     }
137 
138     for elm in DIV_REM_QUADRUPLES.iter() {
139         let (a_vec, b_vec, c_vec, d_vec) = *elm;
140         let a = BigInt::from_slice(Plus, a_vec);
141         let c = BigInt::from_slice(Plus, c_vec);
142         let d = BigInt::from_slice(Plus, d_vec);
143 
144         if b_vec.len() == 1 && b_vec[0] != 0 {
145             let b = b_vec[0];
146             check(&a, b, &c, &d);
147         }
148     }
149 }
150 
151 #[test]
152 #[ignore = "Android sometimes uses panic_abort"]
test_scalar_div_rem_zero()153 fn test_scalar_div_rem_zero() {
154     catch_unwind(|| BigInt::zero() / 0u32).unwrap_err();
155     catch_unwind(|| BigInt::zero() % 0u32).unwrap_err();
156     catch_unwind(|| BigInt::one() / 0u32).unwrap_err();
157     catch_unwind(|| BigInt::one() % 0u32).unwrap_err();
158 }
159