1 /*
2  * Copyright (c) 2009, 2012, 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.Integer;
24 
25 import org.testng.annotations.Test;
26 import org.testng.Assert;
27 
28 /*
29  * @test
30  * @bug 4504839 4215269 6322074
31  * @summary Basic tests for unsigned operations.
32  * @author Joseph D. Darcy
33  */
34 public class Unsigned {
35 
36     @Test
testRoundtrip()37     public void testRoundtrip() {
38         int[] data = {-1, 0, 1};
39 
40         for(int datum : data) {
41             Assert.assertEquals(
42                 Integer.parseUnsignedInt(Integer.toBinaryString(datum), 2),
43                 datum,
44                 "Bad binary roundtrip conversion of " + datum);
45 
46             Assert.assertEquals(Integer.parseUnsignedInt(Integer.toOctalString(datum), 8),
47                 datum,
48                 "Bad octal roundtrip conversion of " + datum);
49 
50             Assert.assertEquals(Integer.parseUnsignedInt(Integer.toHexString(datum), 16),
51                 datum,
52                 "Bad hex roundtrip conversion of " + datum);
53         }
54     }
55 
56     @Test
testByteToUnsignedInt()57     public void testByteToUnsignedInt() {
58         for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
59             byte datum = (byte) i;
60             int ui = Byte.toUnsignedInt(datum);
61 
62             if ( (ui & (~0xff)) != 0 || ((byte)ui != datum )) {
63                 Assert.fail(
64                     String.format("Bad conversion of byte %d to unsigned int %d%n", datum, ui));
65             }
66         }
67     }
68 
69     @Test
testShortToUnsignedInt()70     public void testShortToUnsignedInt() {
71         for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) {
72             short datum = (short) i;
73             int ui = Short.toUnsignedInt(datum);
74 
75             if ( (ui & (~0xffff)) != 0 || ((short)ui != datum )) {
76                 Assert.fail(
77                     String.format("Bad conversion of short %d to unsigned int %d%n", datum, ui));
78             }
79         }
80     }
81 
82     @Test
testUnsignedCompare()83     public void testUnsignedCompare() {
84         int[] data = {
85             0,
86             1,
87             2,
88             3,
89             0x8000_0000,
90             0x8000_0001,
91             0x8000_0002,
92             0x8000_0003,
93             0xFFFF_FFFE,
94             0xFFFF_FFFF,
95         };
96 
97         for(int i : data) {
98             for(int j : data) {
99                 int libraryResult    = Integer.compareUnsigned(i, j);
100                 int libraryResultRev = Integer.compareUnsigned(j, i);
101                 int localResult      = compUnsigned(i, j);
102 
103                 if (i == j) {
104                     Assert.assertEquals(libraryResult, 0,
105                         String.format("Value 0x%x did not compare as " +
106                                           "an unsigned value equal to itself; got %d%n",
107                                           i, libraryResult));
108                 }
109 
110                 Assert.assertEquals(Integer.signum(libraryResult),
111                     Integer.signum(localResult),
112                     String.format("Unsigned compare of 0x%x to 0x%x%n:" +
113                                       "\texpected sign of %d, got %d%n",
114                                       i, j, localResult, libraryResult));
115 
116                 Assert.assertEquals(Integer.signum(libraryResult),
117                     -Integer.signum(libraryResultRev),
118                     String.format("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" +
119                                       " for \t0x%x and 0x%x, computed %d and %d%n",
120                                       i, j, libraryResult, libraryResultRev));
121             }
122         }
123     }
124 
125     /**
126      * Straightforward compare unsigned algorithm.
127      */
compUnsigned(int x, int y)128     private static int compUnsigned(int x, int y) {
129         int sign_x = x & Integer.MIN_VALUE;
130         int sign_y = y & Integer.MIN_VALUE;
131 
132         int mant_x  = x & (~Integer.MIN_VALUE);
133         int mant_y  = y & (~Integer.MIN_VALUE);
134 
135         if (sign_x == sign_y)
136             return Integer.compare(mant_x, mant_y);
137         else {
138             if (sign_x == 0)
139                 return -1; // sign x is 0, sign y is 1 => (x < y)
140             else
141                 return 1; //  sign x is 1, sign y is 0 => (x > y)
142         }
143     }
144 
145     @Test
testToUnsignedLong()146     public void testToUnsignedLong() {
147         int[] data = {
148             0,
149             1,
150             2,
151             3,
152             0x1234_5678,
153             0x8000_0000,
154             0x8000_0001,
155             0x8000_0002,
156             0x8000_0003,
157             0x8765_4321,
158             0xFFFF_FFFE,
159             0xFFFF_FFFF,
160         };
161 
162         for(int datum : data) {
163             long result = Integer.toUnsignedLong(datum);
164 
165             // High-order bits should be zero
166             Assert.assertEquals(
167                 (result & 0xffff_ffff_0000_0000L),
168                 0L,
169                 String.format("High bits set converting 0x%x to 0x%x%n", datum, result));
170 
171             // Lower-order bits should be equal to datum.
172             int lowOrder = (int)(result & 0x0000_0000_ffff_ffffL);
173             Assert.assertEquals(lowOrder, datum,
174                 String.format("Low bits not preserved converting 0x%x to 0x%x%n", datum, result));
175         }
176     }
177 
178     @Test
testToStringUnsigned()179     public void testToStringUnsigned() {
180         int[] data = {
181             0,
182             1,
183             2,
184             3,
185             99999,
186             100000,
187             999999,
188             100000,
189             999999999,
190             1000000000,
191             0x1234_5678,
192             0x8000_0000,
193             0x8000_0001,
194             0x8000_0002,
195             0x8000_0003,
196             0x8765_4321,
197             0xFFFF_FFFE,
198             0xFFFF_FFFF,
199         };
200 
201         for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
202             for(int datum : data) {
203                 String result1 = Integer.toUnsignedString(datum, radix);
204                 String result2 = Long.toString(Integer.toUnsignedLong(datum), radix);
205 
206                 if (!result1.equals(result2)) {
207                     Assert.fail(String.format("Unexpected string difference converting 0x%x:" +
208                                       "\t%s %s%n",
209                                       datum, result1, result2));
210                 }
211 
212                 if (radix == 10) {
213                     String result3 = Integer.toUnsignedString(datum);
214                     if (!result2.equals(result3)) {
215                         Assert.fail(String.format("Unexpected string difference converting 0x%x:" +
216                                           "\t%s %s%n",
217                                           datum, result3, result2));
218                     }
219                 }
220 
221                 int parseResult = Integer.parseUnsignedInt(result1, radix);
222 
223                 if (parseResult != datum) {
224                     Assert.fail(String.format("Bad roundtrip conversion of %d in base %d" +
225                                           "\tconverting back ''%s'' resulted in %d%n",
226                                           datum, radix, result1,  parseResult));
227                 }
228             }
229         }
230     }
231 
232     private static final long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
233 
234     @Test
testParseUnsignedInt()235     public void testParseUnsignedInt() {
236         // Values include those between signed Integer.MAX_VALUE and
237         // unsignted int MAX_VALUE.
238         long[] inRange = {
239             0L,
240             1L,
241             10L,
242             2147483646L,   // MAX_VALUE - 1
243             2147483647L,   // MAX_VALUE
244             2147483648L,   // MAX_VALUE + 1
245 
246             MAX_UNSIGNED_INT - 1L,
247             MAX_UNSIGNED_INT,
248         };
249 
250         for(long value : inRange) {
251             for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
252                 String longString = Long.toString(value, radix);
253                 int intResult = Integer.parseUnsignedInt(longString, radix);
254 
255                 if (Integer.toUnsignedLong(intResult) != value) {
256                     Assert.fail(String.format("Bad roundtrip conversion of %d in base %d" +
257                                       "\tconverting back ''%s'' resulted in %d%n",
258                                       value, radix, longString,  intResult));
259                 }
260 
261                 // test offset based parse method
262                 intResult = Integer.parseUnsignedInt("prefix" + longString + "suffix",
263                         "prefix".length(), "prefix".length() + longString.length(), radix);
264 
265                 if (Integer.toUnsignedLong(intResult) != value) {
266                     Assert.fail(String.format("Bad roundtrip conversion of %d in base %d" +
267                             "\tconverting back ''%s'' resulted in %d%n",
268                             value, radix, longString,  intResult));
269                 }
270             }
271         }
272 
273         String[] outOfRange = {
274             null,
275             "",
276             "-1",
277             Long.toString(MAX_UNSIGNED_INT + 1L),
278             Long.toString(Long.MAX_VALUE)
279         };
280 
281         for(String s : outOfRange) {
282             try {
283                 int result = Integer.parseUnsignedInt(s);
284                 Assert.fail(
285                     String.format("Unexpected got %d from an unsigned conversion of %s", result, s));
286             } catch(NumberFormatException nfe) {
287                 ; // Correct result
288             }
289         }
290     }
291 
292     @Test
testDivideAndRemainder()293     public void testDivideAndRemainder() {
294         long[] inRange = {
295             0L,
296             1L,
297             2L,
298             2147483646L,   // MAX_VALUE - 1
299             2147483647L,   // MAX_VALUE
300             2147483648L,   // MAX_VALUE + 1
301 
302             MAX_UNSIGNED_INT - 1L,
303             MAX_UNSIGNED_INT,
304         };
305 
306         for(long dividend : inRange) {
307             for(long divisor : inRange) {
308                 int quotient;
309                 long longQuotient;
310 
311                 int remainder;
312                 long longRemainder;
313 
314                 if (divisor == 0) {
315                     try {
316                         quotient = Integer.divideUnsigned((int) dividend, (int) divisor);
317                         Assert.fail("Unexpectedly did not throw");
318                     } catch(ArithmeticException ea) {
319                         ; // Expected
320                     }
321 
322                     try {
323                         remainder = Integer.remainderUnsigned((int) dividend, (int) divisor);
324                         Assert.fail("Unexpectedly did not throw");
325                     } catch(ArithmeticException ea) {
326                         ; // Expected
327                     }
328                 } else {
329                     quotient = Integer.divideUnsigned((int) dividend, (int) divisor);
330                     longQuotient = dividend / divisor;
331 
332                     if (quotient != (int)longQuotient) {
333                         Assert.fail(String.format("Unexpected unsigned divide result %s on %s/%s%n",
334                                           Integer.toUnsignedString(quotient),
335                                           Integer.toUnsignedString((int) dividend),
336                                           Integer.toUnsignedString((int) divisor)));
337                     }
338 
339                     remainder = Integer.remainderUnsigned((int) dividend, (int) divisor);
340                     longRemainder = dividend % divisor;
341 
342                     if (remainder != (int)longRemainder) {
343                         Assert.fail(String.format("Unexpected unsigned remainder result %s on %s%%%s%n",
344                                           Integer.toUnsignedString(remainder),
345                                           Integer.toUnsignedString((int) dividend),
346                                           Integer.toUnsignedString((int) divisor)));
347                     }
348                 }
349             }
350         }
351     }
352 }
353