8006295: Base64.Decoder.wrap(java.io.InputStream) returns InputStream which throws unspecified IOException on attempt to decode invalid Base64 byte stream
8006315: Base64.Decoder decoding methods are not consistent in treating non-padded data
8006530: Base64.getMimeDecoder().decode() throws exception for non-base64 character after adding =
Summary: updated the spec to describe the expected behave explicitly and the implementation to follow
Reviewed-by: alanb, chegar, lancea
diff --git a/test/java/util/Base64/TestBase64.java b/test/java/util/Base64/TestBase64.java
index 0a8eea6..e0af4de 100644
--- a/test/java/util/Base64/TestBase64.java
+++ b/test/java/util/Base64/TestBase64.java
@@ -22,7 +22,7 @@
  */
 
 /**
- * @test 4235519 8004212 8005394 8007298
+ * @test 4235519 8004212 8005394 8007298 8006295 8006315 8006530
  * @summary tests java.util.Base64
  */
 
@@ -112,6 +112,12 @@
 
         // test single-non-base64 character for mime decoding
         testSingleNonBase64MimeDec();
+
+        // test decoding of unpadded data
+        testDecodeUnpadded();
+
+        // test mime decoding with ignored character after padding
+        testDecodeIgnoredAfterPadding();
     }
 
     private static sun.misc.BASE64Encoder sunmisc = new sun.misc.BASE64Encoder();
@@ -359,6 +365,81 @@
         } catch (IllegalArgumentException iae) {}
     }
 
+    private static void testDecodeIgnoredAfterPadding() throws Throwable {
+        for (byte nonBase64 : new byte[] {'#', '(', '!', '\\', '-', '_', '\n', '\r'}) {
+            byte[][] src = new byte[][] {
+                "A".getBytes("ascii"),
+                "AB".getBytes("ascii"),
+                "ABC".getBytes("ascii"),
+                "ABCD".getBytes("ascii"),
+                "ABCDE".getBytes("ascii")
+            };
+            Base64.Encoder encM = Base64.getMimeEncoder();
+            Base64.Decoder decM = Base64.getMimeDecoder();
+            Base64.Encoder enc = Base64.getEncoder();
+            Base64.Decoder dec = Base64.getDecoder();
+            for (int i = 0; i < src.length; i++) {
+                // decode(byte[])
+                byte[] encoded = encM.encode(src[i]);
+                encoded = Arrays.copyOf(encoded, encoded.length + 1);
+                encoded[encoded.length - 1] = nonBase64;
+                checkEqual(decM.decode(encoded), src[i], "Non-base64 char is not ignored");
+                try {
+                    dec.decode(encoded);
+                    throw new RuntimeException("No IAE for non-base64 char");
+                } catch (IllegalArgumentException iae) {}
+
+                // decode(ByteBuffer[], ByteBuffer[])
+                ByteBuffer encodedBB = ByteBuffer.wrap(encoded);
+                ByteBuffer decodedBB = ByteBuffer.allocate(100);
+                int ret = decM.decode(encodedBB, decodedBB);
+                byte[] buf = new byte[ret];
+                decodedBB.flip();
+                decodedBB.get(buf);
+                checkEqual(buf, src[i], "Non-base64 char is not ignored");
+                try {
+                    encodedBB.rewind();
+                    decodedBB.clear();
+                    dec.decode(encodedBB, decodedBB);
+                    throw new RuntimeException("No IAE for non-base64 char");
+                } catch (IllegalArgumentException iae) {}
+                // direct
+                encodedBB.rewind();
+                decodedBB = ByteBuffer.allocateDirect(100);
+                ret = decM.decode(encodedBB, decodedBB);
+                buf = new byte[ret];
+                decodedBB.flip();
+                decodedBB.get(buf);
+                checkEqual(buf, src[i], "Non-base64 char is not ignored");
+                try {
+                    encodedBB.rewind();
+                    decodedBB.clear();
+                    dec.decode(encodedBB, decodedBB);
+                    throw new RuntimeException("No IAE for non-base64 char");
+                } catch (IllegalArgumentException iae) {}
+            }
+        }
+    }
+
+    private static void  testDecodeUnpadded() throws Throwable {
+        byte[] srcA = new byte[] { 'Q', 'Q' };
+        byte[] srcAA = new byte[] { 'Q', 'Q', 'E'};
+        Base64.Decoder dec = Base64.getDecoder();
+        byte[] ret = dec.decode(srcA);
+        if (ret[0] != 'A')
+            throw new RuntimeException("Decoding unpadding input A failed");
+        ret = dec.decode(srcAA);
+        if (ret[0] != 'A' && ret[1] != 'A')
+            throw new RuntimeException("Decoding unpadding input AA failed");
+        ret = new byte[10];
+        if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 1 &&
+            ret[0] != 'A')
+            throw new RuntimeException("Decoding unpadding input A from stream failed");
+        if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 2 &&
+            ret[0] != 'A' && ret[1] != 'A')
+            throw new RuntimeException("Decoding unpadding input AA from stream failed");
+    }
+
     // single-non-base64-char should be ignored for mime decoding, but
     // iae for basic decoding
     private static void testSingleNonBase64MimeDec() throws Throwable {