1 /* 2 * Copyright (c) 2020, 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.util.HexFormat; 24 25 import org.testng.annotations.DataProvider; 26 import org.testng.annotations.Test; 27 import org.testng.SkipException; 28 29 import java.io.CharArrayWriter; 30 import java.io.IOException; 31 import java.io.UncheckedIOException; 32 import java.nio.CharBuffer; 33 import java.util.Arrays; 34 import java.util.HexFormat; 35 import java.util.Locale; 36 37 import static org.testng.Assert.assertEquals; 38 import static org.testng.Assert.assertFalse; 39 import static org.testng.Assert.assertSame; 40 import static org.testng.Assert.assertThrows; 41 import static org.testng.Assert.assertTrue; 42 import static org.testng.Assert.expectThrows; 43 44 import android.platform.test.annotations.LargeTest; 45 46 /* 47 * @test 48 * @summary Check HexFormat formatting and parsing 49 * @run testng/othervm HexFormatTest 50 */ 51 52 @Test 53 // Android-changed: test methods are changed to public. static package private methods 54 // are not picked by the test runner. 55 public class HexFormatTest { 56 static final Class<NullPointerException> NPE = NullPointerException.class; 57 58 @DataProvider(name = "HexFormattersParsers") hexFormattersParsers()59 Object[][] hexFormattersParsers() { 60 return new Object[][]{ 61 {"", "", "", true, 62 HexFormat.of().withUpperCase()}, 63 {", ", "#", "L", false, 64 HexFormat.ofDelimiter(", ").withPrefix("#").withSuffix("L")}, 65 {"", "", "", false, 66 HexFormat.of().withPrefix("").withSuffix("")}, 67 {".", "", "", false, 68 HexFormat.ofDelimiter(".").withPrefix("").withSuffix("")}, 69 {", ", "0x", "", true, 70 HexFormat.ofDelimiter(", ").withUpperCase().withPrefix("0x")}, 71 {"\u0202", "\u0203", "\u0204", false, 72 HexFormat.ofDelimiter("\u0202").withPrefix("\u0203").withSuffix("\u0204")}, 73 {"\u0202", "", "", false, 74 HexFormat.ofDelimiter("\u0202")}, 75 76 }; 77 } 78 79 @DataProvider(name = "HexStringsThrowing") HexStringsThrowing()80 Object[][] HexStringsThrowing() { 81 return new Object[][]{ 82 {"0", ":", "", ""}, // wrong string length 83 {"01:", ":", "", ""}, // wrong string length 84 {"01:0", ":", "", ""}, // wrong string length 85 {"0", ",", "", ""}, // wrong length and separator 86 {"01:", ",", "", ""}, // wrong length and separator 87 {"01:0", ",", "", ""}, // wrong length and separator 88 {"01:00", ",", "", ""}, // wrong separator 89 {"00]", ",", "[", "]"}, // missing prefix 90 {"[00", ",", "[", "]"}, // missing suffix 91 {"]", ",", "[", "]"}, // missing prefix 92 {"[", ",", "[", "]"}, // missing suffix 93 {"00", ",", "abc", ""}, // Prefix longer than string 94 {"01", ",", "", "def"}, // Suffix longer than string 95 {"abc00,", ",", "abc", ""}, // Prefix and delim but not another value 96 {"01def,", ",", "", "def"}, // Suffix and delim but not another value 97 }; 98 } 99 100 @DataProvider(name = "BadBytesThrowing") badBytesThrowing()101 Object[][] badBytesThrowing() { 102 return new Object[][]{ 103 {new byte[1], 0, 2}, // bad toIndex 104 {new byte[1], 1, 2}, // bad fromIndex + toIndex 105 {new byte[1], -1, 2}, // bad fromIndex 106 {new byte[1], -1, 1}, // bad fromIndex 107 {new byte[1], 0, -1}, // bad toIndex 108 {new byte[1], 1, -1}, // bad toIndex 109 }; 110 } 111 112 @DataProvider(name = "BadParseHexThrowing") badParseHexThrowing()113 Object[][] badParseHexThrowing() { 114 return new Object[][]{ 115 {"a", 0, 2, IndexOutOfBoundsException.class}, // bad toIndex 116 {"b", 1, 2, IndexOutOfBoundsException.class}, // bad toIndex 117 {"a", -1, 2, IndexOutOfBoundsException.class}, // bad fromIndex 118 {"b", -1, 1, IndexOutOfBoundsException.class}, // bad fromIndex 119 {"a", 0, -1, IndexOutOfBoundsException.class}, // bad toIndex 120 {"b", 1, -1, IndexOutOfBoundsException.class}, // bad fromIndex + toIndex 121 {"76543210", 0, 7, IllegalArgumentException.class}, // odd number of digits 122 {"zz00", 0, 4, IllegalArgumentException.class}, // non-hex digits 123 {"00zz", 0, 4, IllegalArgumentException.class}, // non-hex digits 124 }; 125 } 126 127 @DataProvider(name = "BadFromHexDigitsThrowing") badHexDigitsThrowing()128 Object[][] badHexDigitsThrowing() { 129 return new Object[][]{ 130 {"a", 0, 2, IndexOutOfBoundsException.class}, // bad toIndex 131 {"b", 1, 2, IndexOutOfBoundsException.class}, // bad fromIndex + toIndex 132 {"a", -1, 2, IndexOutOfBoundsException.class}, // bad toIndex 133 {"b", -1, 1, IndexOutOfBoundsException.class}, // bad fromIndex + toIndex 134 {"a", 0, -1, IndexOutOfBoundsException.class}, // bad toIndex 135 {"b", 1, -1, IndexOutOfBoundsException.class}, // bad fromIndex + toIndex 136 }; 137 } 138 genBytes(int origin, int len)139 static byte[] genBytes(int origin, int len) { 140 byte[] bytes = new byte[len]; 141 for (int i = 0; i < len; i++) 142 bytes[i] = (byte) (origin + i); 143 return bytes; 144 } 145 146 @Test testToHex()147 public void testToHex() { 148 HexFormat hex = HexFormat.of(); 149 for (int i = 0; i < 32; i++) { 150 char c = hex.toLowHexDigit((byte)i); 151 String expected = Integer.toHexString(i & 0xf); 152 assertEquals(c, expected.charAt(0), "toHex formatting"); 153 } 154 } 155 156 @Test testToHexDigits()157 public void testToHexDigits() { 158 HexFormat hex = HexFormat.of(); 159 for (int i = 0; i < 256; i++) { 160 String actual = hex.toHexDigits((byte)i); 161 int expected = HexFormat.fromHexDigits(actual); 162 assertEquals(expected, i, "fromHexDigits"); 163 assertEquals(actual.charAt(0), hex.toHighHexDigit((byte)i), 164 "first char mismatch"); 165 assertEquals(actual.charAt(1), hex.toLowHexDigit((byte)i), 166 "second char mismatch"); 167 } 168 } 169 170 @Test testIsHexDigit()171 public void testIsHexDigit() { 172 for (int i = 0; i < 0x3ff; i++) { 173 boolean actual = HexFormat.isHexDigit(i); 174 boolean expected = Character.digit(i, 16) >= 0; 175 assertEquals(actual, expected, "isHexDigit: " + i); 176 } 177 } 178 179 @Test testFromHexDigit()180 public void testFromHexDigit() { 181 String chars = "0123456789ABCDEF0123456789abcdef"; 182 for (int i = 0; i < chars.length(); i++) { 183 int v = HexFormat.fromHexDigit(chars.charAt(i)); 184 assertEquals(v, i & 0xf, "fromHex decode"); 185 } 186 } 187 188 @Test testFromHexInvalid()189 public void testFromHexInvalid() { 190 for (int i = 0; i < 65536; i++) { 191 char ch = (char)i; 192 if (ch > 0xff || Character.digit(ch, 16) < 0) { 193 assertFalse(HexFormat.isHexDigit(ch), "isHexDigit incorrect for '" + ch + "' = " + i); 194 expectThrows(NumberFormatException.class, 195 () -> HexFormat.fromHexDigit(ch)); 196 197 } 198 } 199 } 200 201 @Test testAppendHexByteWithStringBuilder()202 public void testAppendHexByteWithStringBuilder() { 203 HexFormat hex = HexFormat.of(); 204 StringBuilder sb = new StringBuilder(); 205 for (int i = 0; i < 256; i++) { 206 sb.setLength(0); 207 StringBuilder sb1 = hex.toHexDigits(sb, (byte)i); 208 assertSame(sb1, sb, "toHexDigits returned different StringBuilder"); 209 assertEquals(sb.length(), 2, "wrong length after append: " + i); 210 assertEquals(sb.charAt(0), hex.toHighHexDigit((byte)i), "MSB converted wrong"); 211 assertEquals(sb.charAt(1), hex.toLowHexDigit((byte)i), "LSB converted wrong"); 212 213 assertEquals(HexFormat.fromHexDigits(sb), i, "hex.format(sb, byte) wrong"); 214 } 215 } 216 217 @Test testAppendHexByteWithCharBuffer()218 static void testAppendHexByteWithCharBuffer() { 219 HexFormat hex = HexFormat.of(); 220 CharBuffer cb = CharBuffer.allocate(256); 221 for (int i = 1; i <= 128; i++) { 222 CharBuffer cb1 = hex.toHexDigits(cb, (byte)i); 223 assertTrue(cb1 == cb); 224 assertEquals(cb.position(), i * 2); 225 } 226 assertEquals(cb.remaining(), 0); 227 } 228 229 @Test testAppendHexByteWithCharArrayWriter()230 public void testAppendHexByteWithCharArrayWriter() { 231 HexFormat hex = HexFormat.of(); 232 CharArrayWriter caw = new CharArrayWriter(); 233 for (int i = 1; i <= 128; i++) { 234 CharArrayWriter caw1 = hex.toHexDigits(caw, (byte)i); 235 assertTrue(caw1 == caw); 236 assertEquals(caw.size(), i * 2); 237 } 238 } 239 240 @Test testFromHexPairInvalid()241 public void testFromHexPairInvalid() { 242 HexFormat hex = HexFormat.of(); 243 244 // An assortment of invalid characters 245 String chars = "-0--0-"; 246 for (int i = 0; i < chars.length(); i += 2) { 247 final int ndx = i; 248 Throwable ex = expectThrows(NumberFormatException.class, 249 () -> HexFormat.fromHexDigits(chars.subSequence(ndx, ndx+2))); 250 System.out.println(ex); 251 } 252 } 253 254 @Test(dataProvider = "HexStringsThrowing") testToBytesThrowing(String value, String sep, String prefix, String suffix)255 public void testToBytesThrowing(String value, String sep, String prefix, String suffix) { 256 HexFormat hex = HexFormat.ofDelimiter(sep).withPrefix(prefix).withSuffix(suffix); 257 Throwable ex = expectThrows(IllegalArgumentException.class, 258 () -> { 259 byte[] v = hex.parseHex(value); 260 System.out.println("str: " + value + ", actual: " + v + ", bytes: " + 261 Arrays.toString(v)); 262 }); 263 System.out.println("ex: " + ex); 264 } 265 266 @Test testFactoryNPE()267 public void testFactoryNPE() { 268 assertThrows(NPE, () -> HexFormat.ofDelimiter(null)); 269 assertThrows(NPE, () -> HexFormat.of().withDelimiter(null)); 270 assertThrows(NPE, () -> HexFormat.of().withPrefix(null)); 271 assertThrows(NPE, () -> HexFormat.of().withSuffix(null)); 272 } 273 274 @Test testFormatHexNPE()275 public void testFormatHexNPE() { 276 assertThrows(NPE, () -> HexFormat.of().formatHex(null)); 277 assertThrows(NPE, () -> HexFormat.of().formatHex(null, 0, 1)); 278 assertThrows(NPE, () -> HexFormat.of().formatHex(null, null)); 279 assertThrows(NPE, () -> HexFormat.of().formatHex(null, null, 0, 0)); 280 StringBuilder sb = new StringBuilder(); 281 assertThrows(NPE, () -> HexFormat.of().formatHex(sb, null)); 282 assertThrows(NPE, () -> HexFormat.of().formatHex(sb, null, 0, 1)); 283 } 284 285 @Test testParseHexNPE()286 public void testParseHexNPE() { 287 assertThrows(NPE, () -> HexFormat.of().parseHex(null)); 288 assertThrows(NPE, () -> HexFormat.of().parseHex((String)null, 0, 0)); 289 assertThrows(NPE, () -> HexFormat.of().parseHex((char[])null, 0, 0)); 290 } 291 292 @Test testFromHexNPE()293 public void testFromHexNPE() { 294 assertThrows(NPE, () -> HexFormat.fromHexDigits(null)); 295 assertThrows(NPE, () -> HexFormat.fromHexDigits(null, 0, 0)); 296 assertThrows(NPE, () -> HexFormat.fromHexDigitsToLong(null)); 297 assertThrows(NPE, () -> HexFormat.fromHexDigitsToLong(null, 0, 0)); 298 } 299 300 @Test testToHexDigitsNPE()301 public void testToHexDigitsNPE() { 302 assertThrows(NPE, () -> HexFormat.of().toHexDigits(null, (byte)0)); 303 } 304 305 @Test(dataProvider = "BadParseHexThrowing") badParseHex(String string, int offset, int length, Class<? extends Throwable> exClass)306 public void badParseHex(String string, int offset, int length, 307 Class<? extends Throwable> exClass) { 308 assertThrows(exClass, 309 () -> HexFormat.of().parseHex(string, offset, length)); 310 char[] chars = string.toCharArray(); 311 assertThrows(exClass, 312 () -> HexFormat.of().parseHex(chars, offset, length)); 313 } 314 315 @Test(dataProvider = "BadFromHexDigitsThrowing") badFromHexDigits(String string, int fromIndex, int toIndex, Class<? extends Throwable> exClass)316 public void badFromHexDigits(String string, int fromIndex, int toIndex, 317 Class<? extends Throwable> exClass) { 318 assertThrows(exClass, 319 () -> HexFormat.fromHexDigits(string, fromIndex, toIndex)); 320 assertThrows(exClass, 321 () -> HexFormat.fromHexDigitsToLong(string, fromIndex, toIndex)); 322 } 323 324 // Verify IAE for strings that are too long for the target primitive type 325 // or the number of requested digits is too large. 326 @Test wrongNumberDigits()327 public void wrongNumberDigits() { 328 assertThrows(IllegalArgumentException.class, 329 () -> HexFormat.fromHexDigits("9876543210")); 330 assertThrows(IllegalArgumentException.class, 331 () -> HexFormat.fromHexDigits("9876543210", 0, 9)); 332 assertThrows(IllegalArgumentException.class, 333 () -> HexFormat.fromHexDigitsToLong("98765432109876543210")); 334 assertThrows(IllegalArgumentException.class, 335 () -> HexFormat.fromHexDigitsToLong("98765432109876543210", 0, 17)); 336 } 337 338 @Test(dataProvider="HexFormattersParsers") testFormatter(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat hex)339 public void testFormatter(String delimiter, String prefix, String suffix, 340 boolean uppercase, 341 HexFormat hex) { 342 byte[] expected = genBytes('A', 15); 343 String res = hex.formatHex(expected); 344 assertTrue(res.startsWith(prefix), "Prefix not found"); 345 assertTrue(res.endsWith(suffix), "Suffix not found"); 346 int expectedLen = expected.length * (2 + prefix.length() + 347 delimiter.length() + suffix.length()) - delimiter.length(); 348 assertEquals(res.length(), expectedLen, "String length"); 349 350 if (expected.length > 1) { 351 // check prefix and suffix is present for each hex pair 352 for (int i = 0; i < expected.length; i++) { 353 int valueChars = prefix.length() + 2 + suffix.length(); 354 int offset = i * (valueChars + delimiter.length()); 355 String value = res.substring(offset, offset + valueChars); 356 assertTrue(value.startsWith(prefix), "wrong prefix"); 357 assertTrue(value.endsWith(suffix), "wrong suffix"); 358 359 // Check case of digits 360 String cc = value.substring(prefix.length(), prefix.length() + 2); 361 assertEquals(cc, 362 (uppercase) ? cc.toUpperCase(Locale.ROOT) : cc.toLowerCase(Locale.ROOT), 363 "Case mismatch"); 364 if (i < expected.length - 1 && !delimiter.isEmpty()) { 365 // Check the delimiter is present for each pair except the last 366 assertEquals(res.substring(offset + valueChars, 367 offset + valueChars + delimiter.length()), delimiter); 368 } 369 } 370 } 371 } 372 373 @Test(dataProvider="HexFormattersParsers") testFormatHexString(String unused1, String unused2, String unused3, boolean unused4, HexFormat hex)374 public void testFormatHexString(String unused1, String unused2, String unused3, 375 boolean unused4, HexFormat hex) { 376 byte[] expected = genBytes('A', 15); 377 String s = hex.formatHex(expected); 378 System.out.println(" formatted: " + s); 379 380 byte[] actual = hex.parseHex(s); 381 System.out.println(" parsed as: " + Arrays.toString(actual)); 382 int mismatch = Arrays.mismatch(expected, actual); 383 assertEquals(actual, expected, "format/parse cycle failed, mismatch: " + mismatch); 384 } 385 386 @Test(dataProvider="HexFormattersParsers") testParseHexStringRange(String delimiter, String prefix, String suffix, boolean unused4, HexFormat hex)387 public void testParseHexStringRange(String delimiter, String prefix, String suffix, 388 boolean unused4, HexFormat hex) { 389 byte[] expected = genBytes('A', 15); 390 String s = hex.formatHex(expected); 391 392 // Parse values 2, 3, 4 from the generated string 393 int low = 2; 394 int high = 5; 395 int stride = prefix.length() + 2 + suffix.length() + delimiter.length(); 396 System.out.println(" formatted subrange: " + 397 s.substring(low * stride, high * stride - delimiter.length())); 398 byte[] actual = hex.parseHex(s, low * stride, 399 high * stride - delimiter.length()); 400 System.out.println(" parsed as: " + Arrays.toString(actual)); 401 402 assertEquals(actual.length, (high - low), "array length"); 403 int mismatch = Arrays.mismatch(expected, low, high, actual, 0, high - low); 404 assertEquals(mismatch, -1, "format/parse cycle failed, mismatch: " + mismatch); 405 } 406 407 @Test(dataProvider="HexFormattersParsers") testParseHexEmptyString(String delimiter, String prefix, String suffix, boolean unused4, HexFormat hex)408 public void testParseHexEmptyString(String delimiter, String prefix, String suffix, 409 boolean unused4, HexFormat hex) { 410 byte[] actual = hex.parseHex(""); 411 assertEquals(actual.length, 0, "empty string parse"); 412 actual = hex.parseHex("abc", 0, 0); 413 assertEquals(actual.length, 0, "empty string range parse"); 414 actual = hex.parseHex(new char[1], 0, 0); 415 assertEquals(actual.length, 0, "empty char array subrange empty parse"); 416 } 417 418 @Test(dataProvider="HexFormattersParsers") testFormatHexRangeString(String unused1, String unused2, String unused3, boolean unused4, HexFormat hex)419 public void testFormatHexRangeString(String unused1, String unused2, String unused3, 420 boolean unused4, HexFormat hex) { 421 byte[] expected = genBytes('A', 15); 422 int low = 1; 423 int high = expected.length - 2; 424 String s = hex.formatHex(expected, low, high); 425 System.out.println(" formatted: " + s); 426 427 byte[] actual = hex.parseHex(s); 428 System.out.println(" parsed as: " + Arrays.toString(actual)); 429 int mismatch = Arrays.mismatch(expected, low, high, actual, 0, high - low); 430 assertEquals(mismatch, -1, "format/parse cycle failed, mismatch: " + mismatch); 431 } 432 433 @Test(dataProvider="HexFormattersParsers") testFormatHexAppendable(String unused1, String unused2, String unused3, boolean unused4, HexFormat hex)434 public void testFormatHexAppendable(String unused1, String unused2, String unused3, 435 boolean unused4, HexFormat hex) { 436 byte[] expected = genBytes('A', 15); 437 StringBuilder sb = new StringBuilder(); 438 StringBuilder s = hex.formatHex(sb, expected); 439 assertEquals(s, sb, "formatHex returned unknown StringBuilder"); 440 System.out.println(" formatted: " + s); 441 442 byte[] actual = hex.parseHex(s.toString()); 443 System.out.println(" parsed as: " + Arrays.toString(actual)); 444 int mismatch = Arrays.mismatch(expected, actual); 445 assertEquals(actual, expected, "format/parse cycle failed, mismatch: " + mismatch); 446 } 447 448 @Test(dataProvider="HexFormattersParsers") testFormatHexRangeAppendable(String unused1, String unused2, String unused3, boolean unused4, HexFormat hex)449 public void testFormatHexRangeAppendable(String unused1, String unused2, String unused3, 450 boolean unused4, HexFormat hex) { 451 byte[] expected = genBytes('A', 15); 452 int low = 1; 453 int high = expected.length - 2; 454 StringBuilder sb = new StringBuilder(); 455 StringBuilder s = hex.formatHex(sb, expected, low, high); 456 assertEquals(s, sb, "formatHex returned unknown StringBuilder"); 457 System.out.println(" formatted: " + s); 458 459 byte[] actual = hex.parseHex(s.toString()); 460 System.out.println(" parsed as: " + Arrays.toString(actual)); 461 byte[] sub = Arrays.copyOfRange(expected, low, high); 462 System.out.println("actual: " + Arrays.toString(actual)); 463 System.out.println("sub : " + Arrays.toString(sub)); 464 int mismatch = Arrays.mismatch(expected, low, high, actual, 0, high - low); 465 466 assertEquals(actual, sub, "format/parse cycle failed, mismatch: " + mismatch); 467 assertEquals(mismatch, -1, "format/parse cycle failed, mismatch: " + mismatch); 468 } 469 470 @Test(dataProvider="HexFormattersParsers") testFormatHexCharArray(String unused1, String unused2, String unused3, boolean unused4, HexFormat hex)471 public void testFormatHexCharArray(String unused1, String unused2, String unused3, 472 boolean unused4, HexFormat hex) { 473 byte[] expected = genBytes('A', 15); 474 String s = hex.formatHex(expected); 475 System.out.println(" formatted: " + s); 476 477 char[] chars = s.toCharArray(); 478 byte[] actual = hex.parseHex(chars, 0, chars.length); 479 System.out.println(" parsed as: " + Arrays.toString(actual)); 480 int mismatch = Arrays.mismatch(expected, actual); 481 assertEquals(actual, expected, "format/parse cycle failed, mismatch: " + mismatch); 482 } 483 484 @Test(dataProvider="HexFormattersParsers") testFormatHexCharArrayIndexed(String delimiter, String prefix, String suffix, boolean unused4, HexFormat hex)485 public void testFormatHexCharArrayIndexed(String delimiter, String prefix, String suffix, 486 boolean unused4, HexFormat hex) { 487 byte[] expected = genBytes('A', 15); 488 String s = hex.formatHex(expected); 489 System.out.println(" formatted: " + s); 490 491 492 // Parse values 2, 3, 4 from the generated string 493 int low = 2; 494 int high = 5; 495 int stride = prefix.length() + 2 + suffix.length() + delimiter.length(); 496 System.out.println(" formatted subrange: " + 497 s.substring(low * stride, high * stride - delimiter.length())); 498 char[] chars = s.toCharArray(); 499 byte[] actual = hex.parseHex(chars, low * stride, 500 high * stride - delimiter.length()); 501 System.out.println(" parsed as: " + Arrays.toString(actual)); 502 503 assertEquals(actual.length, (high - low), "array length"); 504 int mismatch = Arrays.mismatch(expected, low, high, actual, 0, high - low); 505 assertEquals(mismatch, -1, "format/parse cycle failed, mismatch: " + mismatch); 506 } 507 508 @Test(dataProvider="HexFormattersParsers") testFormatterToString(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat hex)509 public void testFormatterToString(String delimiter, String prefix, String suffix, 510 boolean uppercase, 511 HexFormat hex) { 512 String actual = String.format( 513 "uppercase: %s, delimiter: \"%s\", prefix: \"%s\", suffix: \"%s\"", 514 uppercase, escapeNL(delimiter), escapeNL(prefix), escapeNL(suffix)); 515 System.out.println(" hex: " + actual); 516 assertEquals(actual, hex.toString(), "Formatter toString mismatch"); 517 } 518 519 @Test(dataProvider="HexFormattersParsers") testFormatterParameterMethods(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat hex)520 public void testFormatterParameterMethods(String delimiter, String prefix, String suffix, 521 boolean uppercase, 522 HexFormat hex) { 523 assertEquals(hex.delimiter(), delimiter); 524 assertEquals(hex.prefix(), prefix); 525 assertEquals(hex.suffix(), suffix); 526 assertEquals(hex.isUpperCase(), uppercase); 527 } 528 529 @Test(dataProvider="HexFormattersParsers") testFormatterTestEquals(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat expected)530 public void testFormatterTestEquals(String delimiter, String prefix, String suffix, 531 boolean uppercase, 532 HexFormat expected) { 533 HexFormat actual = HexFormat.of() 534 .withDelimiter(delimiter) 535 .withPrefix(prefix) 536 .withSuffix(suffix); 537 actual = uppercase ? actual.withUpperCase() : actual.withLowerCase(); 538 539 assertEquals(actual.delimiter(), delimiter, "delimiter"); 540 assertEquals(actual.prefix(), prefix, "prefix"); 541 assertEquals(actual.suffix(), suffix, "suffix"); 542 assertEquals(actual.isUpperCase(), uppercase, "uppercase"); 543 assertTrue(actual.equals(expected), "equals method"); 544 assertEquals(actual.hashCode(), expected.hashCode(), "hashCode"); 545 546 assertTrue(actual.equals(actual)); // equals self 547 assertFalse(actual.equals(null)); // never equals null 548 } 549 550 @Test(dataProvider="HexFormattersParsers") testZeroLength(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat hex)551 public void testZeroLength(String delimiter, String prefix, String suffix, boolean uppercase, 552 HexFormat hex) { 553 // Test formatting of zero length byte arrays, should produce no output 554 StringBuilder sb = new StringBuilder(); 555 assertEquals(hex.formatHex(new byte[0]), "", "Zero length"); 556 assertEquals(hex.formatHex(new byte[0], 0, 0), "", "Zero length"); 557 558 hex.formatHex(sb, new byte[0]); 559 assertEquals(sb.length(), 0, "length should not change"); 560 hex.formatHex(sb, new byte[0], 0, 0); 561 assertEquals(sb.length(), 0, "length should not change"); 562 563 } escapeNL(String string)564 private static String escapeNL(String string) { 565 return string.replace("\n", "\\n") 566 .replace("\r", "\\r"); 567 } 568 569 @Test testfromHexDigitsToInt()570 public void testfromHexDigitsToInt() { 571 HexFormat hex = HexFormat.of(); 572 573 String allHex = "76543210"; 574 final int orig = 0x76543210; 575 for (int digits = 0; digits <= 8; digits++) { 576 String s = hex.toHexDigits(orig, digits); 577 long actual = HexFormat.fromHexDigits(s, 0, digits); 578 System.out.printf(" digits: %2d, formatted: \"%s\", parsed as: 0x%08x%n", 579 digits, s, actual); 580 assertEquals(s, allHex.substring(8 - digits, 8)); 581 long expected = (digits < 8) ? orig & ~(0xffffffff << (4 * digits)) : orig; 582 assertEquals(actual, expected); 583 } 584 } 585 586 @Test testfromHexDigitsToLong()587 public void testfromHexDigitsToLong() { 588 HexFormat hex = HexFormat.of(); 589 590 String allHex = "fedcba9876543210"; 591 final long orig = 0xfedcba9876543210L; 592 for (int digits = 0; digits <= 16; digits++) { 593 String s = hex.toHexDigits(orig, digits); 594 long actual = HexFormat.fromHexDigitsToLong(s, 0, digits); 595 System.out.printf(" digits: %2d, formatted: \"%s\", parsed as: 0x%016xL%n", 596 digits, s, actual); 597 assertEquals(s, allHex.substring(16 - digits, 16)); 598 long expected = (digits < 16) ? orig & ~(0xffffffffffffffffL << (4 * digits)) : orig; 599 assertEquals(actual, expected); 600 } 601 } 602 603 @Test testToHexDigitsLong()604 public void testToHexDigitsLong() { 605 HexFormat hex = HexFormat.of(); 606 607 String allHex = "fedcba9876543210"; 608 final long expected = 0xfedcba9876543210L; 609 String s = hex.toHexDigits(expected); 610 long actual = HexFormat.fromHexDigitsToLong(s); 611 System.out.printf(" formatted: \"%s\", parsed as: 0x%016xL%n", s, actual); 612 assertEquals(s, allHex); 613 assertEquals(actual, expected); 614 } 615 616 @Test(dataProvider="HexFormattersParsers") testIOException(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat hex)617 public void testIOException(String delimiter, String prefix, String suffix, boolean uppercase, 618 HexFormat hex) { 619 Appendable throwingAppendable = new ThrowingAppendable(); 620 assertThrows(UncheckedIOException.class, 621 () -> hex.formatHex(throwingAppendable, new byte[1])); 622 assertThrows(UncheckedIOException.class, 623 () -> hex.formatHex(throwingAppendable, new byte[1], 0, 1)); 624 assertThrows(UncheckedIOException.class, 625 () -> hex.toHexDigits(throwingAppendable, (byte)1)); 626 } 627 628 @LargeTest 629 @Test(dataProvider="HexFormattersParsers") testOOME(String delimiter, String prefix, String suffix, boolean uppercase, HexFormat hex)630 public void testOOME(String delimiter, String prefix, String suffix, boolean uppercase, 631 HexFormat hex) { 632 // compute the size of byte array that will exceed the buffer 633 long valueChars = prefix.length() + 2 + suffix.length(); 634 long stride = valueChars + delimiter.length(); 635 long max = Integer.MAX_VALUE & 0xFFFFFFFFL; 636 long len = max / stride; 637 long remainder = max - ((len - 1) * stride); 638 if (remainder > valueChars) { 639 len++; 640 remainder -= valueChars; 641 } 642 try { 643 byte[] bytes = new byte[(int) len]; 644 Throwable ex = expectThrows(OutOfMemoryError.class, 645 () -> hex.formatHex(bytes)); 646 System.out.println("ex: " + ex); 647 } catch (OutOfMemoryError oome) { 648 System.out.printf("OOME: total mem: %08x, free mem: %08x, max mem: %08x%n", 649 Runtime.getRuntime().totalMemory(), 650 Runtime.getRuntime().freeMemory(), 651 Runtime.getRuntime().maxMemory()); 652 throw new SkipException("Insufficient Memory to test OOME"); 653 } 654 655 } 656 657 /** 658 * Example code from the HexFormat javadoc. 659 * Showing simple usage of the API using "assert" to express the correct results 660 * when shown in the javadoc. 661 * The additional TestNG asserts verify the correctness of the same code. 662 */ 663 @Test samples()664 public void samples() { 665 { 666 // Primitive formatting and parsing. 667 HexFormat hex = HexFormat.of(); 668 669 byte b = 127; 670 String byteStr = hex.toHexDigits(b); 671 System.out.println(" " + byteStr); 672 673 byte byteVal = (byte) HexFormat.fromHexDigits(byteStr); 674 assert(byteStr.equals("7f")); 675 assert(b == byteVal); 676 assertTrue(byteStr.equals("7f")); 677 assertTrue(b == byteVal); 678 679 680 char c = 'A'; 681 String charStr = hex.toHexDigits(c); 682 System.out.println(" " + charStr); 683 int charVal = HexFormat.fromHexDigits(charStr); 684 assert(c == charVal); 685 assertTrue(c == charVal); 686 687 int i = 12345; 688 String intStr = hex.toHexDigits(i); 689 System.out.println(" " + intStr); 690 int intVal = HexFormat.fromHexDigits(intStr); 691 assert(i == intVal); 692 assertTrue(i == intVal); 693 694 long l = Long.MAX_VALUE; 695 String longStr = hex.toHexDigits(l, 16); 696 long longVal = HexFormat.fromHexDigitsToLong(longStr, 0, 16); 697 System.out.println(" " + longStr + ", " + longVal); 698 assert(l == longVal); 699 assertTrue(l == longVal); 700 } 701 702 { 703 // RFC 4752 Fingerprint 704 HexFormat formatFingerprint = HexFormat.ofDelimiter(":").withUpperCase(); 705 byte[] bytes = {0, 1, 2, 3, 124, 125, 126, 127}; 706 String str = formatFingerprint.formatHex(bytes); 707 System.out.println(" Formatted: " + str); 708 709 byte[] parsed = formatFingerprint.parseHex(str); 710 System.out.println(" Parsed: " + Arrays.toString(parsed)); 711 assert(Arrays.equals(bytes, parsed)); 712 assertTrue(Arrays.equals(bytes, parsed)); 713 } 714 715 { 716 // Comma separated formatting 717 HexFormat commaFormat = HexFormat.ofDelimiter(","); 718 byte[] bytes = {0, 1, 2, 3, 124, 125, 126, 127}; 719 String str = commaFormat.formatHex(bytes); 720 System.out.println(" Formatted: " + str); 721 722 byte[] parsed = commaFormat.parseHex(str); 723 System.out.println(" Parsed: " + Arrays.toString(parsed)); 724 assert(Arrays.equals(bytes, parsed)); 725 assertTrue(Arrays.equals(bytes, parsed)); 726 } 727 { 728 // Text formatting 729 HexFormat commaFormat = HexFormat.ofDelimiter(", ").withPrefix("#"); 730 byte[] bytes = {0, 1, 2, 3, 124, 125, 126, 127}; 731 String str = commaFormat.formatHex(bytes); 732 System.out.println(" Formatted: " + str); 733 734 byte[] parsed = commaFormat.parseHex(str); 735 System.out.println(" Parsed: " + Arrays.toString(parsed)); 736 assert(Arrays.equals(bytes, parsed)); 737 assertTrue(Arrays.equals(bytes, parsed)); 738 } 739 } 740 741 /** 742 * A test implementation of Appendable that throws IOException on all methods. 743 */ 744 static class ThrowingAppendable implements Appendable { 745 @Override append(CharSequence csq)746 public Appendable append(CharSequence csq) throws IOException { 747 throw new IOException(".append(CharSequence) always throws"); 748 } 749 750 @Override append(CharSequence csq, int start, int end)751 public Appendable append(CharSequence csq, int start, int end) throws IOException { 752 throw new IOException(".append(CharSequence, start, end) always throws"); 753 } 754 755 @Override append(char c)756 public Appendable append(char c) throws IOException { 757 throw new IOException(".append(char) always throws"); 758 } 759 } 760 } 761