1 /*
2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package test.java.lang.StrictMath;
24 
25 import java.math.BigInteger;
26 
27 import org.testng.annotations.Test;
28 
29 import static org.testng.Assert.fail;
30 
31 /**
32  * @test Test for StrictMath.*Exact integer and long methods.
33  * @bug 6708398
34  * @summary Basic tests for StrictMath exact arithmetic operations.
35  *
36  * @author Roger Riggs
37  */
38 public class ExactArithTests {
39 
40     /**
41      * Test StrictMath.addExact, multiplyExact, subtractExact, incrementExact,
42      * decrementExact, negateExact methods with {@code int} arguments.
43      */
44     @Test
testIntegerExact()45     public void testIntegerExact() {
46         testIntegerExact(0, 0);
47         testIntegerExact(1, 1);
48         testIntegerExact(1, -1);
49         testIntegerExact(-1, 1);
50         testIntegerExact(1000, 2000);
51 
52         testIntegerExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
53         testIntegerExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
54         testIntegerExact(Integer.MIN_VALUE, 1);
55         testIntegerExact(Integer.MAX_VALUE, 1);
56         testIntegerExact(Integer.MIN_VALUE, 2);
57         testIntegerExact(Integer.MAX_VALUE, 2);
58         testIntegerExact(Integer.MIN_VALUE, -1);
59         testIntegerExact(Integer.MAX_VALUE, -1);
60         testIntegerExact(Integer.MIN_VALUE, -2);
61         testIntegerExact(Integer.MAX_VALUE, -2);
62     }
63 
64     /**
65      * Test exact arithmetic by comparing with the same operations using long
66      * and checking that the result is the same as the integer truncation.
67      * Errors are reported with {@link fail}.
68      *
69      * @param x first parameter
70      * @param y second parameter
71      */
testIntegerExact(int x, int y)72     static void testIntegerExact(int x, int y) {
73         try {
74             // Test addExact
75             int sum = StrictMath.addExact(x, y);
76             long sum2 = (long) x + (long) y;
77             if ((int) sum2 != sum2) {
78                 fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ") = " + sum + "; expected Arithmetic exception");
79             } else if (sum != sum2) {
80                 fail("FAIL: long StrictMath.addExact(" + x + " + " + y + ") = " + sum + "; expected: " + sum2);
81             }
82         } catch (ArithmeticException ex) {
83             long sum2 = (long) x + (long) y;
84             if ((int) sum2 == sum2) {
85                 fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
86             }
87         }
88 
89         try {
90             // Test subtractExact
91             int diff = StrictMath.subtractExact(x, y);
92             long diff2 = (long) x - (long) y;
93             if ((int) diff2 != diff2) {
94                 fail("FAIL: int StrictMath.subtractExact(" + x + " - " + y + ") = " + diff + "; expected: " + diff2);
95             }
96 
97         } catch (ArithmeticException ex) {
98             long diff2 = (long) x - (long) y;
99             if ((int) diff2 == diff2) {
100                 fail("FAIL: int StrictMath.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
101             }
102         }
103 
104         try {
105             // Test multiplyExact
106             int product = StrictMath.multiplyExact(x, y);
107             long m2 = (long) x * (long) y;
108             if ((int) m2 != m2) {
109                 fail("FAIL: int StrictMath.multiplyExact(" + x + " * " + y + ") = " + product + "; expected: " + m2);
110             }
111         } catch (ArithmeticException ex) {
112             long m2 = (long) x * (long) y;
113             if ((int) m2 == m2) {
114                 fail("FAIL: int StrictMath.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
115             }
116         }
117 
118         try {
119             // Test incrementExact
120             int inc = StrictMath.incrementExact(x);
121             long inc2 = (long) x + 1L;
122             if ((int) inc2 != inc2) {
123                 fail("FAIL: int StrictMath.incrementExact(" + x + ") = " + inc + "; expected Arithmetic exception");
124             } else if (inc != inc2) {
125                 fail("FAIL: long StrictMath.incrementExact(" + x + ") = " + inc + "; expected: " + inc2);
126             }
127         } catch (ArithmeticException ex) {
128             long inc2 = (long) x + 1L;
129             if ((int) inc2 == inc2) {
130                 fail("FAIL: int StrictMath.incrementExact(" + x + ")" + "; Unexpected exception: " + ex);
131             }
132         }
133 
134         try {
135             // Test decrementExact
136             int dec = StrictMath.decrementExact(x);
137             long dec2 = (long) x - 1L;
138             if ((int) dec2 != dec2) {
139                 fail("FAIL: int StrictMath.decrementExact(" + x + ") = " + dec + "; expected Arithmetic exception");
140             } else if (dec != dec2) {
141                 fail("FAIL: long StrictMath.decrementExact(" + x + ") = " + dec + "; expected: " + dec2);
142             }
143         } catch (ArithmeticException ex) {
144             long dec2 = (long) x - 1L;
145             if ((int) dec2 == dec2) {
146                 fail("FAIL: int StrictMath.decrementExact(" + x + ")" + "; Unexpected exception: " + ex);
147             }
148         }
149 
150         try {
151             // Test negateExact
152             int neg = StrictMath.negateExact(x);
153             long neg2 = -((long)x);
154             if ((int) neg2 != neg2) {
155                 fail("FAIL: int StrictMath.negateExact(" + x + ") = " + neg + "; expected Arithmetic exception");
156             } else if (neg != neg2) {
157                 fail("FAIL: long StrictMath.negateExact(" + x + ") = " + neg + "; expected: " + neg2);
158             }
159         } catch (ArithmeticException ex) {
160             long neg2 = -((long)x);
161             if ((int) neg2 == neg2) {
162                 fail("FAIL: int StrictMath.negateExact(" + x + ")" + "; Unexpected exception: " + ex);
163             }
164         }
165     }
166 
167     /**
168      * Test StrictMath.addExact, multiplyExact, subtractExact, incrementExact,
169      * decrementExact, negateExact, toIntExact methods with {@code long} arguments.
170      */
171     @Test
testLongExact()172     public void testLongExact() {
173         testLongExactTwice(0, 0);
174         testLongExactTwice(1, 1);
175         testLongExactTwice(1, -1);
176         testLongExactTwice(1000, 2000);
177 
178         testLongExactTwice(Long.MIN_VALUE, Long.MIN_VALUE);
179         testLongExactTwice(Long.MAX_VALUE, Long.MAX_VALUE);
180         testLongExactTwice(Long.MIN_VALUE, 1);
181         testLongExactTwice(Long.MAX_VALUE, 1);
182         testLongExactTwice(Long.MIN_VALUE, 2);
183         testLongExactTwice(Long.MAX_VALUE, 2);
184         testLongExactTwice(Long.MIN_VALUE, -1);
185         testLongExactTwice(Long.MAX_VALUE, -1);
186         testLongExactTwice(Long.MIN_VALUE, -2);
187         testLongExactTwice(Long.MAX_VALUE, -2);
188         testLongExactTwice(Long.MIN_VALUE/2, 2);
189         testLongExactTwice(Long.MAX_VALUE, 2);
190         testLongExactTwice(Integer.MAX_VALUE, Integer.MAX_VALUE);
191         testLongExactTwice(Integer.MAX_VALUE, -Integer.MAX_VALUE);
192         testLongExactTwice(Integer.MAX_VALUE+1, Integer.MAX_VALUE+1);
193         testLongExactTwice(Integer.MAX_VALUE+1, -Integer.MAX_VALUE+1);
194         testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
195         testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
196         testLongExactTwice(Integer.MIN_VALUE/2, 2);
197     }
198 
199     /**
200      * Test each of the exact operations with the arguments and
201      * with the arguments reversed.
202      * @param x
203      * @param y
204      */
testLongExactTwice(long x, long y)205     static void testLongExactTwice(long x, long y) {
206         testLongExact(x, y);
207         testLongExact(y, x);
208     }
209 
210 
211     /**
212      * Test long exact arithmetic by comparing with the same operations using BigInteger
213      * and checking that the result is the same as the long truncation.
214      * Errors are reported with {@link fail}.
215      *
216      * @param x first parameter
217      * @param y second parameter
218      */
testLongExact(long x, long y)219     static void testLongExact(long x, long y) {
220         BigInteger resultBig = null;
221         final BigInteger xBig = BigInteger.valueOf(x);
222         final BigInteger yBig = BigInteger.valueOf(y);
223         try {
224             // Test addExact
225             resultBig = xBig.add(yBig);
226             long sum = StrictMath.addExact(x, y);
227             checkResult("long StrictMath.addExact", x, y, sum, resultBig);
228         } catch (ArithmeticException ex) {
229             if (inLongRange(resultBig)) {
230                 fail("FAIL: long StrictMath.addExact(" + x + " + " + y + "); Unexpected exception: " + ex);
231             }
232         }
233 
234         try {
235             // Test subtractExact
236             resultBig = xBig.subtract(yBig);
237             long diff = StrictMath.subtractExact(x, y);
238             checkResult("long StrictMath.subtractExact", x, y, diff, resultBig);
239         } catch (ArithmeticException ex) {
240             if (inLongRange(resultBig)) {
241                 fail("FAIL: long StrictMath.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
242             }
243         }
244 
245         try {
246             // Test multiplyExact
247             resultBig = xBig.multiply(yBig);
248             long product = StrictMath.multiplyExact(x, y);
249             checkResult("long StrictMath.multiplyExact", x, y, product, resultBig);
250         } catch (ArithmeticException ex) {
251             if (inLongRange(resultBig)) {
252                 fail("FAIL: long StrictMath.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
253             }
254         }
255 
256         try {
257             // Test incrementExact
258             resultBig = xBig.add(BigInteger.ONE);
259             long inc = StrictMath.incrementExact(x);
260             checkResult("long Math.incrementExact", x, 1L, inc, resultBig);
261         } catch (ArithmeticException ex) {
262             if (inLongRange(resultBig)) {
263                 fail("FAIL: long Math.incrementExact(" + x + "); Unexpected exception: " + ex);
264             }
265         }
266 
267         try {
268             // Test decrementExact
269             resultBig = xBig.subtract(BigInteger.ONE);
270             long dec = StrictMath.decrementExact(x);
271             checkResult("long Math.decrementExact", x, 1L, dec, resultBig);
272         } catch (ArithmeticException ex) {
273             if (inLongRange(resultBig)) {
274                 fail("FAIL: long Math.decrementExact(" + x + "); Unexpected exception: " + ex);
275             }
276         }
277 
278         try {
279             // Test negateExact
280             resultBig = xBig.negate();
281             long dec = StrictMath.negateExact(x);
282             checkResult("long Math.negateExact", x, 0L, dec, resultBig);
283         } catch (ArithmeticException ex) {
284             if (inLongRange(resultBig)) {
285                 fail("FAIL: long Math.negateExact(" + x + "); Unexpected exception: " + ex);
286             }
287         }
288 
289         try {
290             // Test toIntExact
291             int value = StrictMath.toIntExact(x);
292             if ((long)value != x) {
293                 fail("FAIL: " + "long StrictMath.toIntExact" + "(" + x + ") = " + value + "; expected an arithmetic exception: ");
294             }
295         } catch (ArithmeticException ex) {
296             if (resultBig.bitLength() <= 32) {
297                 fail("FAIL: long StrictMath.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
298             }
299         }
300     }
301 
302     /**
303      * Compare the expected and actual results.
304      * @param message message for the error
305      * @param x first argument
306      * @param y second argument
307      * @param result actual result value
308      * @param expected expected result value
309      */
checkResult(String message, long x, long y, long result, BigInteger expected)310     static void checkResult(String message, long x, long y, long result, BigInteger expected) {
311         BigInteger resultBig = BigInteger.valueOf(result);
312         if (!inLongRange(expected)) {
313             fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result
314                     + "; expected an arithmetic exception: ");
315         } else if (!resultBig.equals(expected)) {
316             fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected "
317                     + expected);
318         }
319     }
320 
321     /**
322      * Check if the value fits in 64 bits (a long).
323      *
324      * @return true if the value fits in 64 bits (including the sign).
325      */
inLongRange(BigInteger value)326     static boolean inLongRange(BigInteger value) {
327         return value.bitLength() <= 63;
328     }
329 
330     // BEGIN Android-added: add multiplyExact(long, int) based on Math.ExactArithTests.
331 
332     /**
333      * Test StrictMath.multiplyExact method with {@code long} and {@code int} arguments.
334      */
335     @Test
testLongIntExact()336     static void testLongIntExact() {
337         testLongIntExact(0, 0);
338         testLongIntExact(1, 1);
339         testLongIntExact(1, -1);
340         testLongIntExact(1000, 2000);
341 
342         testLongIntExact(Long.MIN_VALUE, Integer.MIN_VALUE);
343         testLongIntExact(Long.MAX_VALUE, Integer.MAX_VALUE);
344         testLongIntExact(Long.MIN_VALUE, 1);
345         testLongIntExact(Long.MAX_VALUE, 1);
346         testLongIntExact(Long.MIN_VALUE, 2);
347         testLongIntExact(Long.MAX_VALUE, 2);
348         testLongIntExact(Long.MIN_VALUE, -1);
349         testLongIntExact(Long.MAX_VALUE, -1);
350         testLongIntExact(Long.MIN_VALUE, -2);
351         testLongIntExact(Long.MAX_VALUE, -2);
352         testLongIntExact(Long.MIN_VALUE / 2, 2);
353         testLongIntExact(Long.MAX_VALUE, 2);
354         testLongIntExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
355         testLongIntExact(Integer.MAX_VALUE, -Integer.MAX_VALUE);
356         testLongIntExact((long) Integer.MAX_VALUE + 1L, Integer.MAX_VALUE);
357         testLongIntExact((long) Integer.MAX_VALUE + 1L, -Integer.MAX_VALUE + 1);
358         testLongIntExact((long) Integer.MIN_VALUE - 1L, Integer.MIN_VALUE);
359         testLongIntExact((long) Integer.MIN_VALUE - 1, Integer.MAX_VALUE);
360         testLongIntExact(Integer.MIN_VALUE / 2, 2);
361     }
362 
363     /**
364      * Test long-int exact arithmetic by comparing with the same operations using BigInteger and
365      * checking that the result is the same as the long truncation. Errors are reported with {@link
366      * fail}.
367      *
368      * @param x first parameter
369      * @param y second parameter
370      */
testLongIntExact(long x, int y)371     static void testLongIntExact(long x, int y) {
372         BigInteger resultBig = null;
373         final BigInteger xBig = BigInteger.valueOf(x);
374         final BigInteger yBig = BigInteger.valueOf(y);
375 
376         try {
377             // Test multiplyExact
378             resultBig = xBig.multiply(yBig);
379             long product = StrictMath.multiplyExact(x, y);
380             checkResult("long StrictMath.multiplyExact", x, y, product, resultBig);
381         } catch (ArithmeticException ex) {
382             if (inLongRange(resultBig)) {
383                 fail("FAIL: long StrictMath.multiplyExact(" + x + " * " + y + ")"
384                         + "; Unexpected exception: " + ex);
385             }
386         }
387     }
388     // END Android-added: add multiplyExact(long, int) based on Math.ExactArithTests.
389 }