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    *      https://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.assertThrows;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.io.BufferedReader;
28  import java.io.ByteArrayInputStream;
29  import java.io.ByteArrayOutputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.InputStreamReader;
33  
34  import org.apache.commons.codec.CodecPolicy;
35  import org.apache.commons.io.IOUtils;
36  import org.junit.jupiter.api.Test;
37  
38  /**
39   * Tests {@link Base64InputStream}.
40   */
41  class Base64InputStreamTest {
42  
43      /**
44       * Decodes to {0, 0, 0, 255, 255, 255}
45       */
46      private static final String ENCODED_B64 = "AAAA////";
47  
48      private static final byte[] CRLF = { (byte) '\r', (byte) '\n' };
49  
50      private static final byte[] LF = { (byte) '\n' };
51  
52      private static final String STRING_FIXTURE = "Hello World";
53  
54      /**
55       * Tests skipping past the end of a stream.
56       *
57       * @throws Throwable
58       *             for some failure scenarios.
59       */
60      @Test
61      void testAvailable() throws Throwable {
62          final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
63          try (Base64InputStream b64stream = new Base64InputStream(ins)) {
64              assertEquals(1, b64stream.available());
65              assertEquals(6, b64stream.skip(10));
66              // End of stream reached
67              assertEquals(0, b64stream.available());
68              assertEquals(-1, b64stream.read());
69              assertEquals(-1, b64stream.read());
70              assertEquals(0, b64stream.available());
71          }
72      }
73  
74      private void testBase64EmptyInputStream(final int chuckSize) throws Exception {
75          final byte[] emptyEncoded = {};
76          final byte[] emptyDecoded = {};
77          testByteByByte(emptyEncoded, emptyDecoded, chuckSize, CRLF);
78          testByChunk(emptyEncoded, emptyDecoded, chuckSize, CRLF);
79      }
80  
81      /**
82       * Tests the Base64InputStream implementation against empty input.
83       *
84       * @throws Exception
85       *             for some failure scenarios.
86       */
87      @Test
88      void testBase64EmptyInputStreamMimeChuckSize() throws Exception {
89          testBase64EmptyInputStream(BaseNCodec.MIME_CHUNK_SIZE);
90      }
91  
92      /**
93       * Tests the Base64InputStream implementation against empty input.
94       *
95       * @throws Exception
96       *             for some failure scenarios.
97       */
98      @Test
99      void testBase64EmptyInputStreamPemChuckSize() throws Exception {
100         testBase64EmptyInputStream(BaseNCodec.PEM_CHUNK_SIZE);
101     }
102 
103     /**
104      * Tests the Base64InputStream implementation.
105      *
106      * @throws Exception
107      *             for some failure scenarios.
108      */
109     @Test
110     void testBase64InputStreamByChunk() throws Exception {
111         // Hello World test.
112         byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n");
113         byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
114         testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
115 
116         // Single Byte test.
117         encoded = StringUtils.getBytesUtf8("AA==\r\n");
118         decoded = new byte[] { (byte) 0 };
119         testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
120 
121         // OpenSSL interop test.
122         encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
123         decoded = BaseNTestData.DECODED;
124         testByChunk(encoded, decoded, BaseNCodec.PEM_CHUNK_SIZE, LF);
125 
126         // Single Line test.
127         final String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replace("\n", "");
128         encoded = StringUtils.getBytesUtf8(singleLine);
129         decoded = BaseNTestData.DECODED;
130         testByChunk(encoded, decoded, 0, LF);
131 
132         // test random data of sizes 0 through 150
133         final BaseNCodec codec = new Base64(0, null, false);
134         for (int i = 0; i <= 150; i++) {
135             final byte[][] randomData = BaseNTestData.randomData(codec, i);
136             encoded = randomData[1];
137             decoded = randomData[0];
138             testByChunk(encoded, decoded, 0, LF);
139         }
140     }
141 
142     /**
143      * Tests the Base64InputStream implementation.
144      *
145      * @throws Exception
146      *             for some failure scenarios.
147      */
148     @Test
149     void testBase64InputStreamByteByByte() throws Exception {
150         // Hello World test.
151         byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n");
152         byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
153         testByteByByte(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
154 
155         // Single Byte test.
156         encoded = StringUtils.getBytesUtf8("AA==\r\n");
157         decoded = new byte[] { (byte) 0 };
158         testByteByByte(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
159 
160         // OpenSSL interop test.
161         encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
162         decoded = BaseNTestData.DECODED;
163         testByteByByte(encoded, decoded, BaseNCodec.PEM_CHUNK_SIZE, LF);
164 
165         // Single Line test.
166         final String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replace("\n", "");
167         encoded = StringUtils.getBytesUtf8(singleLine);
168         decoded = BaseNTestData.DECODED;
169         testByteByByte(encoded, decoded, 0, LF);
170 
171         // test random data of sizes 0 through 150
172         final BaseNCodec codec = new Base64(0, null, false);
173         for (int i = 0; i <= 150; i++) {
174             final byte[][] randomData = BaseNTestData.randomData(codec, i);
175             encoded = randomData[1];
176             decoded = randomData[0];
177             testByteByByte(encoded, decoded, 0, LF);
178         }
179     }
180 
181     @Test
182     void testBuilder() {
183         assertNotNull(Base64InputStream.builder().getBaseNCodec());
184     }
185 
186     /**
187      * Tests method does three tests on the supplied data: 1. encoded ---[DECODE]--> decoded 2. decoded ---[ENCODE]--> encoded 3. decoded
188      * ---[WRAP-WRAP-WRAP-etc...] --> decoded
189      * <p/>
190      * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the Base64InputStream wraps itself in encode and decode mode over and over
191      * again.
192      *
193      * @param encoded
194      *            base64 encoded data
195      * @param decoded
196      *            the data from above, but decoded
197      * @param chunkSize
198      *            chunk size (line-length) of the base64 encoded data.
199      * @param separator
200      *            Line separator in the base64 encoded data.
201      * @throws Exception
202      *             Usually signifies a bug in the Base64 commons-codec implementation.
203      */
204     private void testByChunk(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception {
205         // Start with encode.
206         try (InputStream in = new Base64InputStream(new ByteArrayInputStream(decoded), true, chunkSize, separator)) {
207             final byte[] output = IOUtils.toByteArray(in);
208             assertEquals(-1, in.read(), "EOF");
209             assertEquals(-1, in.read(), "Still EOF");
210             assertArrayEquals(encoded, output, "Streaming base64 encode");
211         }
212 
213         // Now let's try to decode.
214         InputStream in = new Base64InputStream(new ByteArrayInputStream(encoded));
215         final InputStream in1 = in;
216         byte[] output = IOUtils.toByteArray(in1);
217 
218         assertEquals(-1, in.read(), "EOF");
219         assertEquals(-1, in.read(), "Still EOF");
220         assertArrayEquals(decoded, output, "Streaming base64 decode");
221 
222         // I always wanted to do this! (wrap encoder with decoder etc.).
223         in = new ByteArrayInputStream(decoded);
224         for (int i = 0; i < 10; i++) {
225             in = new Base64InputStream(in, true, chunkSize, separator);
226             in = new Base64InputStream(in, false);
227         }
228         final InputStream in2 = in;
229         output = IOUtils.toByteArray(in2);
230 
231         assertEquals(-1, in.read(), "EOF");
232         assertEquals(-1, in.read(), "Still EOF");
233         assertArrayEquals(decoded, output, "Streaming base64 wrap-wrap-wrap!");
234         in.close();
235     }
236 
237     /**
238      * Tests method does three tests on the supplied data: 1. encoded ---[DECODE]--> decoded 2. decoded ---[ENCODE]--> encoded 3. decoded
239      * ---[WRAP-WRAP-WRAP-etc...] --> decoded
240      * <p/>
241      * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the Base64InputStream wraps itself in encode and decode mode over and over
242      * again.
243      *
244      * @param encoded
245      *            base64 encoded data
246      * @param decoded
247      *            the data from above, but decoded
248      * @param chunkSize
249      *            chunk size (line-length) of the base64 encoded data.
250      * @param separator
251      *            Line separator in the base64 encoded data.
252      * @throws Exception
253      *             Usually signifies a bug in the Base64 commons-codec implementation.
254      */
255     private void testByteByByte(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception {
256         byte[] output = new byte[encoded.length];
257         // Start with encode.
258         try (InputStream in = new Base64InputStream(new ByteArrayInputStream(decoded), true, chunkSize, separator)) {
259             for (int i = 0; i < output.length; i++) {
260                 output[i] = (byte) in.read();
261             }
262 
263             assertEquals(-1, in.read(), "EOF");
264             assertEquals(-1, in.read(), "Still EOF");
265             assertArrayEquals(encoded, output, "Streaming base64 encode");
266 
267         }
268         // Now let's try to decode.
269         try (InputStream in = new Base64InputStream(new ByteArrayInputStream(encoded))) {
270             output = new byte[decoded.length];
271             for (int i = 0; i < output.length; i++) {
272                 output[i] = (byte) in.read();
273             }
274 
275             assertEquals(-1, in.read(), "EOF");
276             assertEquals(-1, in.read(), "Still EOF");
277             assertArrayEquals(decoded, output, "Streaming base64 decode");
278         }
279 
280         // I always wanted to do this! (wrap encoder with decoder etc.).
281         InputStream in = new ByteArrayInputStream(decoded);
282         for (int i = 0; i < 10; i++) {
283             in = new Base64InputStream(in, true, chunkSize, separator);
284             in = new Base64InputStream(in, false);
285         }
286         output = new byte[decoded.length];
287         for (int i = 0; i < output.length; i++) {
288             output[i] = (byte) in.read();
289         }
290 
291         assertEquals(-1, in.read(), "EOF");
292         assertEquals(-1, in.read(), "Still EOF");
293         assertArrayEquals(decoded, output, "Streaming base64 wrap-wrap-wrap!");
294     }
295 
296     /**
297      * Test for the CODEC-101 bug: InputStream.read(byte[]) should never return 0 because Java's builtin InputStreamReader hates that.
298      *
299      * @throws Exception
300      *             for some failure scenarios.
301      */
302     @Test
303     void testCodec101() throws Exception {
304         final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
305         final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
306         try (Base64InputStream in = new Base64InputStream(bais)) {
307             final byte[] result = new byte[8192];
308             int c = in.read(result);
309             assertTrue(c > 0, "Codec101: First read successful [c=" + c + "]");
310 
311             c = in.read(result);
312             assertTrue(c < 0, "Codec101: Second read should report end-of-stream [c=" + c + "]");
313         }
314     }
315 
316     /**
317      * Tests the bug reported in CODEC-105. Bad interactions with InputStream when reading one byte at a time.
318      */
319     @Test
320     void testCodec105() throws IOException {
321         try (Base64InputStream in = new Base64InputStream(new Codec105ErrorInputStream(), true, 0, null)) {
322             for (int i = 0; i < 5; i++) {
323                 in.read();
324             }
325         }
326     }
327 
328     /**
329      * Tests the problem reported in CODEC-130. Missing / wrong implementation of skip.
330      */
331     @Test
332     void testCodec130() throws IOException {
333         final ByteArrayOutputStream bos = new ByteArrayOutputStream();
334         try (Base64OutputStream base64os = new Base64OutputStream(bos)) {
335             base64os.write(StringUtils.getBytesUtf8(STRING_FIXTURE));
336         }
337 
338         final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
339         final Base64InputStream ins = new Base64InputStream(bis);
340 
341         // we skip the first character read from the reader
342         ins.skip(1);
343         final byte[] decodedBytes = IOUtils.toByteArray(ins);
344         final String str = StringUtils.newStringUtf8(decodedBytes);
345 
346         assertEquals(STRING_FIXTURE.substring(1), str);
347     }
348 
349     /**
350      * Test the Base64InputStream implementation against the special NPE inducing input identified in the CODEC-98 bug.
351      *
352      * @throws Exception
353      *             for some failure scenarios.
354      */
355     @Test
356     void testCodec98NPE() throws Exception {
357         final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
358         final ByteArrayInputStream data = new ByteArrayInputStream(codec98);
359         final Base64InputStream stream = new Base64InputStream(data);
360 
361         // This line causes an NPE in commons-codec-1.4.jar:
362         final byte[] decodedBytes = IOUtils.toByteArray(stream);
363 
364         final String decoded = StringUtils.newStringUtf8(decodedBytes);
365         assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64InputStream");
366     }
367 
368     /**
369      * Another test for the CODEC-101 bug: In commons-codec-1.4 this test shows InputStreamReader explicitly hating an
370      * InputStream.read(byte[]) return of 0:
371      *
372      * java.io.IOException: Underlying input stream returned zero bytes at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268) at
373      * sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158) at
374      * java.io.InputStreamReader.read(InputStreamReader.java:167) at java.io.BufferedReader.fill(BufferedReader.java:136) at
375      * java.io.BufferedReader.readLine(BufferedReader.java:299) at java.io.BufferedReader.readLine(BufferedReader.java:362) at
376      * org.apache.commons.codec.binary.Base64InputStreamTest.testInputStreamReader(Base64InputStreamTest.java:75)
377      *
378      * But in commons-codec-1.5 it's fixed. :-)
379      *
380      * @throws Exception
381      *             for some failure scenarios.
382      */
383     @Test
384     void testInputStreamReader() throws Exception {
385         final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
386         final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
387         final Base64InputStream in = new Base64InputStream(bais);
388         final InputStreamReader isr = new InputStreamReader(in);
389         try (BufferedReader br = new BufferedReader(isr)) {
390             final String line = br.readLine();
391             assertNotNull(line, "Codec101:  InputStreamReader works!");
392         }
393     }
394 
395     /**
396      * Tests markSupported.
397      *
398      * @throws Exception
399      *             for some failure scenarios.
400      */
401     @Test
402     void testMarkSupported() throws Exception {
403         final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
404         final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
405         try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
406             // Always returns false for now.
407             assertFalse(in.markSupported(), "Base64InputStream.markSupported() is false");
408         }
409     }
410 
411     /**
412      * Tests read returning 0
413      *
414      * @throws Exception
415      *             for some failure scenarios.
416      */
417     @Test
418     void testRead0() throws Exception {
419         final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
420         final byte[] buf = new byte[1024];
421         int bytesRead = 0;
422         final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
423         try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
424             bytesRead = in.read(buf, 0, 0);
425             assertEquals(0, bytesRead, "Base64InputStream.read(buf, 0, 0) returns 0");
426         }
427     }
428 
429     /**
430      * Tests read using different buffer sizes
431      *
432      * @throws Exception
433      *             for some failure scenarios.
434      */
435     @Test
436     void testReadMultipleBufferSizes() throws Exception {
437         final byte[][] randomData = BaseNTestData.randomData(new Base64(0, null, false), 1024 * 64);
438         final byte[] encoded = randomData[1];
439         final byte[] decoded = randomData[0];
440         final ByteArrayInputStream bin = new ByteArrayInputStream(encoded);
441         final ByteArrayOutputStream out = new ByteArrayOutputStream();
442         try (Base64InputStream in = new Base64InputStream(bin)) {
443             for (final int i : new int[] { 4 * 1024, 4 * 1024, 8 * 1024, 8 * 1024, 16 * 1024, 16 * 1024, 8 * 1024 }) {
444                 final byte[] buf = new byte[i];
445                 final int bytesRead = in.read(buf);
446                 assertEquals(i, bytesRead);
447                 out.write(buf, 0, bytesRead);
448             }
449         }
450         assertArrayEquals(decoded, out.toByteArray());
451     }
452 
453     /**
454      * Tests read with null.
455      *
456      * @throws Exception
457      *             for some failure scenarios.
458      */
459     @Test
460     void testReadNull() throws Exception {
461         final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
462         final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
463         try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
464             assertThrows(NullPointerException.class, () -> in.read(null, 0, 0));
465         }
466     }
467 
468     /**
469      * Tests read throwing IndexOutOfBoundsException
470      *
471      * @throws Exception
472      *             for some failure scenarios.
473      */
474     @Test
475     void testReadOutOfBounds() throws Exception {
476         final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
477         final byte[] buf = new byte[1024];
478         final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
479         try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] {0, 0, 0})) {
480             assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, -1, 0), "Base64InputStream.read(buf, -1, 0)");
481             assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, 0, -1), "Base64InputStream.read(buf, 0, -1)");
482             assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, buf.length + 1, 0), "Base64InputStream.read(buf, buf.length + 1, 0)");
483             assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, buf.length - 1, 2), "Base64InputStream.read(buf, buf.length - 1, 2)");
484         }
485     }
486 
487     /**
488      * Tests skipping number of characters larger than the internal buffer.
489      *
490      * @throws Throwable
491      *             for some failure scenarios.
492      */
493     @Test
494     void testSkipBig() throws Throwable {
495         final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
496         try (Base64InputStream b64stream = new Base64InputStream(ins)) {
497             assertEquals(6, b64stream.skip(Integer.MAX_VALUE));
498             // End of stream reached
499             assertEquals(-1, b64stream.read());
500             assertEquals(-1, b64stream.read());
501         }
502     }
503 
504     /**
505      * Tests skipping as a noop
506      *
507      * @throws Throwable
508      *             for some failure scenarios.
509      */
510     @Test
511     void testSkipNone() throws Throwable {
512         final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
513         try (Base64InputStream b64stream = new Base64InputStream(ins)) {
514             final byte[] actualBytes = new byte[6];
515             assertEquals(0, b64stream.skip(0));
516             b64stream.read(actualBytes, 0, actualBytes.length);
517             assertArrayEquals(actualBytes, new byte[] { 0, 0, 0, (byte) 255, (byte) 255, (byte) 255 });
518             // End of stream reached
519             assertEquals(-1, b64stream.read());
520         }
521     }
522 
523     /**
524      * Tests skipping past the end of a stream.
525      *
526      * @throws Throwable
527      *             for some failure scenarios.
528      */
529     @Test
530     void testSkipPastEnd() throws Throwable {
531         final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
532         try (Base64InputStream b64stream = new Base64InputStream(ins)) {
533             // due to CODEC-130, skip now skips correctly decoded characters rather than encoded
534             assertEquals(6, b64stream.skip(10));
535             // End of stream reached
536             assertEquals(-1, b64stream.read());
537             assertEquals(-1, b64stream.read());
538         }
539     }
540 
541     /**
542      * Tests skipping to the end of a stream.
543      *
544      * @throws Throwable
545      *             for some failure scenarios.
546      */
547     @Test
548     void testSkipToEnd() throws Throwable {
549         final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
550         try (Base64InputStream b64stream = new Base64InputStream(ins)) {
551             // due to CODEC-130, skip now skips correctly decoded characters rather than encoded
552             assertEquals(6, b64stream.skip(6));
553             // End of stream reached
554             assertEquals(-1, b64stream.read());
555             assertEquals(-1, b64stream.read());
556         }
557     }
558 
559     /**
560      * Tests if negative arguments to skip are handled correctly.
561      *
562      * @throws Throwable
563      *             for some failure scenarios.
564      */
565     @Test
566     void testSkipWrongArgument() throws Throwable {
567         final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
568         try (Base64InputStream b64stream = new Base64InputStream(ins)) {
569             assertThrows(IllegalArgumentException.class, () -> b64stream.skip(-10));
570         }
571     }
572 
573     /**
574      * Test strict decoding.
575      *
576      * @throws Exception
577      *             for some failure scenarios.
578      */
579     @Test
580     void testStrictDecoding() throws Exception {
581         for (final String s : Base64Test.BASE64_IMPOSSIBLE_CASES) {
582             final byte[] encoded = StringUtils.getBytesUtf8(s);
583             final Base64InputStream in = new Base64InputStream(new ByteArrayInputStream(encoded), false);
584             // Default is lenient decoding; it should not throw
585             assertFalse(in.isStrictDecoding());
586             IOUtils.toByteArray(in);
587             // Strict decoding should throw
588             final Base64InputStream in2 = new Base64InputStream(new ByteArrayInputStream(encoded), false, 0, null, CodecPolicy.STRICT);
589             assertTrue(in2.isStrictDecoding());
590             assertThrows(IllegalArgumentException.class, () -> IOUtils.toByteArray(in2));
591             // Same with a builder
592             try (Base64InputStream in3 = Base64InputStream.builder()
593                     .setByteArray(encoded)
594                     .setEncode(false)
595                     .setBaseNCodec(Base64.builder().setLineLength(0).setLineSeparator(null).setDecodingPolicy(CodecPolicy.STRICT).get())
596                     .get()) {
597                 assertTrue(in3.isStrictDecoding());
598                 assertThrows(IllegalArgumentException.class, () -> IOUtils.toByteArray(in3));
599             }
600         }
601     }
602 }