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