1 /* 2 * Copyright (c) 2012, 2017, 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 24 /** 25 * @test 26 * @bug 4235519 8004212 8005394 8007298 8006295 8006315 8006530 8007379 8008925 27 * 8014217 8025003 8026330 8028397 8129544 8165243 8176379 28 * @summary tests java.util.Base64 29 * @library /test/lib 30 * @build jdk.test.lib.RandomFactory 31 * @run main TestBase64 32 * @key randomness 33 */ 34 35 package test.java.util.Base64; 36 37 import java.io.ByteArrayInputStream; 38 import java.io.ByteArrayOutputStream; 39 import java.io.InputStream; 40 import java.io.IOException; 41 import java.io.OutputStream; 42 import java.nio.ByteBuffer; 43 import java.util.Arrays; 44 import java.util.ArrayList; 45 import java.util.Base64; 46 import java.util.List; 47 import java.util.Random; 48 49 import jdk.test.lib.RandomFactory; 50 51 public class TestBase64 { 52 53 private static final Random rnd = RandomFactory.getRandom(); 54 main(String args[])55 public static void main(String args[]) throws Throwable { 56 int numRuns = 10; 57 int numBytes = 200; 58 if (args.length > 1) { 59 numRuns = Integer.parseInt(args[0]); 60 numBytes = Integer.parseInt(args[1]); 61 } 62 63 test(Base64.getEncoder(), Base64.getDecoder(), numRuns, numBytes); 64 test(Base64.getUrlEncoder(), Base64.getUrlDecoder(), numRuns, numBytes); 65 test(Base64.getMimeEncoder(), Base64.getMimeDecoder(), numRuns, numBytes); 66 67 byte[] nl_1 = new byte[] {'\n'}; 68 byte[] nl_2 = new byte[] {'\n', '\r'}; 69 byte[] nl_3 = new byte[] {'\n', '\r', '\n'}; 70 for (int i = 0; i < 10; i++) { 71 int len = rnd.nextInt(200) + 4; 72 test(Base64.getMimeEncoder(len, nl_1), 73 Base64.getMimeDecoder(), 74 numRuns, numBytes); 75 test(Base64.getMimeEncoder(len, nl_2), 76 Base64.getMimeDecoder(), 77 numRuns, numBytes); 78 test(Base64.getMimeEncoder(len, nl_3), 79 Base64.getMimeDecoder(), 80 numRuns, numBytes); 81 } 82 83 // test mime case with < 4 length 84 for (int len = 0; len < 4; len++) { 85 test(Base64.getMimeEncoder(len, nl_1), 86 Base64.getMimeDecoder(), 87 numRuns, numBytes); 88 89 test(Base64.getMimeEncoder(len, nl_2), 90 Base64.getMimeDecoder(), 91 numRuns, numBytes); 92 93 test(Base64.getMimeEncoder(len, nl_3), 94 Base64.getMimeDecoder(), 95 numRuns, numBytes); 96 } 97 98 testNull(Base64.getEncoder()); 99 testNull(Base64.getUrlEncoder()); 100 testNull(Base64.getMimeEncoder()); 101 testNull(Base64.getMimeEncoder(10, new byte[]{'\n'})); 102 testNull(Base64.getDecoder()); 103 testNull(Base64.getUrlDecoder()); 104 testNull(Base64.getMimeDecoder()); 105 checkNull(() -> Base64.getMimeEncoder(10, null)); 106 107 testIOE(Base64.getEncoder()); 108 testIOE(Base64.getUrlEncoder()); 109 testIOE(Base64.getMimeEncoder()); 110 testIOE(Base64.getMimeEncoder(10, new byte[]{'\n'})); 111 112 byte[] src = new byte[1024]; 113 rnd.nextBytes(src); 114 final byte[] decoded = Base64.getEncoder().encode(src); 115 testIOE(Base64.getDecoder(), decoded); 116 testIOE(Base64.getMimeDecoder(), decoded); 117 testIOE(Base64.getUrlDecoder(), Base64.getUrlEncoder().encode(src)); 118 119 // illegal line separator 120 checkIAE(() -> Base64.getMimeEncoder(10, new byte[]{'\r', 'N'})); 121 122 // malformed padding/ending 123 testMalformedPadding(); 124 125 // illegal base64 character 126 decoded[2] = (byte)0xe0; 127 checkIAE(() -> Base64.getDecoder().decode(decoded)); 128 checkIAE(() -> Base64.getDecoder().decode(decoded, new byte[1024])); 129 checkIAE(() -> Base64.getDecoder().decode(ByteBuffer.wrap(decoded))); 130 131 // test single-non-base64 character for mime decoding 132 testSingleNonBase64MimeDec(); 133 134 // test decoding of unpadded data 135 testDecodeUnpadded(); 136 137 // test mime decoding with ignored character after padding 138 testDecodeIgnoredAfterPadding(); 139 140 // given invalid args, encoder should not produce output 141 testEncoderKeepsSilence(Base64.getEncoder()); 142 testEncoderKeepsSilence(Base64.getUrlEncoder()); 143 testEncoderKeepsSilence(Base64.getMimeEncoder()); 144 145 // given invalid args, decoder should not consume input 146 testDecoderKeepsAbstinence(Base64.getDecoder()); 147 testDecoderKeepsAbstinence(Base64.getUrlDecoder()); 148 testDecoderKeepsAbstinence(Base64.getMimeDecoder()); 149 } 150 test(Base64.Encoder enc, Base64.Decoder dec, int numRuns, int numBytes)151 private static void test(Base64.Encoder enc, Base64.Decoder dec, 152 int numRuns, int numBytes) throws Throwable { 153 enc.encode(new byte[0]); 154 dec.decode(new byte[0]); 155 156 for (boolean withoutPadding : new boolean[] { false, true}) { 157 if (withoutPadding) { 158 enc = enc.withoutPadding(); 159 } 160 for (int i=0; i<numRuns; i++) { 161 for (int j=1; j<numBytes; j++) { 162 byte[] orig = new byte[j]; 163 rnd.nextBytes(orig); 164 165 // --------testing encode/decode(byte[])-------- 166 byte[] encoded = enc.encode(orig); 167 byte[] decoded = dec.decode(encoded); 168 169 checkEqual(orig, decoded, 170 "Base64 array encoding/decoding failed!"); 171 if (withoutPadding) { 172 if (encoded[encoded.length - 1] == '=') 173 throw new RuntimeException( 174 "Base64 enc.encode().withoutPadding() has padding!"); 175 } 176 // --------testing encodetoString(byte[])/decode(String)-------- 177 String str = enc.encodeToString(orig); 178 if (!Arrays.equals(str.getBytes("ASCII"), encoded)) { 179 throw new RuntimeException( 180 "Base64 encodingToString() failed!"); 181 } 182 byte[] buf = dec.decode(new String(encoded, "ASCII")); 183 checkEqual(buf, orig, "Base64 decoding(String) failed!"); 184 185 //-------- testing encode/decode(Buffer)-------- 186 testEncode(enc, ByteBuffer.wrap(orig), encoded); 187 ByteBuffer bin = ByteBuffer.allocateDirect(orig.length); 188 bin.put(orig).flip(); 189 testEncode(enc, bin, encoded); 190 191 testDecode(dec, ByteBuffer.wrap(encoded), orig); 192 bin = ByteBuffer.allocateDirect(encoded.length); 193 bin.put(encoded).flip(); 194 testDecode(dec, bin, orig); 195 196 // --------testing decode.wrap(input stream)-------- 197 // 1) random buf length 198 ByteArrayInputStream bais = new ByteArrayInputStream(encoded); 199 InputStream is = dec.wrap(bais); 200 buf = new byte[orig.length + 10]; 201 int len = orig.length; 202 int off = 0; 203 while (true) { 204 int n = rnd.nextInt(len); 205 if (n == 0) 206 n = 1; 207 n = is.read(buf, off, n); 208 if (n == -1) { 209 checkEqual(off, orig.length, 210 "Base64 stream decoding failed"); 211 break; 212 } 213 off += n; 214 len -= n; 215 if (len == 0) 216 break; 217 } 218 buf = Arrays.copyOf(buf, off); 219 checkEqual(buf, orig, "Base64 stream decoding failed!"); 220 221 // 2) read one byte each 222 bais.reset(); 223 is = dec.wrap(bais); 224 buf = new byte[orig.length + 10]; 225 off = 0; 226 int b; 227 while ((b = is.read()) != -1) { 228 buf[off++] = (byte)b; 229 } 230 buf = Arrays.copyOf(buf, off); 231 checkEqual(buf, orig, "Base64 stream decoding failed!"); 232 233 // --------testing encode.wrap(output stream)-------- 234 ByteArrayOutputStream baos = new ByteArrayOutputStream((orig.length + 2) / 3 * 4 + 10); 235 OutputStream os = enc.wrap(baos); 236 off = 0; 237 len = orig.length; 238 for (int k = 0; k < 5; k++) { 239 if (len == 0) 240 break; 241 int n = rnd.nextInt(len); 242 if (n == 0) 243 n = 1; 244 os.write(orig, off, n); 245 off += n; 246 len -= n; 247 } 248 if (len != 0) 249 os.write(orig, off, len); 250 os.close(); 251 buf = baos.toByteArray(); 252 checkEqual(buf, encoded, "Base64 stream encoding failed!"); 253 254 // 2) write one byte each 255 baos.reset(); 256 os = enc.wrap(baos); 257 off = 0; 258 while (off < orig.length) { 259 os.write(orig[off++]); 260 } 261 os.close(); 262 buf = baos.toByteArray(); 263 checkEqual(buf, encoded, "Base64 stream encoding failed!"); 264 265 // --------testing encode(in, out); -> bigger buf-------- 266 buf = new byte[encoded.length + rnd.nextInt(100)]; 267 int ret = enc.encode(orig, buf); 268 checkEqual(ret, encoded.length, 269 "Base64 enc.encode(src, null) returns wrong size!"); 270 buf = Arrays.copyOf(buf, ret); 271 checkEqual(buf, encoded, 272 "Base64 enc.encode(src, dst) failed!"); 273 274 // --------testing decode(in, out); -> bigger buf-------- 275 buf = new byte[orig.length + rnd.nextInt(100)]; 276 ret = dec.decode(encoded, buf); 277 checkEqual(ret, orig.length, 278 "Base64 enc.encode(src, null) returns wrong size!"); 279 buf = Arrays.copyOf(buf, ret); 280 checkEqual(buf, orig, 281 "Base64 dec.decode(src, dst) failed!"); 282 283 } 284 } 285 } 286 } 287 288 private static final byte[] ba_null = null; 289 private static final String str_null = null; 290 private static final ByteBuffer bb_null = null; 291 testNull(Base64.Encoder enc)292 private static void testNull(Base64.Encoder enc) { 293 checkNull(() -> enc.encode(ba_null)); 294 checkNull(() -> enc.encodeToString(ba_null)); 295 checkNull(() -> enc.encode(ba_null, new byte[10])); 296 checkNull(() -> enc.encode(new byte[10], ba_null)); 297 checkNull(() -> enc.encode(bb_null)); 298 checkNull(() -> enc.wrap((OutputStream)null)); 299 } 300 testNull(Base64.Decoder dec)301 private static void testNull(Base64.Decoder dec) { 302 checkNull(() -> dec.decode(ba_null)); 303 checkNull(() -> dec.decode(str_null)); 304 checkNull(() -> dec.decode(ba_null, new byte[10])); 305 checkNull(() -> dec.decode(new byte[10], ba_null)); 306 checkNull(() -> dec.decode(bb_null)); 307 checkNull(() -> dec.wrap((InputStream)null)); 308 } 309 310 @FunctionalInterface 311 private static interface Testable { test()312 public void test() throws Throwable; 313 } 314 testIOE(Base64.Encoder enc)315 private static void testIOE(Base64.Encoder enc) throws Throwable { 316 ByteArrayOutputStream baos = new ByteArrayOutputStream(8192); 317 OutputStream os = enc.wrap(baos); 318 os.write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9}); 319 os.close(); 320 checkIOE(() -> os.write(10)); 321 checkIOE(() -> os.write(new byte[] {10})); 322 checkIOE(() -> os.write(new byte[] {10}, 1, 4)); 323 } 324 testIOE(Base64.Decoder dec, byte[] decoded)325 private static void testIOE(Base64.Decoder dec, byte[] decoded) throws Throwable { 326 ByteArrayInputStream bais = new ByteArrayInputStream(decoded); 327 InputStream is = dec.wrap(bais); 328 is.read(new byte[10]); 329 is.close(); 330 checkIOE(() -> is.read()); 331 checkIOE(() -> is.read(new byte[] {10})); 332 checkIOE(() -> is.read(new byte[] {10}, 1, 4)); 333 checkIOE(() -> is.available()); 334 checkIOE(() -> is.skip(20)); 335 } 336 checkNull(Runnable r)337 private static final void checkNull(Runnable r) { 338 try { 339 r.run(); 340 throw new RuntimeException("NPE is not thrown as expected"); 341 } catch (NullPointerException npe) {} 342 } 343 checkIOE(Testable t)344 private static final void checkIOE(Testable t) throws Throwable { 345 try { 346 t.test(); 347 throw new RuntimeException("IOE is not thrown as expected"); 348 } catch (IOException ioe) {} 349 } 350 checkIAE(Runnable r)351 private static final void checkIAE(Runnable r) throws Throwable { 352 try { 353 r.run(); 354 throw new RuntimeException("IAE is not thrown as expected"); 355 } catch (IllegalArgumentException iae) {} 356 } 357 testDecodeIgnoredAfterPadding()358 private static void testDecodeIgnoredAfterPadding() throws Throwable { 359 for (byte nonBase64 : new byte[] {'#', '(', '!', '\\', '-', '_', '\n', '\r'}) { 360 byte[][] src = new byte[][] { 361 "A".getBytes("ascii"), 362 "AB".getBytes("ascii"), 363 "ABC".getBytes("ascii"), 364 "ABCD".getBytes("ascii"), 365 "ABCDE".getBytes("ascii") 366 }; 367 Base64.Encoder encM = Base64.getMimeEncoder(); 368 Base64.Decoder decM = Base64.getMimeDecoder(); 369 Base64.Encoder enc = Base64.getEncoder(); 370 Base64.Decoder dec = Base64.getDecoder(); 371 for (int i = 0; i < src.length; i++) { 372 // decode(byte[]) 373 byte[] encoded = encM.encode(src[i]); 374 encoded = Arrays.copyOf(encoded, encoded.length + 1); 375 encoded[encoded.length - 1] = nonBase64; 376 checkEqual(decM.decode(encoded), src[i], "Non-base64 char is not ignored"); 377 byte[] decoded = new byte[src[i].length]; 378 decM.decode(encoded, decoded); 379 checkEqual(decoded, src[i], "Non-base64 char is not ignored"); 380 381 try { 382 dec.decode(encoded); 383 throw new RuntimeException("No IAE for non-base64 char"); 384 } catch (IllegalArgumentException iae) {} 385 } 386 } 387 } 388 testMalformedPadding()389 private static void testMalformedPadding() throws Throwable { 390 Object[] data = new Object[] { 391 "$=#", "", 0, // illegal ending unit 392 "A", "", 0, // dangling single byte 393 "A=", "", 0, 394 "A==", "", 0, 395 "QUJDA", "ABC", 4, 396 "QUJDA=", "ABC", 4, 397 "QUJDA==", "ABC", 4, 398 399 "=", "", 0, // unnecessary padding 400 "QUJD=", "ABC", 4, //"ABC".encode() -> "QUJD" 401 402 "AA=", "", 0, // incomplete padding 403 "QQ=", "", 0, 404 "QQ=N", "", 0, // incorrect padding 405 "QQ=?", "", 0, 406 "QUJDQQ=", "ABC", 4, 407 "QUJDQQ=N", "ABC", 4, 408 "QUJDQQ=?", "ABC", 4, 409 }; 410 411 Base64.Decoder[] decs = new Base64.Decoder[] { 412 Base64.getDecoder(), 413 Base64.getUrlDecoder(), 414 Base64.getMimeDecoder() 415 }; 416 417 for (Base64.Decoder dec : decs) { 418 for (int i = 0; i < data.length; i += 3) { 419 final String srcStr = (String)data[i]; 420 final byte[] srcBytes = srcStr.getBytes("ASCII"); 421 final ByteBuffer srcBB = ByteBuffer.wrap(srcBytes); 422 byte[] expected = ((String)data[i + 1]).getBytes("ASCII"); 423 int pos = (Integer)data[i + 2]; 424 425 // decode(byte[]) 426 checkIAE(() -> dec.decode(srcBytes)); 427 428 // decode(String) 429 checkIAE(() -> dec.decode(srcStr)); 430 431 // decode(ByteBuffer) 432 checkIAE(() -> dec.decode(srcBB)); 433 434 // wrap stream 435 checkIOE(new Testable() { 436 public void test() throws IOException { 437 try (InputStream is = dec.wrap(new ByteArrayInputStream(srcBytes))) { 438 while (is.read() != -1); 439 } 440 }}); 441 } 442 } 443 444 // anything left after padding is "invalid"/IAE, if 445 // not MIME. In case of MIME, non-base64 character(s) 446 // is ignored. 447 checkIAE(() -> Base64.getDecoder().decode("AA==\u00D2")); 448 checkIAE(() -> Base64.getUrlDecoder().decode("AA==\u00D2")); 449 Base64.getMimeDecoder().decode("AA==\u00D2"); 450 } 451 testDecodeUnpadded()452 private static void testDecodeUnpadded() throws Throwable { 453 byte[] srcA = new byte[] { 'Q', 'Q' }; 454 byte[] srcAA = new byte[] { 'Q', 'Q', 'E'}; 455 Base64.Decoder dec = Base64.getDecoder(); 456 byte[] ret = dec.decode(srcA); 457 if (ret[0] != 'A') 458 throw new RuntimeException("Decoding unpadding input A failed"); 459 ret = dec.decode(srcAA); 460 if (ret[0] != 'A' && ret[1] != 'A') 461 throw new RuntimeException("Decoding unpadding input AA failed"); 462 ret = new byte[10]; 463 if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 1 && 464 ret[0] != 'A') 465 throw new RuntimeException("Decoding unpadding input A from stream failed"); 466 if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 2 && 467 ret[0] != 'A' && ret[1] != 'A') 468 throw new RuntimeException("Decoding unpadding input AA from stream failed"); 469 } 470 471 // single-non-base64-char should be ignored for mime decoding, but 472 // iae for basic decoding testSingleNonBase64MimeDec()473 private static void testSingleNonBase64MimeDec() throws Throwable { 474 for (String nonBase64 : new String[] {"#", "(", "!", "\\", "-", "_"}) { 475 if (Base64.getMimeDecoder().decode(nonBase64).length != 0) { 476 throw new RuntimeException("non-base64 char is not ignored"); 477 } 478 try { 479 Base64.getDecoder().decode(nonBase64); 480 throw new RuntimeException("No IAE for single non-base64 char"); 481 } catch (IllegalArgumentException iae) {} 482 } 483 } 484 testEncode(Base64.Encoder enc, ByteBuffer bin, byte[] expected)485 private static final void testEncode(Base64.Encoder enc, ByteBuffer bin, byte[] expected) 486 throws Throwable { 487 488 ByteBuffer bout = enc.encode(bin); 489 byte[] buf = new byte[bout.remaining()]; 490 bout.get(buf); 491 if (bin.hasRemaining()) { 492 throw new RuntimeException( 493 "Base64 enc.encode(ByteBuffer) failed!"); 494 } 495 checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!"); 496 } 497 testDecode(Base64.Decoder dec, ByteBuffer bin, byte[] expected)498 private static final void testDecode(Base64.Decoder dec, ByteBuffer bin, byte[] expected) 499 throws Throwable { 500 501 ByteBuffer bout = dec.decode(bin); 502 byte[] buf = new byte[bout.remaining()]; 503 bout.get(buf); 504 checkEqual(buf, expected, "Base64 dec.decode(bf) failed!"); 505 } 506 checkEqual(int v1, int v2, String msg)507 private static final void checkEqual(int v1, int v2, String msg) 508 throws Throwable { 509 if (v1 != v2) { 510 System.out.printf(" v1=%d%n", v1); 511 System.out.printf(" v2=%d%n", v2); 512 throw new RuntimeException(msg); 513 } 514 } 515 checkEqual(byte[] r1, byte[] r2, String msg)516 private static final void checkEqual(byte[] r1, byte[] r2, String msg) 517 throws Throwable { 518 if (!Arrays.equals(r1, r2)) { 519 System.out.printf(" r1[%d]=[%s]%n", r1.length, new String(r1)); 520 System.out.printf(" r2[%d]=[%s]%n", r2.length, new String(r2)); 521 throw new RuntimeException(msg); 522 } 523 } 524 525 // remove line feeds, normalize(byte[] src)526 private static final byte[] normalize(byte[] src) { 527 int n = 0; 528 boolean hasUrl = false; 529 for (int i = 0; i < src.length; i++) { 530 if (src[i] == '\r' || src[i] == '\n') 531 n++; 532 if (src[i] == '-' || src[i] == '_') 533 hasUrl = true; 534 } 535 if (n == 0 && hasUrl == false) 536 return src; 537 byte[] ret = new byte[src.length - n]; 538 int j = 0; 539 for (int i = 0; i < src.length; i++) { 540 if (src[i] == '-') 541 ret[j++] = '+'; 542 else if (src[i] == '_') 543 ret[j++] = '/'; 544 else if (src[i] != '\r' && src[i] != '\n') 545 ret[j++] = src[i]; 546 } 547 return ret; 548 } 549 testEncoderKeepsSilence(Base64.Encoder enc)550 private static void testEncoderKeepsSilence(Base64.Encoder enc) 551 throws Throwable { 552 List<Integer> vals = new ArrayList<>(List.of(Integer.MIN_VALUE, 553 Integer.MIN_VALUE + 1, -1111, -2, -1, 0, 1, 2, 3, 1111, 554 Integer.MAX_VALUE - 1, Integer.MAX_VALUE)); 555 vals.addAll(List.of(rnd.nextInt(), rnd.nextInt(), rnd.nextInt(), 556 rnd.nextInt())); 557 byte[] buf = new byte[] {1, 0, 91}; 558 for (int off : vals) { 559 for (int len : vals) { 560 if (off >= 0 && len >= 0 && off <= buf.length - len) { 561 // valid args, skip them 562 continue; 563 } 564 // invalid args, test them 565 System.out.println("testing off=" + off + ", len=" + len); 566 567 ByteArrayOutputStream baos = new ByteArrayOutputStream(100); 568 try (OutputStream os = enc.wrap(baos)) { 569 os.write(buf, off, len); 570 throw new RuntimeException("Expected IOOBEx was not thrown"); 571 } catch (IndexOutOfBoundsException expected) { 572 } 573 if (baos.size() > 0) 574 throw new RuntimeException("No output was expected, but got " 575 + baos.size() + " bytes"); 576 } 577 } 578 } 579 testDecoderKeepsAbstinence(Base64.Decoder dec)580 private static void testDecoderKeepsAbstinence(Base64.Decoder dec) 581 throws Throwable { 582 List<Integer> vals = new ArrayList<>(List.of(Integer.MIN_VALUE, 583 Integer.MIN_VALUE + 1, -1111, -2, -1, 0, 1, 2, 3, 1111, 584 Integer.MAX_VALUE - 1, Integer.MAX_VALUE)); 585 vals.addAll(List.of(rnd.nextInt(), rnd.nextInt(), rnd.nextInt(), 586 rnd.nextInt())); 587 byte[] buf = new byte[3]; 588 for (int off : vals) { 589 for (int len : vals) { 590 if (off >= 0 && len >= 0 && off <= buf.length - len) { 591 // valid args, skip them 592 continue; 593 } 594 // invalid args, test them 595 System.out.println("testing off=" + off + ", len=" + len); 596 597 String input = "AAAAAAAAAAAAAAAAAAAAAA"; 598 ByteArrayInputStream bais = 599 new ByteArrayInputStream(input.getBytes("Latin1")); 600 try (InputStream is = dec.wrap(bais)) { 601 is.read(buf, off, len); 602 throw new RuntimeException("Expected IOOBEx was not thrown"); 603 } catch (IndexOutOfBoundsException expected) { 604 } 605 if (bais.available() != input.length()) 606 throw new RuntimeException("No input should be consumed, " 607 + "but consumed " + (input.length() - bais.available()) 608 + " bytes"); 609 } 610 } 611 } 612 } 613