View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.binary;
19  
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  import static org.junit.jupiter.api.Assertions.fail;
28  
29  import java.math.BigInteger;
30  import java.nio.charset.Charset;
31  import java.nio.charset.StandardCharsets;
32  import java.util.Arrays;
33  import java.util.Random;
34  
35  import org.apache.commons.codec.CodecPolicy;
36  import org.apache.commons.codec.DecoderException;
37  import org.apache.commons.codec.EncoderException;
38  import org.apache.commons.lang3.ArrayUtils;
39  import org.junit.jupiter.api.Assumptions;
40  import org.junit.jupiter.api.Test;
41  
42  /**
43   * Test cases for Base64 class.
44   *
45   * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
46   */
47  public class Base64Test {
48  
49      private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;
50  
51      /**
52       * Example test cases with valid characters but impossible combinations of
53       * trailing characters (i.e. cannot be created during encoding).
54       */
55      static final String[] BASE64_IMPOSSIBLE_CASES = {
56          "ZE==",
57          "ZmC=",
58          "Zm9vYE==",
59          "Zm9vYmC=",
60          "AB",
61      };
62  
63      /**
64       * Copy of the standard base-64 encoding table. Used to test decoding the final
65       * character of encoded bytes.
66       */
67      private static final byte[] STANDARD_ENCODE_TABLE = {
68              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
69              'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
70              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
71              'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
72              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
73      };
74  
75      /**
76       * Test base 64 decoding of the final trailing bits. Trailing encoded bytes
77       * cannot fit exactly into 6-bit characters so the last character has a limited
78       * alphabet where the final bits are zero. This asserts that illegal final
79       * characters throw an exception when decoding.
80       *
81       * @param nbits the number of trailing bits (must be a factor of 6 and {@code <24})
82       */
83      private static void assertBase64DecodingOfTrailingBits(final int nbits) {
84          final Base64 codec = new Base64(0, null, false, CodecPolicy.STRICT);
85          // Requires strict decoding
86          assertTrue(codec.isStrictDecoding());
87          assertEquals(CodecPolicy.STRICT, codec.getCodecPolicy());
88          // A lenient decoder should not re-encode to the same bytes
89          final Base64 defaultCodec = new Base64();
90          assertFalse(defaultCodec.isStrictDecoding());
91          assertEquals(CodecPolicy.LENIENT, defaultCodec.getCodecPolicy());
92  
93          // Create the encoded bytes. The first characters must be valid so fill with 'zero'
94          // then pad to the block size.
95          final int length = nbits / 6;
96          final byte[] encoded = new byte[4];
97          Arrays.fill(encoded, 0, length, STANDARD_ENCODE_TABLE[0]);
98          Arrays.fill(encoded, length, encoded.length, (byte) '=');
99          // Compute how many bits would be discarded from 8-bit bytes
100         final int discard = nbits % 8;
101         final int emptyBitsMask = (1 << discard) - 1;
102         // Special case when an impossible number of trailing characters
103         final boolean invalid = length == 1;
104         // Enumerate all 64 possible final characters in the last position
105         final int last = length - 1;
106         for (int i = 0; i < 64; i++) {
107             encoded[last] = STANDARD_ENCODE_TABLE[i];
108             // If the lower bits are set we expect an exception. This is not a valid
109             // final character.
110             if (invalid || (i & emptyBitsMask) != 0) {
111                 assertThrows(IllegalArgumentException.class, () -> codec.decode(encoded),
112                         "Final base-64 digit should not be allowed");
113                 // The default lenient mode should decode this
114                 final byte[] decoded = defaultCodec.decode(encoded);
115                 // Re-encoding should not match the original array as it was invalid
116                 assertFalse(Arrays.equals(encoded, defaultCodec.encode(decoded)));
117             } else {
118                 // Otherwise this should decode
119                 final byte[] decoded = codec.decode(encoded);
120                 // Compute the bits that were encoded. This should match the final decoded byte.
121                 final int bitsEncoded = i >> discard;
122                 assertEquals(bitsEncoded, decoded[decoded.length - 1], "Invalid decoding of last character");
123                 // Re-encoding should match the original array (requires the same padding character)
124                 assertArrayEquals(encoded, codec.encode(decoded));
125             }
126         }
127     }
128 
129     private final Random random = new Random();
130 
131     /**
132      * @return Returns the random.
133      */
134     public Random getRandom() {
135         return this.random;
136     }
137 
138     /**
139      * Test the Base64 implementation
140      */
141     @Test
142     public void testBase64() {
143         final String content = "Hello World";
144         String encodedContent;
145         byte[] encodedBytes = Base64.encodeBase64(StringUtils.getBytesUtf8(content));
146         encodedContent = StringUtils.newStringUtf8(encodedBytes);
147         assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
148 
149         Base64 b64 = new Base64(BaseNCodec.MIME_CHUNK_SIZE, null); // null
150                                                                     // lineSeparator
151                                                                     // same as
152                                                                     // saying
153                                                                     // no-chunking
154         encodedBytes = b64.encode(StringUtils.getBytesUtf8(content));
155         encodedContent = StringUtils.newStringUtf8(encodedBytes);
156         assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
157 
158         b64 = new Base64(0, null); // null lineSeparator same as saying
159                                     // no-chunking
160         encodedBytes = b64.encode(StringUtils.getBytesUtf8(content));
161         encodedContent = StringUtils.newStringUtf8(encodedBytes);
162         assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
163 
164         // bogus characters to decode (to skip actually) {e-acute*6}
165         final byte[] decode = b64.decode("SGVsbG{\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9}8gV29ybGQ=");
166         final String decodeString = StringUtils.newStringUtf8(decode);
167         assertEquals("Hello World", decodeString, "decode hello world");
168     }
169 
170     @Test
171     public void testBase64AtBufferEnd() {
172         testBase64InBuffer(100, 0);
173     }
174 
175     @Test
176     public void testBase64AtBufferMiddle() {
177         testBase64InBuffer(100, 100);
178     }
179 
180     @Test
181     public void testBase64AtBufferStart() {
182         testBase64InBuffer(0, 100);
183     }
184 
185     @Test
186     public void testBase64DecodingOfTrailing12Bits() {
187         assertBase64DecodingOfTrailingBits(12);
188     }
189 
190     @Test
191     public void testBase64DecodingOfTrailing18Bits() {
192         assertBase64DecodingOfTrailingBits(18);
193     }
194 
195     @Test
196     public void testBase64DecodingOfTrailing6Bits() {
197         assertBase64DecodingOfTrailingBits(6);
198     }
199 
200     @Test
201     public void testBase64ImpossibleSamples() {
202         final Base64 codec = new Base64(0, null, false, CodecPolicy.STRICT);
203         for (final String s : BASE64_IMPOSSIBLE_CASES) {
204             assertThrows(IllegalArgumentException.class, () -> codec.decode(s));
205         }
206     }
207 
208     private void testBase64InBuffer(final int startPasSize, final int endPadSize) {
209         final String content = "Hello World";
210         final String encodedContent;
211         final byte[] bytesUtf8 = StringUtils.getBytesUtf8(content);
212         byte[] buffer = ArrayUtils.addAll(bytesUtf8, new byte[endPadSize]);
213         buffer = ArrayUtils.addAll(new byte[startPasSize], buffer);
214         final byte[] encodedBytes = new Base64().encode(buffer, startPasSize, bytesUtf8.length);
215         encodedContent = StringUtils.newStringUtf8(encodedBytes);
216         assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
217     }
218 
219     @Test
220     public void testByteToStringVariations() throws DecoderException {
221         final Base64 base64 = new Base64(0);
222         final byte[] b1 = StringUtils.getBytesUtf8("Hello World");
223         final byte[] b2 = {};
224         final byte[] b3 = null;
225         final byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090"); // for url-safe tests
226 
227         assertEquals("SGVsbG8gV29ybGQ=", base64.encodeToString(b1), "byteToString Hello World");
228         assertEquals("SGVsbG8gV29ybGQ=", Base64.encodeBase64String(b1), "byteToString static Hello World");
229         assertEquals("", base64.encodeToString(b2), "byteToString \"\"");
230         assertEquals("", Base64.encodeBase64String(b2), "byteToString static \"\"");
231         assertNull(base64.encodeToString(b3), "byteToString null");
232         assertNull(Base64.encodeBase64String(b3), "byteToString static null");
233         assertEquals("K/fMJwH+Q5e0nr7tWsxwkA==", base64.encodeToString(b4), "byteToString UUID");
234         assertEquals("K/fMJwH+Q5e0nr7tWsxwkA==", Base64.encodeBase64String(b4), "byteToString static UUID");
235         assertEquals("K_fMJwH-Q5e0nr7tWsxwkA", Base64.encodeBase64URLSafeString(b4), "byteToString static-url-safe UUID");
236     }
237 
238     /**
239      * Tests Base64.encodeBase64().
240      */
241     @Test
242     public void testChunkedEncodeMultipleOf76() {
243         final byte[] expectedEncode = Base64.encodeBase64(BaseNTestData.DECODED, true);
244         // convert to "\r\n" so we're equal to the old openssl encoding test
245         // stored
246         // in Base64TestData.ENCODED_76_CHARS_PER_LINE:
247         final String actualResult = Base64TestData.ENCODED_76_CHARS_PER_LINE.replace("\n", "\r\n");
248         final byte[] actualEncode = StringUtils.getBytesUtf8(actualResult);
249         assertArrayEquals(expectedEncode, actualEncode, "chunkedEncodeMultipleOf76");
250     }
251 
252     @Test
253     public void testCodec112() { // size calculation assumes always chunked
254         final byte[] in = { 0 };
255         final byte[] out = Base64.encodeBase64(in);
256         Base64.encodeBase64(in, false, false, out.length);
257         // TODO Assert??
258     }
259 
260     /**
261      * Test for CODEC-265: Encode a 1GiB file.
262      *
263      * @see <a href="https://issues.apache.org/jira/projects/CODEC/issues/CODEC-265">CODEC-265</a>
264      */
265     @Test
266     public void testCodec265() {
267         // 1GiB file to encode: 2^30 bytes
268         final int size1GiB = 1 << 30;
269 
270         // Expecting a size of 4 output bytes per 3 input bytes plus the trailing bytes
271         // padded to a block size of 4.
272         final int blocks = (int) Math.ceil(size1GiB / 3.0);
273         final int expectedLength = 4 * blocks;
274 
275         // This test is memory hungry. Check we can run it.
276         final long presumableFreeMemory = BaseNCodecTest.getPresumableFreeMemory();
277 
278         // Estimate the maximum memory required:
279         // 1GiB + 1GiB + ~2GiB + ~1.33GiB + 32 KiB  = ~5.33GiB
280         //
281         // 1GiB: Input buffer to encode
282         // 1GiB: Existing working buffer (due to doubling of default buffer size of 8192)
283         // ~2GiB: New working buffer to allocate (due to doubling)
284         // ~1.33GiB: Expected output size (since the working buffer is copied at the end)
285         // 32KiB: Some headroom
286         final long estimatedMemory = (long) size1GiB * 4 + expectedLength + 32 * 1024;
287         Assumptions.assumeTrue(presumableFreeMemory > estimatedMemory,
288                 "Not enough free memory for the test");
289 
290         final byte[] bytes = new byte[size1GiB];
291         final byte[] encoded = Base64.encodeBase64(bytes);
292         assertEquals(expectedLength, encoded.length);
293     }
294 
295     /**
296      * CODEC-68: isBase64 throws ArrayIndexOutOfBoundsException on some
297      * non-BASE64 bytes
298      */
299     @Test
300     public void testCodec68() {
301         final byte[] x = { 'n', 'A', '=', '=', (byte) 0x9c };
302         Base64.decodeBase64(x);
303     }
304 
305     @Test
306     public void testCodeInteger1() {
307         final String encodedInt1 = "li7dzDacuo67Jg7mtqEm2TRuOMU=";
308         final BigInteger bigInt1 = new BigInteger("85739377120809420210425962799" + "0318636601332086981");
309 
310         assertEquals(encodedInt1, new String(Base64.encodeInteger(bigInt1)));
311         assertEquals(bigInt1, Base64.decodeInteger(encodedInt1.getBytes(CHARSET_UTF8)));
312     }
313 
314     @Test
315     public void testCodeInteger2() {
316         final String encodedInt2 = "9B5ypLY9pMOmtxCeTDHgwdNFeGs=";
317         final BigInteger bigInt2 = new BigInteger("13936727572861167254666467268" + "91466679477132949611");
318 
319         assertEquals(encodedInt2, new String(Base64.encodeInteger(bigInt2)));
320         assertEquals(bigInt2, Base64.decodeInteger(encodedInt2.getBytes(CHARSET_UTF8)));
321     }
322 
323     @Test
324     public void testCodeInteger3() {
325         final String encodedInt3 = "FKIhdgaG5LGKiEtF1vHy4f3y700zaD6QwDS3IrNVGzNp2" +
326             "rY+1LFWTK6D44AyiC1n8uWz1itkYMZF0/aKDK0Yjg==";
327         final BigInteger bigInt3 = new BigInteger(
328             "10806548154093873461951748545" +
329             "1196989136416448805819079363524309897749044958112417136240557" +
330             "4495062430572478766856090958495998158114332651671116876320938126");
331 
332         assertEquals(encodedInt3, new String(Base64.encodeInteger(bigInt3)));
333         assertEquals(bigInt3, Base64.decodeInteger(encodedInt3.getBytes(CHARSET_UTF8)));
334     }
335 
336     @Test
337     public void testCodeInteger4() {
338         final String encodedInt4 = "ctA8YGxrtngg/zKVvqEOefnwmViFztcnPBYPlJsvh6yKI" +
339             "4iDm68fnp4Mi3RrJ6bZAygFrUIQLxLjV+OJtgJAEto0xAs+Mehuq1DkSFEpP3o" +
340             "DzCTOsrOiS1DwQe4oIb7zVk/9l7aPtJMHW0LVlMdwZNFNNJoqMcT2ZfCPrfvYv" +
341             "Q0=";
342         final BigInteger bigInt4 = new BigInteger("80624726256040348115552042320" +
343             "6968135001872753709424419772586693950232350200555646471175944" +
344             "519297087885987040810778908507262272892702303774422853675597" +
345             "748008534040890923814202286633163248086055216976551456088015" +
346             "338880713818192088877057717530169381044092839402438015097654" +
347             "53542091716518238707344493641683483917");
348 
349         assertEquals(encodedInt4, new String(Base64.encodeInteger(bigInt4)));
350         assertEquals(bigInt4, Base64.decodeInteger(encodedInt4.getBytes(CHARSET_UTF8)));
351     }
352 
353     @Test
354     public void testCodeIntegerEdgeCases() {
355         // TODO
356     }
357 
358     @Test
359     public void testCodeIntegerNull() {
360         assertThrows(NullPointerException.class, () -> Base64.encodeInteger(null),
361                 "Exception not thrown when passing in null to encodeInteger(BigInteger)");
362     }
363 
364     @Test
365     public void testConstructor_Int_ByteArray_Boolean() {
366         final Base64 base64 = new Base64(65, new byte[] { '\t' }, false);
367         final byte[] encoded = base64.encode(BaseNTestData.DECODED);
368         String expectedResult = Base64TestData.ENCODED_64_CHARS_PER_LINE;
369         expectedResult = expectedResult.replace('\n', '\t');
370         final String result = StringUtils.newStringUtf8(encoded);
371         assertEquals(expectedResult, result, "new Base64(65, \\t, false)");
372     }
373 
374     @Test
375     public void testConstructor_Int_ByteArray_Boolean_UrlSafe() {
376         // url-safe variation
377         final Base64 base64 = new Base64(64, new byte[] { '\t' }, true);
378         final byte[] encoded = base64.encode(BaseNTestData.DECODED);
379         String expectedResult = Base64TestData.ENCODED_64_CHARS_PER_LINE;
380         expectedResult = expectedResult.replace("=", ""); // url-safe has no
381                                                                 // == padding.
382         expectedResult = expectedResult.replace('\n', '\t');
383         expectedResult = expectedResult.replace('+', '-');
384         expectedResult = expectedResult.replace('/', '_');
385         final String result = StringUtils.newStringUtf8(encoded);
386         assertEquals(result, expectedResult, "new Base64(64, \\t, true)");
387     }
388 
389     @Test
390     public void testConstructors() {
391         Base64 base64;
392         base64 = new Base64();
393         base64 = new Base64(-1);
394         base64 = new Base64(-1, new byte[] {});
395         base64 = new Base64(64, new byte[] {});
396         base64 = new Base64(64, new byte[] {'$'}); // OK
397 
398         assertThrows(IllegalArgumentException.class, () -> new Base64(-1, new byte[] { 'A' }),
399                 "Should have rejected attempt to use 'A' as a line separator");
400         // TODO do we need to check sep if len = -1?
401 
402         assertThrows(IllegalArgumentException.class, () -> new Base64(64, new byte[] { 'A' }),
403                 "Should have rejected attempt to use 'A' as a line separator");
404 
405         assertThrows(IllegalArgumentException.class, () -> new Base64(64, new byte[] { '=' }),
406                 "Should have rejected attempt to use '=' as a line separator");
407 
408         base64 = new Base64(64, new byte[] { '$' }); // OK
409 
410         assertThrows(IllegalArgumentException.class, () -> new Base64(64, new byte[] { 'A', '$' }),
411                 "Should have rejected attempt to use 'A$' as a line separator");
412 
413         base64 = new Base64(64, new byte[] { ' ', '$', '\n', '\r', '\t' }); // OK
414 
415         assertNotNull(base64);
416     }
417 
418     private void testDecodeEncode(final String encodedText) {
419         final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText));
420         final String encodedText2 = Base64.encodeBase64String(StringUtils.getBytesUtf8(decodedText));
421         assertEquals(encodedText, encodedText2);
422     }
423 
424     /**
425      * Tests conditional true branch for "marker0" test.
426      */
427     @Test
428     public void testDecodePadMarkerIndex2() {
429         assertEquals("A", new String(Base64.decodeBase64("QQ==".getBytes(CHARSET_UTF8))));
430     }
431 
432     /**
433      * Tests conditional branches for "marker1" test.
434      */
435     @Test
436     public void testDecodePadMarkerIndex3() {
437         assertEquals("AA", new String(Base64.decodeBase64("QUE=".getBytes(CHARSET_UTF8))));
438         assertEquals("AAA", new String(Base64.decodeBase64("QUFB".getBytes(CHARSET_UTF8))));
439     }
440 
441     @Test
442     public void testDecodePadOnly() {
443         assertEquals(0, Base64.decodeBase64("====".getBytes(CHARSET_UTF8)).length);
444         assertEquals("", new String(Base64.decodeBase64("====".getBytes(CHARSET_UTF8))));
445         // Test truncated padding
446         assertEquals(0, Base64.decodeBase64("===".getBytes(CHARSET_UTF8)).length);
447         assertEquals(0, Base64.decodeBase64("==".getBytes(CHARSET_UTF8)).length);
448         assertEquals(0, Base64.decodeBase64("=".getBytes(CHARSET_UTF8)).length);
449         assertEquals(0, Base64.decodeBase64("".getBytes(CHARSET_UTF8)).length);
450     }
451 
452     @Test
453     public void testDecodePadOnlyChunked() {
454         assertEquals(0, Base64.decodeBase64("====\n".getBytes(CHARSET_UTF8)).length);
455         assertEquals("", new String(Base64.decodeBase64("====\n".getBytes(CHARSET_UTF8))));
456         // Test truncated padding
457         assertEquals(0, Base64.decodeBase64("===\n".getBytes(CHARSET_UTF8)).length);
458         assertEquals(0, Base64.decodeBase64("==\n".getBytes(CHARSET_UTF8)).length);
459         assertEquals(0, Base64.decodeBase64("=\n".getBytes(CHARSET_UTF8)).length);
460         assertEquals(0, Base64.decodeBase64("\n".getBytes(CHARSET_UTF8)).length);
461     }
462 
463     /**
464      * Test our decode with pad character in the middle. (Our current
465      * implementation: halt decode and return what we've got so far).
466      *
467      * The point of this test is not to say
468      * "this is the correct way to decode base64." The point is simply to keep
469      * us aware of the current logic since 1.4 so we don't accidentally break it
470      * without realizing.
471      *
472      * Note for historians. The 1.3 logic would decode to:
473      * "Hello World\u0000Hello World" -- null in the middle --- and 1.4
474      * unwittingly changed it to current logic.
475      */
476     @Test
477     public void testDecodeWithInnerPad() {
478         final String content = "SGVsbG8gV29ybGQ=SGVsbG8gV29ybGQ=";
479         final byte[] result = Base64.decodeBase64(content);
480         final byte[] shouldBe = StringUtils.getBytesUtf8("Hello World");
481         assertArrayEquals(result, shouldBe, "decode should halt at pad (=)");
482     }
483 
484     @Test
485     public void testDecodeWithWhitespace() throws Exception {
486 
487         final String orig = "I am a late night coder.";
488 
489         final byte[] encodedArray = Base64.encodeBase64(orig.getBytes(CHARSET_UTF8));
490         final StringBuilder intermediate = new StringBuilder(new String(encodedArray));
491 
492         intermediate.insert(2, ' ');
493         intermediate.insert(5, '\t');
494         intermediate.insert(10, '\r');
495         intermediate.insert(15, '\n');
496 
497         final byte[] encodedWithWS = intermediate.toString().getBytes(CHARSET_UTF8);
498         final byte[] decodedWithWS = Base64.decodeBase64(encodedWithWS);
499 
500         final String dest = new String(decodedWithWS);
501 
502         assertEquals(orig, dest, "Dest string doesn't equal the original");
503     }
504 
505     /**
506      * Test encode and decode of empty byte array.
507      */
508     @Test
509     public void testEmptyBase64() {
510         byte[] empty = {};
511         byte[] result = Base64.encodeBase64(empty);
512         assertEquals(0, result.length, "empty base64 encode");
513         assertNull(Base64.encodeBase64(null), "empty base64 encode");
514         result = new Base64().encode(empty, 0, 1);
515         assertEquals(0, result.length, "empty base64 encode");
516         assertNull(new Base64().encode(null, 0, 1), "empty base64 encode");
517 
518         empty = new byte[0];
519         result = Base64.decodeBase64(empty);
520         assertEquals(0, result.length, "empty base64 decode");
521         assertNull(Base64.decodeBase64((byte[]) null), "empty base64 encode");
522     }
523 
524     private void testEncodeDecode(final String plainText) {
525         final String encodedText = Base64.encodeBase64String(StringUtils.getBytesUtf8(plainText));
526         final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText));
527         assertEquals(plainText, decodedText);
528     }
529 
530     // encode/decode a large random array
531     @Test
532     public void testEncodeDecodeRandom() {
533         for (int i = 1; i < 5; i++) {
534             final byte[] data = new byte[this.getRandom().nextInt(10000) + 1];
535             this.getRandom().nextBytes(data);
536             final byte[] enc = Base64.encodeBase64(data);
537             assertTrue(Base64.isBase64(enc));
538             final byte[] data2 = Base64.decodeBase64(enc);
539             assertArrayEquals(data, data2);
540         }
541     }
542 
543     // encode/decode random arrays from size 0 to size 11
544     @Test
545     public void testEncodeDecodeSmall() {
546         for (int i = 0; i < 12; i++) {
547             final byte[] data = new byte[i];
548             this.getRandom().nextBytes(data);
549             final byte[] enc = Base64.encodeBase64(data);
550             assertTrue(Base64.isBase64(enc), "\"" + new String(enc) + "\" is Base64 data.");
551             final byte[] data2 = Base64.decodeBase64(enc);
552             assertArrayEquals(data, data2, toString(data) + " equals " + toString(data2));
553         }
554     }
555 
556     @Test
557     public void testEncodeOverMaxSize() throws Exception {
558         testEncodeOverMaxSize(-1);
559         testEncodeOverMaxSize(0);
560         testEncodeOverMaxSize(1);
561         testEncodeOverMaxSize(2);
562     }
563 
564     private void testEncodeOverMaxSize(final int maxSize) {
565         assertThrows(IllegalArgumentException.class, () -> Base64.encodeBase64(BaseNTestData.DECODED, true, false, maxSize));
566     }
567 
568     /**
569      * Tests a lineSeparator much bigger than DEFAULT_BUFFER_SIZE.
570      *
571      * @see "<a href='https://mail-archives.apache.org/mod_mbox/commons-dev/201202.mbox/%3C4F3C85D7.5060706@snafu.de%3E'>dev@commons.apache.org</a>"
572      */
573     @Test
574     public void testHugeLineSeparator() {
575         final int BaseNCodec_DEFAULT_BUFFER_SIZE = 8192;
576         final int Base64_BYTES_PER_ENCODED_BLOCK = 4;
577         final byte[] baLineSeparator = new byte[BaseNCodec_DEFAULT_BUFFER_SIZE * 4 - 3];
578         final Base64 b64 = new Base64(Base64_BYTES_PER_ENCODED_BLOCK, baLineSeparator);
579         final String strOriginal = "Hello World";
580         final String strDecoded = new String(b64.decode(b64.encode(StringUtils.getBytesUtf8(strOriginal))));
581         assertEquals(strOriginal, strDecoded, "testDEFAULT_BUFFER_SIZE");
582     }
583 
584     @Test
585     public void testIgnoringNonBase64InDecode() throws Exception {
586         assertEquals("The quick brown fox jumped over the lazy dogs.",
587                 new String(Base64.decodeBase64(
588                         "VGhlIH@$#$@%F1aWN@#@#@@rIGJyb3duIGZve\n\r\t%#%#%#%CBqd##$#$W1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg=="
589                                 .getBytes(CHARSET_UTF8))));
590     }
591 
592     @Test
593     public void testIsArrayByteBase64() {
594         assertFalse(Base64.isBase64(new byte[] { Byte.MIN_VALUE }));
595         assertFalse(Base64.isBase64(new byte[] { -125 }));
596         assertFalse(Base64.isBase64(new byte[] { -10 }));
597         assertFalse(Base64.isBase64(new byte[] { 0 }));
598         assertFalse(Base64.isBase64(new byte[] { 64, Byte.MAX_VALUE }));
599         assertFalse(Base64.isBase64(new byte[] { Byte.MAX_VALUE }));
600 
601         assertTrue(Base64.isBase64(new byte[] { 'A' }));
602 
603         assertFalse(Base64.isBase64(new byte[] { 'A', Byte.MIN_VALUE }));
604 
605         assertTrue(Base64.isBase64(new byte[] { 'A', 'Z', 'a' }));
606         assertTrue(Base64.isBase64(new byte[] { '/', '=', '+' }));
607 
608         assertFalse(Base64.isBase64(new byte[] { '$' }));
609     }
610 
611     /**
612      * Test the isStringBase64 method.
613      */
614     @Test
615     public void testIsStringBase64() {
616         final String nullString = null;
617         final String emptyString = "";
618         final String validString = "abc===defg\n\r123456\r789\r\rABC\n\nDEF==GHI\r\nJKL==============";
619         final String invalidString = validString + (char) 0; // append null character
620 
621         assertThrows(NullPointerException.class, () -> Base64.isBase64(nullString),
622                 "Base64.isStringBase64() should not be null-safe.");
623 
624         assertTrue(Base64.isBase64(emptyString), "Base64.isStringBase64(empty-string) is true");
625         assertTrue(Base64.isBase64(validString), "Base64.isStringBase64(valid-string) is true");
626         assertFalse(Base64.isBase64(invalidString), "Base64.isStringBase64(invalid-string) is false");
627     }
628 
629     /**
630      * Tests isUrlSafe.
631      */
632     @Test
633     public void testIsUrlSafe() {
634         final Base64 base64Standard = new Base64(false);
635         final Base64 base64URLSafe = new Base64(true);
636 
637         assertFalse(base64Standard.isUrlSafe(), "Base64.isUrlSafe=false");
638         assertTrue(base64URLSafe.isUrlSafe(), "Base64.isUrlSafe=true");
639 
640         final byte[] whiteSpace = { ' ', '\n', '\r', '\t' };
641         assertTrue(Base64.isBase64(whiteSpace), "Base64.isBase64(whiteSpace)=true");
642     }
643 
644     @Test
645     public void testKnownDecodings() {
646         assertEquals("The quick brown fox jumped over the lazy dogs.", new String(Base64.decodeBase64(
647                 "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg==".getBytes(CHARSET_UTF8))));
648         assertEquals("It was the best of times, it was the worst of times.", new String(Base64.decodeBase64(
649                 "SXQgd2FzIHRoZSBiZXN0IG9mIHRpbWVzLCBpdCB3YXMgdGhlIHdvcnN0IG9mIHRpbWVzLg==".getBytes(CHARSET_UTF8))));
650         assertEquals("http://jakarta.apache.org/commmons", new String(
651                 Base64.decodeBase64("aHR0cDovL2pha2FydGEuYXBhY2hlLm9yZy9jb21tbW9ucw==".getBytes(CHARSET_UTF8))));
652         assertEquals("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz", new String(Base64.decodeBase64(
653                 "QWFCYkNjRGRFZUZmR2dIaElpSmpLa0xsTW1Obk9vUHBRcVJyU3NUdFV1VnZXd1h4WXlaeg==".getBytes(CHARSET_UTF8))));
654         assertEquals("{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }",
655                 new String(Base64.decodeBase64("eyAwLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5IH0=".getBytes(CHARSET_UTF8))));
656         assertEquals("xyzzy!", new String(Base64.decodeBase64("eHl6enkh".getBytes(CHARSET_UTF8))));
657     }
658 
659     @Test
660     public void testKnownEncodings() {
661         assertEquals("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg==", new String(
662                 Base64.encodeBase64("The quick brown fox jumped over the lazy dogs.".getBytes(CHARSET_UTF8))));
663         assertEquals(
664                 "YmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJs\r\nYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFo\r\nIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBi\r\nbGFoIGJsYWg=\r\n",
665                 new String(Base64.encodeBase64Chunked(
666                         "blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah"
667                                 .getBytes(CHARSET_UTF8))));
668         assertEquals("SXQgd2FzIHRoZSBiZXN0IG9mIHRpbWVzLCBpdCB3YXMgdGhlIHdvcnN0IG9mIHRpbWVzLg==", new String(
669                 Base64.encodeBase64("It was the best of times, it was the worst of times.".getBytes(CHARSET_UTF8))));
670         assertEquals("aHR0cDovL2pha2FydGEuYXBhY2hlLm9yZy9jb21tbW9ucw==",
671                 new String(Base64.encodeBase64("http://jakarta.apache.org/commmons".getBytes(CHARSET_UTF8))));
672         assertEquals("QWFCYkNjRGRFZUZmR2dIaElpSmpLa0xsTW1Obk9vUHBRcVJyU3NUdFV1VnZXd1h4WXlaeg==", new String(
673                 Base64.encodeBase64("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz".getBytes(CHARSET_UTF8))));
674         assertEquals("eyAwLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5IH0=",
675                 new String(Base64.encodeBase64("{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }".getBytes(CHARSET_UTF8))));
676         assertEquals("eHl6enkh", new String(Base64.encodeBase64("xyzzy!".getBytes(CHARSET_UTF8))));
677     }
678 
679     @Test
680     public void testNonBase64Test() throws Exception {
681 
682         final byte[] bArray = { '%' };
683 
684         assertFalse(Base64.isBase64(bArray),
685                 "Invalid Base64 array was incorrectly validated as an array of Base64 encoded data");
686 
687         try {
688             final Base64 b64 = new Base64();
689             final byte[] result = b64.decode(bArray);
690 
691             assertEquals(0, result.length, "The result should be empty as the test encoded content did " +
692                     "not contain any valid base 64 characters");
693         } catch (final Exception e) {
694             fail("Exception '" + e.getClass().getName() + "' was thrown when trying to decode " +
695                 "invalid base64 encoded data - RFC 2045 requires that all " +
696                 "non base64 character be discarded, an exception should not have been thrown");
697         }
698     }
699 
700     @Test
701     public void testObjectDecodeWithInvalidParameter() {
702         assertThrows(DecoderException.class, () -> new Base64().decode(Integer.valueOf(5)),
703             "decode(Object) didn't throw an exception when passed an Integer object");
704     }
705 
706     @Test
707     public void testObjectDecodeWithValidParameter() throws Exception {
708 
709         final String original = "Hello World!";
710         final Object o = Base64.encodeBase64(original.getBytes(CHARSET_UTF8));
711 
712         final Base64 b64 = new Base64();
713         final Object oDecoded = b64.decode(o);
714         final byte[] baDecoded = (byte[]) oDecoded;
715         final String dest = new String(baDecoded);
716 
717         assertEquals(original, dest, "dest string does not equal original");
718     }
719 
720     @Test
721     public void testObjectEncode() throws Exception {
722         final Base64 b64 = new Base64();
723         assertEquals("SGVsbG8gV29ybGQ=", new String(b64.encode("Hello World".getBytes(CHARSET_UTF8))));
724     }
725 
726     @Test
727     public void testObjectEncodeWithInvalidParameter() {
728         assertThrows(EncoderException.class, () -> new Base64().encode("Yadayadayada"),
729                 "encode(Object) didn't throw an exception when passed a String object");
730     }
731 
732     @Test
733     public void testObjectEncodeWithValidParameter() throws Exception {
734 
735         final String original = "Hello World!";
736         final Object origObj = original.getBytes(CHARSET_UTF8);
737 
738         final Base64 b64 = new Base64();
739         final Object oEncoded = b64.encode(origObj);
740         final byte[] bArray = Base64.decodeBase64((byte[]) oEncoded);
741         final String dest = new String(bArray);
742 
743         assertEquals(original, dest, "dest string does not equal original");
744     }
745 
746     @Test
747     public void testPairs() {
748         assertEquals("AAA=", new String(Base64.encodeBase64(new byte[] { 0, 0 })));
749         for (int i = -128; i <= 127; i++) {
750             final byte[] test = { (byte) i, (byte) i };
751             assertArrayEquals(test, Base64.decodeBase64(Base64.encodeBase64(test)));
752         }
753     }
754 
755     /**
756      * Tests RFC 1421 section 4.3.2.4 chuck size definition.
757      */
758     @Test
759     public void testRfc1421Section6Dot8ChunkSizeDefinition() {
760         assertEquals(64, BaseNCodec.PEM_CHUNK_SIZE);
761     }
762 
763     /**
764      * Tests RFC 2045 section 2.1 CRLF definition.
765      */
766     @Test
767     public void testRfc2045Section2Dot1CrLfDefinition() {
768         assertArrayEquals(new byte[]{13, 10}, BaseNCodec.CHUNK_SEPARATOR);
769     }
770 
771     /**
772      * Tests RFC 2045 section 6.8 chuck size definition.
773      */
774     @Test
775     public void testRfc2045Section6Dot8ChunkSizeDefinition() {
776         assertEquals(76, BaseNCodec.MIME_CHUNK_SIZE);
777     }
778 
779     /**
780      * Tests RFC 4648 section 10 test vectors.
781      * <ul>
782      * <li>BASE64("") = ""</li>
783      * <li>BASE64("f") = "Zg=="</li>
784      * <li>BASE64("fo") = "Zm8="</li>
785      * <li>BASE64("foo") = "Zm9v"</li>
786      * <li>BASE64("foob") = "Zm9vYg=="</li>
787      * <li>BASE64("fooba") = "Zm9vYmE="</li>
788      * <li>BASE64("foobar") = "Zm9vYmFy"</li>
789      * </ul>
790      *
791      * @see <a href="https://tools.ietf.org/html/rfc4648">https://tools.ietf.org/
792      *      html/rfc4648</a>
793      */
794     @Test
795     public void testRfc4648Section10Decode() {
796         assertEquals("", StringUtils.newStringUsAscii(Base64.decodeBase64("")));
797         assertEquals("f", StringUtils.newStringUsAscii(Base64.decodeBase64("Zg==")));
798         assertEquals("fo", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm8=")));
799         assertEquals("foo", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9v")));
800         assertEquals("foob", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYg==")));
801         assertEquals("fooba", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYmE=")));
802         assertEquals("foobar", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYmFy")));
803     }
804 
805     /**
806      * Tests RFC 4648 section 10 test vectors.
807      * <ul>
808      * <li>BASE64("") = ""</li>
809      * <li>BASE64("f") = "Zg=="</li>
810      * <li>BASE64("fo") = "Zm8="</li>
811      * <li>BASE64("foo") = "Zm9v"</li>
812      * <li>BASE64("foob") = "Zm9vYg=="</li>
813      * <li>BASE64("fooba") = "Zm9vYmE="</li>
814      * <li>BASE64("foobar") = "Zm9vYmFy"</li>
815      * </ul>
816      *
817      * @see <a href="https://tools.ietf.org/html/rfc4648">https://tools.ietf.org/
818      *      html/rfc4648</a>
819      */
820     @Test
821     public void testRfc4648Section10DecodeEncode() {
822         testDecodeEncode("");
823         testDecodeEncode("Zg==");
824         testDecodeEncode("Zm8=");
825         testDecodeEncode("Zm9v");
826         testDecodeEncode("Zm9vYg==");
827         testDecodeEncode("Zm9vYmE=");
828         testDecodeEncode("Zm9vYmFy");
829     }
830 
831     /**
832      * Tests RFC 4648 section 10 test vectors.
833      * <ul>
834      * <li>BASE64("") = ""</li>
835      * <li>BASE64("f") = "Zg=="</li>
836      * <li>BASE64("fo") = "Zm8="</li>
837      * <li>BASE64("foo") = "Zm9v"</li>
838      * <li>BASE64("foob") = "Zm9vYg=="</li>
839      * <li>BASE64("fooba") = "Zm9vYmE="</li>
840      * <li>BASE64("foobar") = "Zm9vYmFy"</li>
841      * </ul>
842      *
843      * @see <a href="https://tools.ietf.org/html/rfc4648">https://tools.ietf.org/
844      *      html/rfc4648</a>
845      */
846     @Test
847     public void testRfc4648Section10DecodeWithCrLf() {
848         final String CRLF = StringUtils.newStringUsAscii(BaseNCodec.CHUNK_SEPARATOR);
849         assertEquals("", StringUtils.newStringUsAscii(Base64.decodeBase64("" + CRLF)));
850         assertEquals("f", StringUtils.newStringUsAscii(Base64.decodeBase64("Zg==" + CRLF)));
851         assertEquals("fo", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm8=" + CRLF)));
852         assertEquals("foo", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9v" + CRLF)));
853         assertEquals("foob", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYg==" + CRLF)));
854         assertEquals("fooba", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYmE=" + CRLF)));
855         assertEquals("foobar", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYmFy" + CRLF)));
856     }
857 
858     /**
859      * Tests RFC 4648 section 10 test vectors.
860      * <ul>
861      * <li>BASE64("") = ""</li>
862      * <li>BASE64("f") = "Zg=="</li>
863      * <li>BASE64("fo") = "Zm8="</li>
864      * <li>BASE64("foo") = "Zm9v"</li>
865      * <li>BASE64("foob") = "Zm9vYg=="</li>
866      * <li>BASE64("fooba") = "Zm9vYmE="</li>
867      * <li>BASE64("foobar") = "Zm9vYmFy"</li>
868      * </ul>
869      *
870      * @see <a href="https://tools.ietf.org/html/rfc4648">https://tools.ietf.org/
871      *      html/rfc4648</a>
872      */
873     @Test
874     public void testRfc4648Section10Encode() {
875         assertEquals("", Base64.encodeBase64String(StringUtils.getBytesUtf8("")));
876         assertEquals("Zg==", Base64.encodeBase64String(StringUtils.getBytesUtf8("f")));
877         assertEquals("Zm8=", Base64.encodeBase64String(StringUtils.getBytesUtf8("fo")));
878         assertEquals("Zm9v", Base64.encodeBase64String(StringUtils.getBytesUtf8("foo")));
879         assertEquals("Zm9vYg==", Base64.encodeBase64String(StringUtils.getBytesUtf8("foob")));
880         assertEquals("Zm9vYmE=", Base64.encodeBase64String(StringUtils.getBytesUtf8("fooba")));
881         assertEquals("Zm9vYmFy", Base64.encodeBase64String(StringUtils.getBytesUtf8("foobar")));
882     }
883 
884     /**
885      * Tests RFC 4648 section 10 test vectors.
886      * <ul>
887      * <li>BASE64("") = ""</li>
888      * <li>BASE64("f") = "Zg=="</li>
889      * <li>BASE64("fo") = "Zm8="</li>
890      * <li>BASE64("foo") = "Zm9v"</li>
891      * <li>BASE64("foob") = "Zm9vYg=="</li>
892      * <li>BASE64("fooba") = "Zm9vYmE="</li>
893      * <li>BASE64("foobar") = "Zm9vYmFy"</li>
894      * </ul>
895      *
896      * @see <a href="https://tools.ietf.org/html/rfc4648">https://tools.ietf.org/
897      *      html/rfc4648</a>
898      */
899     @Test
900     public void testRfc4648Section10EncodeDecode() {
901         testEncodeDecode("");
902         testEncodeDecode("f");
903         testEncodeDecode("fo");
904         testEncodeDecode("foo");
905         testEncodeDecode("foob");
906         testEncodeDecode("fooba");
907         testEncodeDecode("foobar");
908     }
909 
910     @Test
911     public void testSingletons() {
912         assertEquals("AA==", new String(Base64.encodeBase64(new byte[] { (byte) 0 })));
913         assertEquals("AQ==", new String(Base64.encodeBase64(new byte[] { (byte) 1 })));
914         assertEquals("Ag==", new String(Base64.encodeBase64(new byte[] { (byte) 2 })));
915         assertEquals("Aw==", new String(Base64.encodeBase64(new byte[] { (byte) 3 })));
916         assertEquals("BA==", new String(Base64.encodeBase64(new byte[] { (byte) 4 })));
917         assertEquals("BQ==", new String(Base64.encodeBase64(new byte[] { (byte) 5 })));
918         assertEquals("Bg==", new String(Base64.encodeBase64(new byte[] { (byte) 6 })));
919         assertEquals("Bw==", new String(Base64.encodeBase64(new byte[] { (byte) 7 })));
920         assertEquals("CA==", new String(Base64.encodeBase64(new byte[] { (byte) 8 })));
921         assertEquals("CQ==", new String(Base64.encodeBase64(new byte[] { (byte) 9 })));
922         assertEquals("Cg==", new String(Base64.encodeBase64(new byte[] { (byte) 10 })));
923         assertEquals("Cw==", new String(Base64.encodeBase64(new byte[] { (byte) 11 })));
924         assertEquals("DA==", new String(Base64.encodeBase64(new byte[] { (byte) 12 })));
925         assertEquals("DQ==", new String(Base64.encodeBase64(new byte[] { (byte) 13 })));
926         assertEquals("Dg==", new String(Base64.encodeBase64(new byte[] { (byte) 14 })));
927         assertEquals("Dw==", new String(Base64.encodeBase64(new byte[] { (byte) 15 })));
928         assertEquals("EA==", new String(Base64.encodeBase64(new byte[] { (byte) 16 })));
929         assertEquals("EQ==", new String(Base64.encodeBase64(new byte[] { (byte) 17 })));
930         assertEquals("Eg==", new String(Base64.encodeBase64(new byte[] { (byte) 18 })));
931         assertEquals("Ew==", new String(Base64.encodeBase64(new byte[] { (byte) 19 })));
932         assertEquals("FA==", new String(Base64.encodeBase64(new byte[] { (byte) 20 })));
933         assertEquals("FQ==", new String(Base64.encodeBase64(new byte[] { (byte) 21 })));
934         assertEquals("Fg==", new String(Base64.encodeBase64(new byte[] { (byte) 22 })));
935         assertEquals("Fw==", new String(Base64.encodeBase64(new byte[] { (byte) 23 })));
936         assertEquals("GA==", new String(Base64.encodeBase64(new byte[] { (byte) 24 })));
937         assertEquals("GQ==", new String(Base64.encodeBase64(new byte[] { (byte) 25 })));
938         assertEquals("Gg==", new String(Base64.encodeBase64(new byte[] { (byte) 26 })));
939         assertEquals("Gw==", new String(Base64.encodeBase64(new byte[] { (byte) 27 })));
940         assertEquals("HA==", new String(Base64.encodeBase64(new byte[] { (byte) 28 })));
941         assertEquals("HQ==", new String(Base64.encodeBase64(new byte[] { (byte) 29 })));
942         assertEquals("Hg==", new String(Base64.encodeBase64(new byte[] { (byte) 30 })));
943         assertEquals("Hw==", new String(Base64.encodeBase64(new byte[] { (byte) 31 })));
944         assertEquals("IA==", new String(Base64.encodeBase64(new byte[] { (byte) 32 })));
945         assertEquals("IQ==", new String(Base64.encodeBase64(new byte[] { (byte) 33 })));
946         assertEquals("Ig==", new String(Base64.encodeBase64(new byte[] { (byte) 34 })));
947         assertEquals("Iw==", new String(Base64.encodeBase64(new byte[] { (byte) 35 })));
948         assertEquals("JA==", new String(Base64.encodeBase64(new byte[] { (byte) 36 })));
949         assertEquals("JQ==", new String(Base64.encodeBase64(new byte[] { (byte) 37 })));
950         assertEquals("Jg==", new String(Base64.encodeBase64(new byte[] { (byte) 38 })));
951         assertEquals("Jw==", new String(Base64.encodeBase64(new byte[] { (byte) 39 })));
952         assertEquals("KA==", new String(Base64.encodeBase64(new byte[] { (byte) 40 })));
953         assertEquals("KQ==", new String(Base64.encodeBase64(new byte[] { (byte) 41 })));
954         assertEquals("Kg==", new String(Base64.encodeBase64(new byte[] { (byte) 42 })));
955         assertEquals("Kw==", new String(Base64.encodeBase64(new byte[] { (byte) 43 })));
956         assertEquals("LA==", new String(Base64.encodeBase64(new byte[] { (byte) 44 })));
957         assertEquals("LQ==", new String(Base64.encodeBase64(new byte[] { (byte) 45 })));
958         assertEquals("Lg==", new String(Base64.encodeBase64(new byte[] { (byte) 46 })));
959         assertEquals("Lw==", new String(Base64.encodeBase64(new byte[] { (byte) 47 })));
960         assertEquals("MA==", new String(Base64.encodeBase64(new byte[] { (byte) 48 })));
961         assertEquals("MQ==", new String(Base64.encodeBase64(new byte[] { (byte) 49 })));
962         assertEquals("Mg==", new String(Base64.encodeBase64(new byte[] { (byte) 50 })));
963         assertEquals("Mw==", new String(Base64.encodeBase64(new byte[] { (byte) 51 })));
964         assertEquals("NA==", new String(Base64.encodeBase64(new byte[] { (byte) 52 })));
965         assertEquals("NQ==", new String(Base64.encodeBase64(new byte[] { (byte) 53 })));
966         assertEquals("Ng==", new String(Base64.encodeBase64(new byte[] { (byte) 54 })));
967         assertEquals("Nw==", new String(Base64.encodeBase64(new byte[] { (byte) 55 })));
968         assertEquals("OA==", new String(Base64.encodeBase64(new byte[] { (byte) 56 })));
969         assertEquals("OQ==", new String(Base64.encodeBase64(new byte[] { (byte) 57 })));
970         assertEquals("Og==", new String(Base64.encodeBase64(new byte[] { (byte) 58 })));
971         assertEquals("Ow==", new String(Base64.encodeBase64(new byte[] { (byte) 59 })));
972         assertEquals("PA==", new String(Base64.encodeBase64(new byte[] { (byte) 60 })));
973         assertEquals("PQ==", new String(Base64.encodeBase64(new byte[] { (byte) 61 })));
974         assertEquals("Pg==", new String(Base64.encodeBase64(new byte[] { (byte) 62 })));
975         assertEquals("Pw==", new String(Base64.encodeBase64(new byte[] { (byte) 63 })));
976         assertEquals("QA==", new String(Base64.encodeBase64(new byte[] { (byte) 64 })));
977         assertEquals("QQ==", new String(Base64.encodeBase64(new byte[] { (byte) 65 })));
978         assertEquals("Qg==", new String(Base64.encodeBase64(new byte[] { (byte) 66 })));
979         assertEquals("Qw==", new String(Base64.encodeBase64(new byte[] { (byte) 67 })));
980         assertEquals("RA==", new String(Base64.encodeBase64(new byte[] { (byte) 68 })));
981         assertEquals("RQ==", new String(Base64.encodeBase64(new byte[] { (byte) 69 })));
982         assertEquals("Rg==", new String(Base64.encodeBase64(new byte[] { (byte) 70 })));
983         assertEquals("Rw==", new String(Base64.encodeBase64(new byte[] { (byte) 71 })));
984         assertEquals("SA==", new String(Base64.encodeBase64(new byte[] { (byte) 72 })));
985         assertEquals("SQ==", new String(Base64.encodeBase64(new byte[] { (byte) 73 })));
986         assertEquals("Sg==", new String(Base64.encodeBase64(new byte[] { (byte) 74 })));
987         assertEquals("Sw==", new String(Base64.encodeBase64(new byte[] { (byte) 75 })));
988         assertEquals("TA==", new String(Base64.encodeBase64(new byte[] { (byte) 76 })));
989         assertEquals("TQ==", new String(Base64.encodeBase64(new byte[] { (byte) 77 })));
990         assertEquals("Tg==", new String(Base64.encodeBase64(new byte[] { (byte) 78 })));
991         assertEquals("Tw==", new String(Base64.encodeBase64(new byte[] { (byte) 79 })));
992         assertEquals("UA==", new String(Base64.encodeBase64(new byte[] { (byte) 80 })));
993         assertEquals("UQ==", new String(Base64.encodeBase64(new byte[] { (byte) 81 })));
994         assertEquals("Ug==", new String(Base64.encodeBase64(new byte[] { (byte) 82 })));
995         assertEquals("Uw==", new String(Base64.encodeBase64(new byte[] { (byte) 83 })));
996         assertEquals("VA==", new String(Base64.encodeBase64(new byte[] { (byte) 84 })));
997         assertEquals("VQ==", new String(Base64.encodeBase64(new byte[] { (byte) 85 })));
998         assertEquals("Vg==", new String(Base64.encodeBase64(new byte[] { (byte) 86 })));
999         assertEquals("Vw==", new String(Base64.encodeBase64(new byte[] { (byte) 87 })));
1000         assertEquals("WA==", new String(Base64.encodeBase64(new byte[] { (byte) 88 })));
1001         assertEquals("WQ==", new String(Base64.encodeBase64(new byte[] { (byte) 89 })));
1002         assertEquals("Wg==", new String(Base64.encodeBase64(new byte[] { (byte) 90 })));
1003         assertEquals("Ww==", new String(Base64.encodeBase64(new byte[] { (byte) 91 })));
1004         assertEquals("XA==", new String(Base64.encodeBase64(new byte[] { (byte) 92 })));
1005         assertEquals("XQ==", new String(Base64.encodeBase64(new byte[] { (byte) 93 })));
1006         assertEquals("Xg==", new String(Base64.encodeBase64(new byte[] { (byte) 94 })));
1007         assertEquals("Xw==", new String(Base64.encodeBase64(new byte[] { (byte) 95 })));
1008         assertEquals("YA==", new String(Base64.encodeBase64(new byte[] { (byte) 96 })));
1009         assertEquals("YQ==", new String(Base64.encodeBase64(new byte[] { (byte) 97 })));
1010         assertEquals("Yg==", new String(Base64.encodeBase64(new byte[] { (byte) 98 })));
1011         assertEquals("Yw==", new String(Base64.encodeBase64(new byte[] { (byte) 99 })));
1012         assertEquals("ZA==", new String(Base64.encodeBase64(new byte[] { (byte) 100 })));
1013         assertEquals("ZQ==", new String(Base64.encodeBase64(new byte[] { (byte) 101 })));
1014         assertEquals("Zg==", new String(Base64.encodeBase64(new byte[] { (byte) 102 })));
1015         assertEquals("Zw==", new String(Base64.encodeBase64(new byte[] { (byte) 103 })));
1016         assertEquals("aA==", new String(Base64.encodeBase64(new byte[] { (byte) 104 })));
1017         for (int i = -128; i <= 127; i++) {
1018             final byte[] test = { (byte) i };
1019             assertArrayEquals(test, Base64.decodeBase64(Base64.encodeBase64(test)));
1020         }
1021     }
1022 
1023     @Test
1024     public void testSingletonsChunked() {
1025         assertEquals("AA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0 })));
1026         assertEquals("AQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 1 })));
1027         assertEquals("Ag==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 2 })));
1028         assertEquals("Aw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 3 })));
1029         assertEquals("BA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 4 })));
1030         assertEquals("BQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 5 })));
1031         assertEquals("Bg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 6 })));
1032         assertEquals("Bw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 7 })));
1033         assertEquals("CA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 8 })));
1034         assertEquals("CQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 9 })));
1035         assertEquals("Cg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 10 })));
1036         assertEquals("Cw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 11 })));
1037         assertEquals("DA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 12 })));
1038         assertEquals("DQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 13 })));
1039         assertEquals("Dg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 14 })));
1040         assertEquals("Dw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 15 })));
1041         assertEquals("EA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 16 })));
1042         assertEquals("EQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 17 })));
1043         assertEquals("Eg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 18 })));
1044         assertEquals("Ew==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 19 })));
1045         assertEquals("FA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 20 })));
1046         assertEquals("FQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 21 })));
1047         assertEquals("Fg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 22 })));
1048         assertEquals("Fw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 23 })));
1049         assertEquals("GA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 24 })));
1050         assertEquals("GQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 25 })));
1051         assertEquals("Gg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 26 })));
1052         assertEquals("Gw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 27 })));
1053         assertEquals("HA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 28 })));
1054         assertEquals("HQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 29 })));
1055         assertEquals("Hg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 30 })));
1056         assertEquals("Hw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 31 })));
1057         assertEquals("IA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 32 })));
1058         assertEquals("IQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 33 })));
1059         assertEquals("Ig==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 34 })));
1060         assertEquals("Iw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 35 })));
1061         assertEquals("JA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 36 })));
1062         assertEquals("JQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 37 })));
1063         assertEquals("Jg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 38 })));
1064         assertEquals("Jw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 39 })));
1065         assertEquals("KA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 40 })));
1066         assertEquals("KQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 41 })));
1067         assertEquals("Kg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 42 })));
1068         assertEquals("Kw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 43 })));
1069         assertEquals("LA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 44 })));
1070         assertEquals("LQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 45 })));
1071         assertEquals("Lg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 46 })));
1072         assertEquals("Lw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 47 })));
1073         assertEquals("MA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 48 })));
1074         assertEquals("MQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 49 })));
1075         assertEquals("Mg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 50 })));
1076         assertEquals("Mw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 51 })));
1077         assertEquals("NA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 52 })));
1078         assertEquals("NQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 53 })));
1079         assertEquals("Ng==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 54 })));
1080         assertEquals("Nw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 55 })));
1081         assertEquals("OA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 56 })));
1082         assertEquals("OQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 57 })));
1083         assertEquals("Og==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 58 })));
1084         assertEquals("Ow==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 59 })));
1085         assertEquals("PA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 60 })));
1086         assertEquals("PQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 61 })));
1087         assertEquals("Pg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 62 })));
1088         assertEquals("Pw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 63 })));
1089         assertEquals("QA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 64 })));
1090         assertEquals("QQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 65 })));
1091         assertEquals("Qg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 66 })));
1092         assertEquals("Qw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 67 })));
1093         assertEquals("RA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 68 })));
1094         assertEquals("RQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 69 })));
1095         assertEquals("Rg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 70 })));
1096         assertEquals("Rw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 71 })));
1097         assertEquals("SA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 72 })));
1098         assertEquals("SQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 73 })));
1099         assertEquals("Sg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 74 })));
1100         assertEquals("Sw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 75 })));
1101         assertEquals("TA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 76 })));
1102         assertEquals("TQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 77 })));
1103         assertEquals("Tg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 78 })));
1104         assertEquals("Tw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 79 })));
1105         assertEquals("UA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 80 })));
1106         assertEquals("UQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 81 })));
1107         assertEquals("Ug==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 82 })));
1108         assertEquals("Uw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 83 })));
1109         assertEquals("VA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 84 })));
1110         assertEquals("VQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 85 })));
1111         assertEquals("Vg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 86 })));
1112         assertEquals("Vw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 87 })));
1113         assertEquals("WA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 88 })));
1114         assertEquals("WQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 89 })));
1115         assertEquals("Wg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 90 })));
1116         assertEquals("Ww==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 91 })));
1117         assertEquals("XA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 92 })));
1118         assertEquals("XQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 93 })));
1119         assertEquals("Xg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 94 })));
1120         assertEquals("Xw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 95 })));
1121         assertEquals("YA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 96 })));
1122         assertEquals("YQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 97 })));
1123         assertEquals("Yg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 98 })));
1124         assertEquals("Yw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 99 })));
1125         assertEquals("ZA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 100 })));
1126         assertEquals("ZQ==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 101 })));
1127         assertEquals("Zg==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 102 })));
1128         assertEquals("Zw==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 103 })));
1129         assertEquals("aA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 104 })));
1130     }
1131 
1132     @Test
1133     public void testStringToByteVariations() throws DecoderException {
1134         final Base64 base64 = new Base64();
1135         final String s1 = "SGVsbG8gV29ybGQ=\r\n";
1136         final String s2 = "";
1137         final String s3 = null;
1138         final String s4a = "K/fMJwH+Q5e0nr7tWsxwkA==\r\n";
1139         final String s4b = "K_fMJwH-Q5e0nr7tWsxwkA";
1140         final byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090"); // for
1141                                                                                             // url-safe
1142                                                                                             // tests
1143 
1144         assertEquals("Hello World", StringUtils.newStringUtf8(base64.decode(s1)), "StringToByte Hello World");
1145         assertEquals("Hello World", StringUtils.newStringUtf8((byte[]) base64.decode((Object) s1)), "StringToByte Hello World");
1146         assertEquals("Hello World", StringUtils.newStringUtf8(Base64.decodeBase64(s1)), "StringToByte static Hello World");
1147         assertEquals("", StringUtils.newStringUtf8(base64.decode(s2)), "StringToByte \"\"");
1148         assertEquals("", StringUtils.newStringUtf8(Base64.decodeBase64(s2)), "StringToByte static \"\"");
1149         assertNull(StringUtils.newStringUtf8(base64.decode(s3)), "StringToByte null");
1150         assertNull(StringUtils.newStringUtf8(Base64.decodeBase64(s3)), "StringToByte static null");
1151         assertArrayEquals(b4, base64.decode(s4b), "StringToByte UUID");
1152         assertArrayEquals(b4, Base64.decodeBase64(s4a), "StringToByte static UUID");
1153         assertArrayEquals(b4, Base64.decodeBase64(s4b), "StringToByte static-url-safe UUID");
1154     }
1155 
1156     @Test
1157     public void testTriplets() {
1158         assertEquals("AAAA", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 0 })));
1159         assertEquals("AAAB", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 1 })));
1160         assertEquals("AAAC", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 2 })));
1161         assertEquals("AAAD", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 3 })));
1162         assertEquals("AAAE", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 4 })));
1163         assertEquals("AAAF", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 5 })));
1164         assertEquals("AAAG", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 6 })));
1165         assertEquals("AAAH", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 7 })));
1166         assertEquals("AAAI", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 8 })));
1167         assertEquals("AAAJ", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 9 })));
1168         assertEquals("AAAK", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 10 })));
1169         assertEquals("AAAL", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 11 })));
1170         assertEquals("AAAM", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 12 })));
1171         assertEquals("AAAN", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 13 })));
1172         assertEquals("AAAO", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 14 })));
1173         assertEquals("AAAP", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 15 })));
1174         assertEquals("AAAQ", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 16 })));
1175         assertEquals("AAAR", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 17 })));
1176         assertEquals("AAAS", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 18 })));
1177         assertEquals("AAAT", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 19 })));
1178         assertEquals("AAAU", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 20 })));
1179         assertEquals("AAAV", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 21 })));
1180         assertEquals("AAAW", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 22 })));
1181         assertEquals("AAAX", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 23 })));
1182         assertEquals("AAAY", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 24 })));
1183         assertEquals("AAAZ", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 25 })));
1184         assertEquals("AAAa", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 26 })));
1185         assertEquals("AAAb", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 27 })));
1186         assertEquals("AAAc", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 28 })));
1187         assertEquals("AAAd", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 29 })));
1188         assertEquals("AAAe", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 30 })));
1189         assertEquals("AAAf", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 31 })));
1190         assertEquals("AAAg", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 32 })));
1191         assertEquals("AAAh", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 33 })));
1192         assertEquals("AAAi", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 34 })));
1193         assertEquals("AAAj", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 35 })));
1194         assertEquals("AAAk", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 36 })));
1195         assertEquals("AAAl", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 37 })));
1196         assertEquals("AAAm", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 38 })));
1197         assertEquals("AAAn", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 39 })));
1198         assertEquals("AAAo", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 40 })));
1199         assertEquals("AAAp", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 41 })));
1200         assertEquals("AAAq", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 42 })));
1201         assertEquals("AAAr", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 43 })));
1202         assertEquals("AAAs", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 44 })));
1203         assertEquals("AAAt", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 45 })));
1204         assertEquals("AAAu", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 46 })));
1205         assertEquals("AAAv", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 47 })));
1206         assertEquals("AAAw", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 48 })));
1207         assertEquals("AAAx", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 49 })));
1208         assertEquals("AAAy", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 50 })));
1209         assertEquals("AAAz", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 51 })));
1210         assertEquals("AAA0", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 52 })));
1211         assertEquals("AAA1", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 53 })));
1212         assertEquals("AAA2", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 54 })));
1213         assertEquals("AAA3", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 55 })));
1214         assertEquals("AAA4", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 56 })));
1215         assertEquals("AAA5", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 57 })));
1216         assertEquals("AAA6", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 58 })));
1217         assertEquals("AAA7", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 59 })));
1218         assertEquals("AAA8", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 60 })));
1219         assertEquals("AAA9", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 61 })));
1220         assertEquals("AAA+", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 62 })));
1221         assertEquals("AAA/", new String(Base64.encodeBase64(new byte[] { (byte) 0, (byte) 0, (byte) 63 })));
1222     }
1223 
1224     @Test
1225     public void testTripletsChunked() {
1226         assertEquals("AAAA\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 0 })));
1227         assertEquals("AAAB\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 1 })));
1228         assertEquals("AAAC\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 2 })));
1229         assertEquals("AAAD\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 3 })));
1230         assertEquals("AAAE\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 4 })));
1231         assertEquals("AAAF\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 5 })));
1232         assertEquals("AAAG\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 6 })));
1233         assertEquals("AAAH\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 7 })));
1234         assertEquals("AAAI\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 8 })));
1235         assertEquals("AAAJ\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 9 })));
1236         assertEquals("AAAK\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 10 })));
1237         assertEquals("AAAL\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 11 })));
1238         assertEquals("AAAM\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 12 })));
1239         assertEquals("AAAN\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 13 })));
1240         assertEquals("AAAO\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 14 })));
1241         assertEquals("AAAP\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 15 })));
1242         assertEquals("AAAQ\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 16 })));
1243         assertEquals("AAAR\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 17 })));
1244         assertEquals("AAAS\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 18 })));
1245         assertEquals("AAAT\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 19 })));
1246         assertEquals("AAAU\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 20 })));
1247         assertEquals("AAAV\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 21 })));
1248         assertEquals("AAAW\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 22 })));
1249         assertEquals("AAAX\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 23 })));
1250         assertEquals("AAAY\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 24 })));
1251         assertEquals("AAAZ\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 25 })));
1252         assertEquals("AAAa\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 26 })));
1253         assertEquals("AAAb\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 27 })));
1254         assertEquals("AAAc\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 28 })));
1255         assertEquals("AAAd\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 29 })));
1256         assertEquals("AAAe\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 30 })));
1257         assertEquals("AAAf\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 31 })));
1258         assertEquals("AAAg\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 32 })));
1259         assertEquals("AAAh\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 33 })));
1260         assertEquals("AAAi\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 34 })));
1261         assertEquals("AAAj\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 35 })));
1262         assertEquals("AAAk\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 36 })));
1263         assertEquals("AAAl\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 37 })));
1264         assertEquals("AAAm\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 38 })));
1265         assertEquals("AAAn\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 39 })));
1266         assertEquals("AAAo\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 40 })));
1267         assertEquals("AAAp\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 41 })));
1268         assertEquals("AAAq\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 42 })));
1269         assertEquals("AAAr\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 43 })));
1270         assertEquals("AAAs\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 44 })));
1271         assertEquals("AAAt\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 45 })));
1272         assertEquals("AAAu\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 46 })));
1273         assertEquals("AAAv\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 47 })));
1274         assertEquals("AAAw\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 48 })));
1275         assertEquals("AAAx\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 49 })));
1276         assertEquals("AAAy\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 50 })));
1277         assertEquals("AAAz\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 51 })));
1278         assertEquals("AAA0\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 52 })));
1279         assertEquals("AAA1\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 53 })));
1280         assertEquals("AAA2\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 54 })));
1281         assertEquals("AAA3\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 55 })));
1282         assertEquals("AAA4\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 56 })));
1283         assertEquals("AAA5\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 57 })));
1284         assertEquals("AAA6\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 58 })));
1285         assertEquals("AAA7\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 59 })));
1286         assertEquals("AAA8\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 60 })));
1287         assertEquals("AAA9\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 61 })));
1288         assertEquals("AAA+\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 62 })));
1289         assertEquals("AAA/\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 0, (byte) 0, (byte) 63 })));
1290     }
1291 
1292     /**
1293      * Tests URL-safe Base64 against random data, sizes 0 to 150.
1294      */
1295     @Test
1296     public void testUrlSafe() {
1297         // test random data of sizes 0 through 150
1298         final BaseNCodec codec = new Base64(true);
1299         for (int i = 0; i <= 150; i++) {
1300             final byte[][] randomData = BaseNTestData.randomData(codec, i);
1301             final byte[] encoded = randomData[1];
1302             final byte[] decoded = randomData[0];
1303             final byte[] result = Base64.decodeBase64(encoded);
1304             assertArrayEquals(decoded, result, "url-safe i=" + i);
1305             assertFalse(BaseNTestData.bytesContain(encoded, (byte) '='), "url-safe i=" + i + " no '='");
1306             assertFalse(BaseNTestData.bytesContain(encoded, (byte) '\\'), "url-safe i=" + i + " no '\\'");
1307             assertFalse(BaseNTestData.bytesContain(encoded, (byte) '+'), "url-safe i=" + i + " no '+'");
1308         }
1309 
1310     }
1311 
1312     /**
1313      * Base64 encoding of UUID's is a common use-case, especially in URL-SAFE
1314      * mode. This test case ends up being the "URL-SAFE" JUnit's.
1315      *
1316      * @throws DecoderException
1317      *             if Hex.decode() fails - a serious problem since Hex comes
1318      *             from our own commons-codec!
1319      */
1320     @Test
1321     public void testUUID() throws DecoderException {
1322         // The 4 UUID's below contains mixtures of + and / to help us test the
1323         // URL-SAFE encoding mode.
1324         final byte[][] ids = new byte[4][];
1325 
1326         // ids[0] was chosen so that it encodes with at least one +.
1327         ids[0] = Hex.decodeHex("94ed8d0319e4493399560fb67404d370");
1328 
1329         // ids[1] was chosen so that it encodes with both / and +.
1330         ids[1] = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090");
1331 
1332         // ids[2] was chosen so that it encodes with at least one /.
1333         ids[2] = Hex.decodeHex("64be154b6ffa40258d1a01288e7c31ca");
1334 
1335         // ids[3] was chosen so that it encodes with both / and +, with /
1336         // right at the beginning.
1337         ids[3] = Hex.decodeHex("ff7f8fc01cdb471a8c8b5a9306183fe8");
1338 
1339         final byte[][] standard = new byte[4][];
1340         standard[0] = StringUtils.getBytesUtf8("lO2NAxnkSTOZVg+2dATTcA==");
1341         standard[1] = StringUtils.getBytesUtf8("K/fMJwH+Q5e0nr7tWsxwkA==");
1342         standard[2] = StringUtils.getBytesUtf8("ZL4VS2/6QCWNGgEojnwxyg==");
1343         standard[3] = StringUtils.getBytesUtf8("/3+PwBzbRxqMi1qTBhg/6A==");
1344 
1345         final byte[][] urlSafe1 = new byte[4][];
1346         // regular padding (two '==' signs).
1347         urlSafe1[0] = StringUtils.getBytesUtf8("lO2NAxnkSTOZVg-2dATTcA==");
1348         urlSafe1[1] = StringUtils.getBytesUtf8("K_fMJwH-Q5e0nr7tWsxwkA==");
1349         urlSafe1[2] = StringUtils.getBytesUtf8("ZL4VS2_6QCWNGgEojnwxyg==");
1350         urlSafe1[3] = StringUtils.getBytesUtf8("_3-PwBzbRxqMi1qTBhg_6A==");
1351 
1352         final byte[][] urlSafe2 = new byte[4][];
1353         // single padding (only one '=' sign).
1354         urlSafe2[0] = StringUtils.getBytesUtf8("lO2NAxnkSTOZVg-2dATTcA=");
1355         urlSafe2[1] = StringUtils.getBytesUtf8("K_fMJwH-Q5e0nr7tWsxwkA=");
1356         urlSafe2[2] = StringUtils.getBytesUtf8("ZL4VS2_6QCWNGgEojnwxyg=");
1357         urlSafe2[3] = StringUtils.getBytesUtf8("_3-PwBzbRxqMi1qTBhg_6A=");
1358 
1359         final byte[][] urlSafe3 = new byte[4][];
1360         // no padding (no '=' signs).
1361         urlSafe3[0] = StringUtils.getBytesUtf8("lO2NAxnkSTOZVg-2dATTcA");
1362         urlSafe3[1] = StringUtils.getBytesUtf8("K_fMJwH-Q5e0nr7tWsxwkA");
1363         urlSafe3[2] = StringUtils.getBytesUtf8("ZL4VS2_6QCWNGgEojnwxyg");
1364         urlSafe3[3] = StringUtils.getBytesUtf8("_3-PwBzbRxqMi1qTBhg_6A");
1365 
1366         for (int i = 0; i < 4; i++) {
1367             final byte[] encodedStandard = Base64.encodeBase64(ids[i]);
1368             final byte[] encodedUrlSafe = Base64.encodeBase64URLSafe(ids[i]);
1369             final byte[] decodedStandard = Base64.decodeBase64(standard[i]);
1370             final byte[] decodedUrlSafe1 = Base64.decodeBase64(urlSafe1[i]);
1371             final byte[] decodedUrlSafe2 = Base64.decodeBase64(urlSafe2[i]);
1372             final byte[] decodedUrlSafe3 = Base64.decodeBase64(urlSafe3[i]);
1373 
1374             // Very important debugging output should anyone
1375             // ever need to delve closely into this stuff.
1376 //            {
1377 //                System.out.println("reference: [" + Hex.encodeHexString(ids[i]) + "]");
1378 //                System.out.println("standard:  [" + Hex.encodeHexString(decodedStandard) + "] From: ["
1379 //                        + StringUtils.newStringUtf8(standard[i]) + "]");
1380 //                System.out.println("safe1:     [" + Hex.encodeHexString(decodedUrlSafe1) + "] From: ["
1381 //                        + StringUtils.newStringUtf8(urlSafe1[i]) + "]");
1382 //                System.out.println("safe2:     [" + Hex.encodeHexString(decodedUrlSafe2) + "] From: ["
1383 //                        + StringUtils.newStringUtf8(urlSafe2[i]) + "]");
1384 //                System.out.println("safe3:     [" + Hex.encodeHexString(decodedUrlSafe3) + "] From: ["
1385 //                        + StringUtils.newStringUtf8(urlSafe3[i]) + "]");
1386 //            }
1387 
1388             assertArrayEquals(encodedStandard, standard[i], "standard encode uuid");
1389             assertArrayEquals(encodedUrlSafe, urlSafe3[i], "url-safe encode uuid");
1390             assertArrayEquals(decodedStandard, ids[i], "standard decode uuid");
1391             assertArrayEquals(decodedUrlSafe1, ids[i], "url-safe1 decode uuid");
1392             assertArrayEquals(decodedUrlSafe2, ids[i], "url-safe2 decode uuid");
1393             assertArrayEquals(decodedUrlSafe3, ids[i], "url-safe3 decode uuid");
1394         }
1395     }
1396 
1397     private String toString(final byte[] data) {
1398         final StringBuilder buf = new StringBuilder();
1399         for (int i = 0; i < data.length; i++) {
1400             buf.append(data[i]);
1401             if (i != data.length - 1) {
1402                 buf.append(",");
1403             }
1404         }
1405         return buf.toString();
1406     }
1407 }