1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.java.lang; 18 19 import static org.junit.Assert.*; 20 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.junit.runners.JUnit4; 24 25 import java.lang.invoke.MethodHandle; 26 import java.lang.invoke.MethodHandles; 27 import java.lang.invoke.MethodType; 28 import java.util.Properties; 29 30 @RunWith(JUnit4.class) 31 public class IntegerTest { 32 static final int[] INT_VALUES = {0, 1, 23, 456, 0x7fff_ffff, 0x8000_0000, 0xffff_ffff}; 33 34 static final long[] LONG_VALUES = { 35 0x1_0000_0000L, (long) Integer.MIN_VALUE - 1L, Long.MIN_VALUE, Long.MAX_VALUE 36 }; 37 38 @Test testSystemProperties()39 public void testSystemProperties() { 40 Properties originalProperties = System.getProperties(); 41 try { 42 Properties testProperties = new Properties(); 43 testProperties.put("testIncInt", "notInt"); 44 System.setProperties(testProperties); 45 assertNull("returned incorrect default Integer", Integer.getInteger("testIncInt")); 46 assertEquals(new Integer(4), Integer.getInteger("testIncInt", 4)); 47 assertEquals(new Integer(4), Integer.getInteger("testIncInt", new Integer(4))); 48 } finally { 49 System.setProperties(originalProperties); 50 } 51 } 52 53 @Test testCompare()54 public void testCompare() throws Exception { 55 final int min = Integer.MIN_VALUE; 56 final int zero = 0; 57 final int max = Integer.MAX_VALUE; 58 assertTrue(Integer.compare(max, max) == 0); 59 assertTrue(Integer.compare(min, min) == 0); 60 assertTrue(Integer.compare(zero, zero) == 0); 61 assertTrue(Integer.compare(max, zero) > 0); 62 assertTrue(Integer.compare(max, min) > 0); 63 assertTrue(Integer.compare(zero, max) < 0); 64 assertTrue(Integer.compare(zero, min) > 0); 65 assertTrue(Integer.compare(min, zero) < 0); 66 assertTrue(Integer.compare(min, max) < 0); 67 } 68 69 @Test 70 public void testParseInt() throws Exception { 71 assertEquals(0, Integer.parseInt("+0", 10)); 72 assertEquals(473, Integer.parseInt("+473", 10)); 73 assertEquals(255, Integer.parseInt("+FF", 16)); 74 assertEquals(102, Integer.parseInt("+1100110", 2)); 75 assertEquals(2147483647, Integer.parseInt("+2147483647", 10)); 76 assertEquals(411787, Integer.parseInt("Kona", 27)); 77 assertEquals(411787, Integer.parseInt("+Kona", 27)); 78 assertEquals(-145, Integer.parseInt("-145", 10)); 79 80 // multiple sign chars 81 assertThrows(NumberFormatException.class, () -> Integer.parseInt("--1", 10)); 82 assertThrows(NumberFormatException.class, () -> Integer.parseInt("++1", 10)); 83 84 // base too small 85 assertThrows(NumberFormatException.class, () -> Integer.parseInt("Kona", 10)); 86 } 87 88 @Test testDecodeInt()89 public void testDecodeInt() throws Exception { 90 assertEquals(0, Integer.decode("+0").intValue()); 91 assertEquals(473, Integer.decode("+473").intValue()); 92 assertEquals(255, Integer.decode("+0xFF").intValue()); 93 assertEquals(16, Integer.decode("+020").intValue()); 94 assertEquals(2147483647, Integer.decode("+2147483647").intValue()); 95 assertEquals(-73, Integer.decode("-73").intValue()); 96 assertEquals(-255, Integer.decode("-0xFF").intValue()); 97 assertEquals(255, Integer.decode("+#FF").intValue()); 98 assertEquals(-255, Integer.decode("-#FF").intValue()); 99 100 assertThrows(NumberFormatException.class, () -> Integer.decode("--1")); 101 assertThrows(NumberFormatException.class, () -> Integer.decode("++1")); 102 assertThrows(NumberFormatException.class, () -> Integer.decode("-+1")); 103 assertThrows(NumberFormatException.class, () -> Integer.decode("Kona")); 104 } 105 106 /* 107 public void testParsePositiveInt() throws Exception { 108 assertEquals(0, Integer.parsePositiveInt("0", 10)); 109 assertEquals(473, Integer.parsePositiveInt("473", 10)); 110 assertEquals(255, Integer.parsePositiveInt("FF", 16)); 111 112 try { 113 Integer.parsePositiveInt("-1", 10); 114 fail(); 115 } catch (NumberFormatException e) {} 116 117 try { 118 Integer.parsePositiveInt("+1", 10); 119 fail(); 120 } catch (NumberFormatException e) {} 121 122 try { 123 Integer.parsePositiveInt("+0", 16); 124 fail(); 125 } catch (NumberFormatException e) {} 126 } 127 */ 128 129 @Test testStaticHashCode()130 public void testStaticHashCode() { 131 assertEquals(Integer.valueOf(567).hashCode(), Integer.hashCode(567)); 132 } 133 134 @Test testMax()135 public void testMax() { 136 int a = 567; 137 int b = 578; 138 assertEquals(Math.max(a, b), Integer.max(a, b)); 139 } 140 141 @Test testMin()142 public void testMin() { 143 int a = 567; 144 int b = 578; 145 assertEquals(Math.min(a, b), Integer.min(a, b)); 146 } 147 148 @Test testSum()149 public void testSum() { 150 int a = 567; 151 int b = 578; 152 assertEquals(a + b, Integer.sum(a, b)); 153 } 154 155 @Test testBYTES()156 public void testBYTES() { 157 assertEquals(4, Integer.BYTES); 158 } 159 160 @Test testCompareUnsigned()161 public void testCompareUnsigned() { 162 for (int i = 0; i < INT_VALUES.length; ++i) { 163 for (int j = 0; j < INT_VALUES.length; ++j) { 164 assertEquals( 165 Integer.compare(i, j), 166 Integer.compareUnsigned(INT_VALUES[i], INT_VALUES[j])); 167 } 168 } 169 } 170 171 @Test testDivideAndRemainderUnsigned()172 public void testDivideAndRemainderUnsigned() { 173 long[] vals = {1L, 23L, 456L, 0x7fff_ffffL, 0x8000_0000L, 0xffff_ffffL}; 174 175 for (long dividend : vals) { 176 for (long divisor : vals) { 177 int uq = Integer.divideUnsigned((int) dividend, (int) divisor); 178 int ur = Integer.remainderUnsigned((int) dividend, (int) divisor); 179 assertEquals((int) (dividend / divisor), uq); 180 assertEquals((int) (dividend % divisor), ur); 181 assertEquals((int) dividend, uq * (int) divisor + ur); 182 } 183 } 184 185 for (long dividend : vals) { 186 assertThrows( 187 ArithmeticException.class, () -> Integer.divideUnsigned((int) dividend, 0)); 188 assertThrows( 189 ArithmeticException.class, () -> Integer.remainderUnsigned((int) dividend, 0)); 190 } 191 } 192 193 @Test testParseUnsignedInt()194 public void testParseUnsignedInt() { 195 for (int value : INT_VALUES) { 196 // Special radices 197 assertEquals(value, Integer.parseUnsignedInt(Integer.toBinaryString(value), 2)); 198 assertEquals(value, Integer.parseUnsignedInt(Integer.toOctalString(value), 8)); 199 assertEquals(value, Integer.parseUnsignedInt(Integer.toUnsignedString(value))); 200 assertEquals(value, Integer.parseUnsignedInt(Integer.toHexString(value), 16)); 201 202 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; ++radix) { 203 assertEquals( 204 value, 205 Integer.parseUnsignedInt(Integer.toUnsignedString(value, radix), radix)); 206 } 207 } 208 209 for (long longValue : LONG_VALUES) { 210 // Special radices 211 assertThrows( 212 NumberFormatException.class, 213 () -> Integer.parseUnsignedInt(Long.toBinaryString(longValue), 2)); 214 assertThrows( 215 NumberFormatException.class, 216 () -> Integer.parseUnsignedInt(Long.toOctalString(longValue), 8)); 217 assertThrows( 218 NumberFormatException.class, 219 () -> Integer.parseUnsignedInt(Long.toUnsignedString(longValue), 10)); 220 assertThrows( 221 NumberFormatException.class, 222 () -> Integer.parseUnsignedInt(Long.toHexString(longValue), 16)); 223 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; ++radix) { 224 final int r = radix; 225 assertThrows( 226 NumberFormatException.class, 227 () -> Integer.parseUnsignedInt(Long.toUnsignedString(longValue, r), r)); 228 } 229 } 230 231 assertThrows(NumberFormatException.class, () -> Integer.parseUnsignedInt("-1")); 232 assertThrows(NumberFormatException.class, () -> Integer.parseUnsignedInt("123", 2)); 233 assertThrows(NumberFormatException.class, () -> Integer.parseUnsignedInt(null)); 234 assertThrows( 235 NumberFormatException.class, 236 () -> Integer.parseUnsignedInt("0", Character.MAX_RADIX + 1)); 237 assertThrows( 238 NumberFormatException.class, 239 () -> Integer.parseUnsignedInt("0", Character.MIN_RADIX - 1)); 240 } 241 242 @Test testParseUnsignedIntSubstring()243 public void testParseUnsignedIntSubstring() { 244 final String LEFT = "1"; 245 final String RIGHT = "0"; 246 247 for (int ii = 0; ii < 8; ii = 2 * ii + 1) { 248 for (int jj = 0; jj < 8; jj = 2 * jj + 1) { 249 final int i = ii; // final for use in lambdas 250 final int j = jj; // final for use in lambdas 251 final String leftPad = LEFT.repeat(i); 252 final String rightPad = RIGHT.repeat(j); 253 for (int value : INT_VALUES) { 254 String binary = leftPad + Integer.toBinaryString(value) + rightPad; 255 assertEquals( 256 value, Integer.parseUnsignedInt(binary, i, binary.length() - j, 2)); 257 258 String octal = leftPad + Integer.toOctalString(value) + rightPad; 259 assertEquals(value, Integer.parseUnsignedInt(octal, i, octal.length() - j, 8)); 260 261 String denary = leftPad + Integer.toUnsignedString(value) + rightPad; 262 assertEquals( 263 value, Integer.parseUnsignedInt(denary, i, denary.length() - j, 10)); 264 265 String hex = leftPad + Integer.toHexString(value) + rightPad; 266 assertEquals(value, Integer.parseUnsignedInt(hex, i, hex.length() - j, 16)); 267 268 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; ++radix) { 269 String arb = leftPad + Integer.toUnsignedString(value, radix) + rightPad; 270 assertEquals( 271 value, Integer.parseUnsignedInt(arb, i, arb.length() - j, radix)); 272 } 273 } 274 275 for (long large_value : LONG_VALUES) { 276 { 277 final String input = leftPad + Long.toBinaryString(large_value) + rightPad; 278 assertThrows( 279 NumberFormatException.class, 280 () -> Integer.parseUnsignedInt(input, i, input.length() - j, 2)); 281 } 282 { 283 final String input = leftPad + Long.toOctalString(large_value) + rightPad; 284 assertThrows( 285 NumberFormatException.class, 286 () -> Integer.parseUnsignedInt(input, i, input.length() - j, 8)); 287 } 288 { 289 final String input = 290 leftPad + Long.toUnsignedString(large_value) + rightPad; 291 assertThrows( 292 NumberFormatException.class, 293 () -> Integer.parseUnsignedInt(input, i, input.length() - j, 10)); 294 } 295 { 296 final String input = leftPad + Long.toHexString(large_value) + rightPad; 297 assertThrows( 298 NumberFormatException.class, 299 () -> Integer.parseUnsignedInt(input, i, input.length() - j, 16)); 300 } 301 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; ++radix) { 302 final int r = radix; 303 String input = 304 leftPad + Long.toUnsignedString(large_value, radix) + rightPad; 305 assertThrows( 306 NumberFormatException.class, 307 () -> Integer.parseUnsignedInt(input, i, input.length() - j, r)); 308 } 309 } 310 } 311 } 312 313 assertThrows( 314 IndexOutOfBoundsException.class, () -> Integer.parseUnsignedInt("123", -1, 3, 10)); 315 assertThrows( 316 IndexOutOfBoundsException.class, () -> Integer.parseUnsignedInt("123", 4, 5, 10)); 317 assertThrows( 318 IndexOutOfBoundsException.class, () -> Integer.parseUnsignedInt("123", 2, 1, 10)); 319 assertThrows( 320 IndexOutOfBoundsException.class, () -> Integer.parseUnsignedInt("123", 2, 4, 10)); 321 assertThrows(NumberFormatException.class, () -> Integer.parseUnsignedInt("-1", 0, 2, 10)); 322 assertThrows(NumberFormatException.class, () -> Integer.parseUnsignedInt("123", 0, 3, 2)); 323 assertThrows( 324 NumberFormatException.class, 325 () -> Integer.parseUnsignedInt("0", 0, 1, Character.MAX_RADIX + 1)); 326 assertThrows( 327 NumberFormatException.class, 328 () -> Integer.parseUnsignedInt("0", 0, 1, Character.MIN_RADIX - 1)); 329 assertThrows(NullPointerException.class, () -> Integer.parseUnsignedInt(null, 0, 1, 10)); 330 } 331 332 @Test testToUnsignedLong()333 public void testToUnsignedLong() { 334 for (int val : INT_VALUES) { 335 long ul = Integer.toUnsignedLong(val); 336 assertEquals(0, ul >>> Integer.BYTES * 8); 337 assertEquals(val, (int) ul); 338 } 339 } 340 341 @Test testToUnsignedString()342 public void testToUnsignedString() { 343 for (int val : INT_VALUES) { 344 // Special radices 345 assertTrue(Integer.toUnsignedString(val, 2).equals(Integer.toBinaryString(val))); 346 assertTrue(Integer.toUnsignedString(val, 8).equals(Integer.toOctalString(val))); 347 assertTrue(Integer.toUnsignedString(val, 10).equals(Integer.toUnsignedString(val))); 348 assertTrue(Integer.toUnsignedString(val, 16).equals(Integer.toHexString(val))); 349 350 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; ++radix) { 351 assertTrue( 352 Integer.toUnsignedString(val, radix) 353 .equals(Long.toString(Integer.toUnsignedLong(val), radix))); 354 } 355 356 // Behavior is not defined by Java API specification if the radix falls outside of valid 357 // range, thus we don't test for such cases. 358 } 359 } 360 361 @Test testParseUnsignedIntSubstringForBackports()362 public void testParseUnsignedIntSubstringForBackports() { 363 // Rudimentary test to register coverage on older branches where we may see backports for 364 // OpenJDK 11 methods (b/191859202). NB using Integer_parseUnsignedInt rather than 365 // Integer.parseUnsignedInt. 366 assertEquals( 367 0xaa55aa55, 368 Integer_parseUnsignedInt("left10101010010101011010101001010101right", 4, 36, 2)); 369 assertEquals(8003, Integer_parseUnsignedInt("left17503right", 4, 9, 8)); 370 assertEquals(0xffff_ffff, Integer_parseUnsignedInt("left4294967295right", 4, 14, 10)); 371 assertEquals(0x1234_5678, Integer_parseUnsignedInt("lefty12345678righty", 5, 13, 16)); 372 } 373 374 /** 375 * Parses an unsigned integer using a {@code MethodHandle} to invoke {@code 376 * Integer.parseUnsignedInt}. 377 * 378 * @param val the {@code CharSequence} to be parsed. 379 * @param start the starting index in {@code val}. 380 * @param end the ending ing index in {@code val}, exclusive. 381 * @param radix the radix to parse {@code val} with. 382 * @return the parsed unsigned integer. 383 */ Integer_parseUnsignedInt(CharSequence val, int start, int end, int radix)384 private static int Integer_parseUnsignedInt(CharSequence val, int start, int end, int radix) { 385 try { 386 MethodType parseUnsignedIntType = 387 MethodType.methodType( 388 int.class, CharSequence.class, int.class, int.class, int.class); 389 MethodHandle parseUnsignedInt = 390 MethodHandles.lookup() 391 .findStatic(Integer.class, "parseUnsignedInt", parseUnsignedIntType); 392 return (int) parseUnsignedInt.invokeExact(val, start, end, radix); 393 } catch (IndexOutOfBoundsException | NullPointerException | NumberFormatException e) { 394 // Expected exceptions from the target method during the tests here. 395 throw e; 396 } catch (Throwable t) { 397 // Everything else. 398 throw new RuntimeException(t); 399 } 400 } 401 } 402