1 /*
   2  * Copyright (c) 2012, 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 4235519
  26  * @author Eric Wang <yiming.wang@oracle.com>
  27  * @summary tests java.util.Base64
  28  */
  29 
  30 import java.io.BufferedReader;
  31 import java.io.FileReader;
  32 import java.nio.ByteBuffer;
  33 import java.nio.charset.Charset;
  34 import java.nio.charset.StandardCharsets;
  35 import java.nio.file.Files;
  36 import java.nio.file.Paths;
  37 import java.util.Base64;
  38 import java.util.Base64.Decoder;
  39 import java.util.Base64.Encoder;
  40 import java.util.Objects;
  41 import java.util.Random;
  42 
  43 import sun.misc.BASE64Decoder;
  44 import sun.misc.BASE64Encoder;
  45 
  46 public class TestBase64Golden {
  47 
  48     public static void main(String[] args) throws Exception {
  49         test0(Base64Type.BASIC, Base64.getEncoder(), Base64.getDecoder(),
  50               "plain.txt", "baseEncode.txt");
  51 
  52         test0(Base64Type.URLSAFE, Base64.getUrlEncoder(), Base64.getUrlDecoder(),
  53               "plain.txt", "urlEncode.txt");
  54 
  55         test0(Base64Type.MIME, Base64.getMimeEncoder(), Base64.getMimeDecoder(),
  56               "plain.txt", "mimeEncode.txt");
  57         test1();
  58         test2();
  59     }
  60 
  61     public static void test0(Base64Type type, Encoder encoder, Decoder decoder,
  62                              String srcFile, String encodedFile) throws Exception {
  63 
  64         String[] srcLns = Files.readAllLines(Paths.get(SRCDIR, srcFile), DEF_CHARSET)
  65                                .toArray(new String[0]);
  66         String[] encodedLns = Files.readAllLines(Paths.get(SRCDIR, encodedFile),
  67                                                  DEF_CHARSET)
  68                                    .toArray(new String[0]);
  69         int lns = 0;
  70         for (String srcStr : srcLns) {
  71             String encodedStr = null;
  72             if (type != Base64Type.MIME) {
  73                 encodedStr = encodedLns[lns++];
  74             } else {
  75                 while (lns < encodedLns.length) {
  76                     String s = encodedLns[lns++];
  77                     if (s.length() == 0)
  78                         break;
  79                     if (encodedStr != null) {
  80                         encodedStr += DEFAULT_CRLF + s;
  81                     } else {
  82                         encodedStr = s;
  83                     }
  84                 }
  85                 if (encodedStr == null && srcStr.length() == 0) {
  86                     encodedStr = "";
  87                 }
  88             }
  89             System.out.printf("%n    src[%d]: %s%n", srcStr.length(), srcStr);
  90             System.out.printf("encoded[%d]: %s%n", encodedStr.length(), encodedStr);
  91 
  92             byte[] srcArr = srcStr.getBytes(DEF_CHARSET);
  93             byte[] encodedArr = encodedStr.getBytes(DEF_CHARSET);
  94 
  95             ByteBuffer srcBuf = ByteBuffer.wrap(srcArr);
  96             ByteBuffer encodedBuf = ByteBuffer.wrap(encodedArr);
  97             byte[] resArr = new byte[encodedArr.length];
  98 
  99             // test int encode(byte[], byte[])
 100             int len = encoder.encode(srcArr, resArr);
 101             assertEqual(len, encodedArr.length);
 102             assertEqual(resArr, encodedArr);
 103 
 104             // test byte[] encode(byte[])
 105             resArr = encoder.encode(srcArr);
 106             assertEqual(resArr, encodedArr);
 107 
 108             // test ByteBuffer encode(ByteBuffer)
 109             int limit = srcBuf.limit();
 110             ByteBuffer resBuf = encoder.encode(srcBuf);
 111             assertEqual(srcBuf.position(), limit);
 112             assertEqual(srcBuf.limit(), limit);
 113             assertEqual(resBuf, encodedBuf);
 114             srcBuf.rewind(); // reset for next test
 115 
 116             // test encode(ByteBuffer, ByteBuffer, bytesOut)
 117             resBuf.clear();
 118             len = encoder.encode(srcBuf, resBuf, 0);
 119             assertEqual(len, encodedArr.length);
 120             assertEqual(srcBuf.position(), limit);
 121             assertEqual(srcBuf.limit(), limit);
 122             assertEqual(resBuf.position(), len);
 123             resBuf.flip();
 124             assertEqual(resBuf, encodedBuf);
 125             srcBuf.rewind();
 126 
 127             // test encode(ByteBuffer, ByteBuffer, bytesOut)[direct]
 128             ByteBuffer resBuf_d = ByteBuffer.allocateDirect(encodedArr.length);
 129             len = encoder.encode(srcBuf, resBuf_d, 0);
 130             assertEqual(len, encodedArr.length);
 131             assertEqual(srcBuf.position(), limit);
 132             assertEqual(srcBuf.limit(), limit);
 133             assertEqual(resBuf_d.position(), len);
 134             resBuf_d.flip();
 135             assertEqual(resBuf_d, encodedBuf);
 136             srcBuf.rewind();
 137 
 138             // test String encodeToString(byte[])
 139             String resEncodeStr = encoder.encodeToString(srcArr);
 140             assertEqual(resEncodeStr, encodedStr);
 141 
 142             // test int decode(byte[], byte[])
 143             resArr = new byte[srcArr.length];
 144             len = decoder.decode(encodedArr, resArr);
 145             assertEqual(len, srcArr.length);
 146             assertEqual(resArr, srcArr);
 147 
 148             // test byte[] decode(byte[])
 149             resArr = decoder.decode(encodedArr);
 150             assertEqual(resArr, srcArr);
 151 
 152             // test ByteBuffer decode(ByteBuffer)
 153             limit = encodedBuf.limit();
 154             resBuf = decoder.decode(encodedBuf);
 155             assertEqual(encodedBuf.position(), limit);
 156             assertEqual(encodedBuf.limit(), limit);
 157             assertEqual(resBuf, srcBuf);
 158             encodedBuf.rewind(); // reset for next test
 159 
 160             // test int decode(ByteBuffer, ByteBuffer)
 161             resBuf.clear();
 162             len = decoder.decode(encodedBuf, resBuf);
 163             assertEqual(len, srcArr.length);
 164             assertEqual(encodedBuf.position(), limit);
 165             assertEqual(encodedBuf.limit(), limit);
 166             assertEqual(resBuf.position(), len);
 167             resBuf.flip();
 168             assertEqual(resBuf, srcBuf);
 169             encodedBuf.rewind(); // reset for next test
 170 
 171             // test int decode(ByteBuffer, ByteBuffer)[direct]
 172             resBuf_d = ByteBuffer.allocateDirect(srcArr.length);
 173             len = decoder.decode(encodedBuf, resBuf_d);
 174             assertEqual(len, srcArr.length);
 175             assertEqual(encodedBuf.position(), limit);
 176             assertEqual(encodedBuf.limit(), limit);
 177             assertEqual(resBuf_d.position(), len);
 178             resBuf_d.flip();
 179             assertEqual(resBuf_d, srcBuf);
 180             encodedBuf.rewind(); // reset for next test
 181 
 182             // test byte[] decode(String)
 183             resArr = decoder.decode(encodedStr);
 184             assertEqual(resArr, srcArr);
 185 
 186             // test compatible with sun.misc.Base64Encoder
 187             if (type == Base64Type.MIME) {
 188                 sun.misc.BASE64Encoder miscEncoder = new BASE64Encoder();
 189                 sun.misc.BASE64Decoder miscDecoder = new BASE64Decoder();
 190                 resArr = decoder.decode(miscEncoder.encode(srcArr));
 191                 assertEqual(resArr, srcArr);
 192 
 193                 resArr = encoder.encode(miscDecoder.decodeBuffer(encodedStr));
 194                 assertEqual(new String(resArr, DEF_CHARSET), encodedStr);
 195             }
 196         }
 197     }
 198 
 199     private static void test1() throws Exception {
 200         byte[] src = new byte[6];
 201         new Random().nextBytes(src);
 202 
 203         ByteBuffer srcBuf = ByteBuffer.allocate(10);
 204         srcBuf.position(2);
 205         srcBuf.mark();
 206         srcBuf.limit(8);
 207         srcBuf.put(src);
 208         srcBuf.reset();
 209 
 210         ByteBuffer dstBuf = ByteBuffer.allocate((src.length + 2) / 3 * 4);
 211         Base64.getEncoder().encode(srcBuf, dstBuf, 0);
 212         dstBuf.rewind();
 213         byte[] dst = new byte[dstBuf.limit()];
 214         dstBuf.get(dst);
 215         System.out.printf("%n    src[%d]: %s%n", src.length, new String(src));
 216         System.out.printf("encoded[%d]: %s%n",   dst.length, new String(dst));
 217         assertEqual(src, Base64.getDecoder().decode(dst));
 218 
 219         dstBuf = ByteBuffer.allocateDirect((src.length + 2) / 3 * 4);
 220         srcBuf.reset();
 221         Base64.getEncoder().encode(srcBuf, dstBuf, 0);
 222         dstBuf.rewind();
 223         dst = new byte[dstBuf.limit()];
 224         dstBuf.get(dst);
 225         assertEqual(src, Base64.getDecoder().decode(dst));
 226     }
 227 
 228     private static void test2() throws Exception {
 229         byte[] src = new byte[] {
 230             46, -97, -35, -44, 127, -60, -39, -4, -112, 34, -57, 47, -14, 67,
 231             40, 18, 90, -59, 68, 112, 23, 121, -91, 94, 35, 49, 104, 17, 30,
 232             -80, -104, -3, -53, 27, 38, -72, -47, 113, -52, 18, 5, -126 };
 233         Encoder encoder = Base64.getMimeEncoder(49, new byte[] { 0x7e });
 234         byte[] encoded = encoder.encode(src);
 235         Decoder decoder = Base64.getMimeDecoder();
 236         byte[] decoded = decoder.decode(encoded);
 237         if (!Objects.deepEquals(src, decoded)) {
 238             throw new RuntimeException();
 239         }
 240     }
 241 
 242     // helper
 243     enum Base64Type {
 244         BASIC, URLSAFE, MIME
 245     }
 246 
 247     private static final String SRCDIR = System.getProperty("test.src", ".");
 248     private static final Charset DEF_CHARSET = StandardCharsets.US_ASCII;
 249     private static final String DEF_EXCEPTION_MSG =
 250         "Assertion failed! The result is not same as expected";
 251     private static final String DEFAULT_CRLF = "\r\n";
 252 
 253     private static void assertEqual(Object result, Object expect) {
 254         if (!Objects.deepEquals(result, expect)) {
 255             String resultStr = result.toString();
 256             String expectStr = expect.toString();
 257             if (result instanceof byte[]) {
 258                 resultStr = new String((byte[]) result, DEF_CHARSET);
 259             }
 260             if (expect instanceof byte[]) {
 261                 expectStr = new String((byte[]) expect, DEF_CHARSET);
 262             }
 263             throw new RuntimeException(DEF_EXCEPTION_MSG +
 264                 " result: " + resultStr + " expected: " + expectStr);
 265         }
 266     }
 267 }