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