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.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.nio.charset.Charset;
30  import java.nio.charset.StandardCharsets;
31  import java.util.Arrays;
32  
33  import org.apache.commons.codec.CodecPolicy;
34  import org.apache.commons.codec.DecoderException;
35  import org.apache.commons.lang3.ArrayUtils;
36  import org.junit.jupiter.api.Test;
37  
38  /**
39   * Tests {@link Base32}.
40   */
41  class Base32Test {
42  
43      private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;
44  
45      /** RFC 4648. */
46      // @formatter:off
47      private static final String [][] BASE32_TEST_CASES = {
48          { ""       , "" },
49          { "f"      , "MY======" },
50          { "fo"     , "MZXQ====" },
51          { "foo"    , "MZXW6===" },
52          { "foob"   , "MZXW6YQ=" },
53          { "fooba"  , "MZXW6YTB" },
54          { "foobar" , "MZXW6YTBOI======" }
55      };
56      // @formatter:on
57  
58      /**
59       * Example test cases with valid characters but impossible combinations of
60       * trailing characters (i.e. cannot be created during encoding).
61       */
62      // @formatter:off
63      static final String[] BASE32_IMPOSSIBLE_CASES = {
64          "MC======",
65          "MZXE====",
66          "MZXWB===",
67          "MZXW6YB=",
68          "MZXW6YTBOC======",
69          "AB======"
70          };
71      // @formatter:on
72  
73      // @formatter:off
74      private static final String[] BASE32_IMPOSSIBLE_CASES_CHUNKED = {
75          "M2======\r\n",
76          "MZX0====\r\n",
77          "MZXW0===\r\n",
78          "MZXW6Y2=\r\n",
79          "MZXW6YTBO2======\r\n"
80      };
81      // @formatter:on
82  
83      // @formatter:off
84      private static final String[] BASE32HEX_IMPOSSIBLE_CASES = {
85          "C2======",
86          "CPN4====",
87          "CPNM1===",
88          "CPNMUO1=",
89          "CPNMUOJ1E2======"
90      };
91      // @formatter:on
92  
93      /**
94       * Copy of the standard base-32 encoding table. Used to test decoding the final
95       * character of encoded bytes.
96       */
97      // @formatter:off
98      private static final byte[] ENCODE_TABLE = {
99              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
100             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
101             '2', '3', '4', '5', '6', '7'
102     };
103     // @formatter:on
104 
105     private static final Object[][] BASE32_BINARY_TEST_CASES;
106 
107 //            { null, "O0o0O0o0" }
108 //            BASE32_BINARY_TEST_CASES[2][0] = new Hex().decode("739ce739ce");
109 
110     static {
111         final Hex hex = new Hex();
112         try {
113             BASE32_BINARY_TEST_CASES = new Object[][] {
114                     new Object[] { hex.decode("623a01735836e9a126e12fbf95e013ee6892997c"),
115                                    "MI5AC42YG3U2CJXBF67ZLYAT5ZUJFGL4" },
116                     new Object[] { hex.decode("623a01735836e9a126e12fbf95e013ee6892997c"),
117                                    "mi5ac42yg3u2cjxbf67zlyat5zujfgl4" },
118                     new Object[] { hex.decode("739ce42108"),
119                                    "OOOOIIII" }
120             };
121         } catch (final DecoderException de) {
122             throw new AssertionError(":(", de);
123         }
124     }
125 
126     // @formatter:off
127     private static final String [][] BASE32HEX_TEST_CASES = { // RFC 4648
128         { ""       , "" },
129         { "f"      , "CO======" },
130         { "fo"     , "CPNG====" },
131         { "foo"    , "CPNMU===" },
132         { "foob"   , "CPNMUOG=" },
133         { "fooba"  , "CPNMUOJ1" },
134         { "foobar" , "CPNMUOJ1E8======" }
135     };
136     // @formatter:on
137 
138     // @formatter:off
139     private static final String [][] BASE32_TEST_CASES_CHUNKED = { //Chunked
140         { ""       , "" },
141         { "f"      , "MY======\r\n" },
142         { "fo"     , "MZXQ====\r\n" },
143         { "foo"    , "MZXW6===\r\n" },
144         { "foob"   , "MZXW6YQ=\r\n" },
145         { "fooba"  , "MZXW6YTB\r\n" },
146         { "foobar" , "MZXW6YTBOI======\r\n" }
147     };
148     // @formatter:on
149 
150     // @formatter:off
151     private static final String [][] BASE32_PAD_TEST_CASES = { // RFC 4648
152         { ""       , "" },
153         { "f"      , "MY%%%%%%" },
154         { "fo"     , "MZXQ%%%%" },
155         { "foo"    , "MZXW6%%%" },
156         { "foob"   , "MZXW6YQ%" },
157         { "fooba"  , "MZXW6YTB" },
158         { "foobar" , "MZXW6YTBOI%%%%%%" }
159     };
160     // @formatter:on
161 
162     /**
163      * Test base 32 decoding of the final trailing bits. Trailing encoded bytes
164      * cannot fit exactly into 5-bit characters so the last character has a limited
165      * alphabet where the final bits are zero. This asserts that illegal final
166      * characters throw an exception when decoding.
167      *
168      * @param nbits the number of trailing bits (must be a factor of 5 and {@code <40})
169      */
170     private static void assertBase32DecodingOfTrailingBits(final int nbits) {
171         // Requires strict decoding
172         final Base32 codec = new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT);
173         assertTrue(codec.isStrictDecoding());
174         assertEquals(CodecPolicy.STRICT, codec.getCodecPolicy());
175         // A lenient decoder should not re-encode to the same bytes
176         final Base32 defaultCodec = new Base32();
177         assertFalse(defaultCodec.isStrictDecoding());
178         assertEquals(CodecPolicy.LENIENT, defaultCodec.getCodecPolicy());
179 
180         // Create the encoded bytes. The first characters must be valid so fill with 'zero'
181         // then pad to the block size.
182         final int length = nbits / 5;
183         final byte[] encoded = new byte[8];
184         Arrays.fill(encoded, 0, length, ENCODE_TABLE[0]);
185         Arrays.fill(encoded, length, encoded.length, (byte) '=');
186         // Compute how many bits would be discarded from 8-bit bytes
187         final int discard = nbits % 8;
188         final int emptyBitsMask = (1 << discard) - 1;
189         // Special case when an impossible number of trailing characters
190         final boolean invalid = length == 1 || length == 3 || length == 6;
191         // Enumerate all 32 possible final characters in the last position
192         final int last = length - 1;
193         for (int i = 0; i < 32; i++) {
194             encoded[last] = ENCODE_TABLE[i];
195             // If the lower bits are set we expect an exception. This is not a valid
196             // final character.
197             if (invalid || (i & emptyBitsMask) != 0) {
198                 assertThrows(IllegalArgumentException.class, () -> codec.decode(encoded), "Final base-32 digit should not be allowed");
199                 // The default lenient mode should decode this
200                 final byte[] decoded = defaultCodec.decode(encoded);
201                 // Re-encoding should not match the original array as it was invalid
202                 assertFalse(Arrays.equals(encoded, defaultCodec.encode(decoded)));
203             } else {
204                 // Otherwise this should decode
205                 final byte[] decoded = codec.decode(encoded);
206                 // Compute the bits that were encoded. This should match the final decoded byte.
207                 final int bitsEncoded = i >> discard;
208                 assertEquals(bitsEncoded, decoded[decoded.length - 1], "Invalid decoding of last character");
209                 // Re-encoding should match the original array (requires the same padding character)
210                 assertArrayEquals(encoded, codec.encode(decoded));
211             }
212         }
213     }
214 
215     @Test
216     void testBase32AtBufferEnd() {
217         testBase32InBuffer(100, 0);
218     }
219 
220     @Test
221     void testBase32AtBufferMiddle() {
222         testBase32InBuffer(100, 100);
223     }
224 
225     @Test
226     void testBase32AtBufferStart() {
227         testBase32InBuffer(0, 100);
228     }
229 
230     @Test
231     void testBase32BinarySamples() throws Exception {
232         final Base32 codec = new Base32();
233         for (final Object[] element : BASE32_BINARY_TEST_CASES) {
234             final String expected;
235             if (element.length > 2) {
236                 expected = (String) element[2];
237             } else {
238                 expected = (String) element[1];
239             }
240             assertEquals(expected.toUpperCase(), codec.encodeAsString((byte[]) element[0]));
241         }
242     }
243 
244     @Test
245     void testBase32BinarySamplesReverse() throws Exception {
246         final Base32 codec = new Base32();
247         for (final Object[] element : BASE32_BINARY_TEST_CASES) {
248             assertArrayEquals((byte[]) element[0], codec.decode((String) element[1]));
249         }
250     }
251 
252     @Test
253     void testBase32Chunked() throws Exception {
254         final Base32 codec = new Base32(20);
255         for (final String[] element : BASE32_TEST_CASES_CHUNKED) {
256             assertEquals(element[1], codec.encodeAsString(element[0].getBytes(CHARSET_UTF8)));
257         }
258     }
259 
260     @Test
261     void testBase32DecodingOfTrailing10Bits() {
262         assertBase32DecodingOfTrailingBits(10);
263     }
264 
265     @Test
266     void testBase32DecodingOfTrailing15Bits() {
267         assertBase32DecodingOfTrailingBits(15);
268     }
269 
270     @Test
271     void testBase32DecodingOfTrailing20Bits() {
272         assertBase32DecodingOfTrailingBits(20);
273     }
274 
275     @Test
276     void testBase32DecodingOfTrailing25Bits() {
277         assertBase32DecodingOfTrailingBits(25);
278     }
279 
280     @Test
281     void testBase32DecodingOfTrailing30Bits() {
282         assertBase32DecodingOfTrailingBits(30);
283     }
284 
285     @Test
286     void testBase32DecodingOfTrailing35Bits() {
287         assertBase32DecodingOfTrailingBits(35);
288     }
289 
290     @Test
291     void testBase32DecodingOfTrailing5Bits() {
292         assertBase32DecodingOfTrailingBits(5);
293     }
294 
295     @Test
296     void testBase32HexImpossibleSamples() {
297         testImpossibleCases(new Base32(0, null, true, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT), BASE32HEX_IMPOSSIBLE_CASES);
298         // @formatter:off
299         testImpossibleCases(Base32.builder()
300                 .setHexEncodeTable(true)
301                 .setDecodingPolicy(CodecPolicy.STRICT)
302                 .get(), BASE32HEX_IMPOSSIBLE_CASES);
303         // @formatter:on
304         // overrides, last set wins
305         // @formatter:off
306         testImpossibleCases(Base32.builder()
307                 .setHexDecodeTable(false)
308                 .setHexDecodeTable(true)
309                 .setHexEncodeTable(false)
310                 .setHexEncodeTable(true)
311                 .setDecodingPolicy(CodecPolicy.STRICT)
312                 .get(), BASE32HEX_IMPOSSIBLE_CASES);
313         // @formatter:on
314     }
315 
316     @Test
317     void testBase32HexSamples() throws Exception {
318         final Base32 codec = new Base32(true);
319         for (final String[] element : BASE32HEX_TEST_CASES) {
320             assertEquals(element[1], codec.encodeAsString(element[0].getBytes(CHARSET_UTF8)));
321         }
322     }
323 
324     @Test
325     void testBase32HexSamplesReverse() throws Exception {
326         final Base32 codec = new Base32(true);
327         for (final String[] element : BASE32HEX_TEST_CASES) {
328             assertEquals(element[0], new String(codec.decode(element[1]), CHARSET_UTF8));
329         }
330     }
331 
332     @Test
333     void testBase32HexSamplesReverseLowercase() throws Exception {
334         final Base32 codec = new Base32(true);
335         for (final String[] element : BASE32HEX_TEST_CASES) {
336             assertEquals(element[0], new String(codec.decode(element[1].toLowerCase()), CHARSET_UTF8));
337         }
338     }
339 
340     @Test
341     void testBase32ImpossibleChunked() {
342         testImpossibleCases(new Base32(20, BaseNCodec.CHUNK_SEPARATOR, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT), BASE32_IMPOSSIBLE_CASES_CHUNKED);
343     }
344 
345     @Test
346     void testBase32ImpossibleSamples() {
347         testImpossibleCases(new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT), BASE32_IMPOSSIBLE_CASES);
348     }
349 
350     private void testBase32InBuffer(final int startPasSize, final int endPadSize) {
351         final Base32 codec = new Base32();
352         for (final String[] element : BASE32_TEST_CASES) {
353             final byte[] bytes = element[0].getBytes(CHARSET_UTF8);
354             byte[] buffer = ArrayUtils.addAll(bytes, new byte[endPadSize]);
355             buffer = ArrayUtils.addAll(new byte[startPasSize], buffer);
356             assertEquals(element[1], StringUtils.newStringUtf8(codec.encode(buffer, startPasSize, bytes.length)));
357         }
358     }
359 
360     @Test
361     void testBase32Samples() throws Exception {
362         final Base32 codec = new Base32();
363         for (final String[] element : BASE32_TEST_CASES) {
364             assertEquals(element[1], codec.encodeAsString(element[0].getBytes(CHARSET_UTF8)));
365         }
366     }
367 
368     @Test
369     void testBase32SamplesNonDefaultPadding() throws Exception {
370         final Base32 codec = new Base32((byte) 0x25); // '%' <=> 0x25
371 
372         for (final String[] element : BASE32_PAD_TEST_CASES) {
373             assertEquals(element[1], codec.encodeAsString(element[0].getBytes(CHARSET_UTF8)));
374         }
375     }
376 
377     @Test
378     void testBuilderCodecPolicy() {
379         assertEquals(CodecPolicy.LENIENT, Base32.builder().get().getCodecPolicy());
380         assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(CodecPolicy.LENIENT).get().getCodecPolicy());
381         assertEquals(CodecPolicy.STRICT, Base32.builder().setDecodingPolicy(CodecPolicy.STRICT).get().getCodecPolicy());
382         assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(CodecPolicy.STRICT).setDecodingPolicy(null).get().getCodecPolicy());
383         assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(null).get().getCodecPolicy());
384     }
385 
386     @Test
387     void testBuilderLineAttributes() {
388         assertNull(Base32.builder().get().getLineSeparator());
389         assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
390         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
391         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator());
392         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator());
393         assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator());
394         assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator());
395         assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator());
396         assertEquals("MZXXQ===", Base32.builder().setLineLength(4).get().encodeToString("fox".getBytes(CHARSET_UTF8)));
397     }
398 
399     @Test
400     void testBuilderPadingByte() {
401         assertNull(Base32.builder().get().getLineSeparator());
402         assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
403         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
404         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator());
405         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator());
406         assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator());
407         assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator());
408         assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator());
409         assertEquals("MZXXQ___", Base32.builder().setLineLength(4).setPadding((byte) '_').get().encodeToString("fox".getBytes(CHARSET_UTF8)));
410     }
411 
412     @Test
413     void testCodec200() {
414         final Base32 codec = new Base32(true, (byte) 'W'); // should be allowed
415         assertNotNull(codec);
416     }
417 
418     @Test
419     void testConstructors() {
420         Base32 base32;
421         base32 = new Base32();
422         base32 = new Base32(-1);
423         base32 = new Base32(-1, new byte[] {});
424         base32 = new Base32(32, new byte[] {});
425         base32 = new Base32(32, new byte[] {}, false);
426         // This is different behavior than Base64 which validates the separator
427         // even when line length is negative.
428         base32 = new Base32(-1, new byte[] { 'A' });
429         base32 = new Base32(32, new byte[] { '$' }); // OK
430         assertThrows(IllegalArgumentException.class, () -> new Base32(32, null), "null line separator");
431         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { 'A' }), "'A' as a line separator");
432         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '=' }), "'=' as a line separator");
433         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { 'A', '$' }), "'A$' as a line separator");
434         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '\n' }, false, (byte) 'A'), "'A' as padding");
435         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '\n' }, false, (byte) ' '), "' ' as padding");
436 
437         base32 = new Base32(32, new byte[] { ' ', '$', '\n', '\r', '\t' }); // OK
438         assertNotNull(base32);
439     }
440 
441     /**
442      * Test encode and decode of empty byte array.
443      */
444     @Test
445     void testEmptyBase32() {
446         byte[] empty = {};
447         byte[] result = new Base32().encode(empty);
448         assertEquals(0, result.length, "empty Base32 encode");
449         assertNull(new Base32().encode(null), "empty Base32 encode");
450         result = new Base32().encode(empty, 0, 1);
451         assertEquals(0, result.length, "empty Base32 encode with offset");
452         assertNull(new Base32().encode(null), "empty Base32 encode with offset");
453 
454         empty = new byte[0];
455         result = new Base32().decode(empty);
456         assertEquals(0, result.length, "empty Base32 decode");
457         assertNull(new Base32().decode((byte[]) null), "empty Base32 encode");
458     }
459 
460     private void testImpossibleCases(final Base32 codec, final String[] impossible_cases) {
461         for (final String impossible : impossible_cases) {
462             assertThrows(IllegalArgumentException.class, () -> codec.decode(impossible));
463         }
464     }
465 
466     @Test
467     void testIsInAlphabet() {
468         // invalid bounds
469         Base32 b32 = new Base32(true);
470         assertFalse(b32.isInAlphabet((byte) 0));
471         assertFalse(b32.isInAlphabet((byte) 1));
472         assertFalse(b32.isInAlphabet((byte) -1));
473         assertFalse(b32.isInAlphabet((byte) -15));
474         assertFalse(b32.isInAlphabet((byte) -32));
475         assertFalse(b32.isInAlphabet((byte) 127));
476         assertFalse(b32.isInAlphabet((byte) 128));
477         assertFalse(b32.isInAlphabet((byte) 255));
478 
479         // default table
480         b32 = new Base32(false);
481         for (char c = '2'; c <= '7'; c++) {
482             assertTrue(b32.isInAlphabet((byte) c));
483         }
484         for (char c = 'A'; c <= 'Z'; c++) {
485             assertTrue(b32.isInAlphabet((byte) c));
486         }
487         for (char c = 'a'; c <= 'z'; c++) {
488             assertTrue(b32.isInAlphabet((byte) c));
489         }
490         assertFalse(b32.isInAlphabet((byte) '1'));
491         assertFalse(b32.isInAlphabet((byte) '8'));
492         assertFalse(b32.isInAlphabet((byte) ('A' - 1)));
493         assertFalse(b32.isInAlphabet((byte) ('Z' + 1)));
494 
495         // hex table
496         b32 = new Base32(true);
497         for (char c = '0'; c <= '9'; c++) {
498             assertTrue(b32.isInAlphabet((byte) c));
499         }
500         for (char c = 'A'; c <= 'V'; c++) {
501             assertTrue(b32.isInAlphabet((byte) c));
502         }
503         for (char c = 'a'; c <= 'v'; c++) {
504             assertTrue(b32.isInAlphabet((byte) c));
505         }
506         assertFalse(b32.isInAlphabet((byte) ('0' - 1)));
507         assertFalse(b32.isInAlphabet((byte) ('9' + 1)));
508         assertFalse(b32.isInAlphabet((byte) ('A' - 1)));
509         assertFalse(b32.isInAlphabet((byte) ('V' + 1)));
510         assertFalse(b32.isInAlphabet((byte) ('a' - 1)));
511         assertFalse(b32.isInAlphabet((byte) ('v' + 1)));
512     }
513 
514     @Test
515     void testRandomBytes() {
516         for (int i = 0; i < 20; i++) {
517             final Base32 codec = new Base32();
518             final byte[][] b = BaseNTestData.randomData(codec, i);
519             assertEquals(b[1].length, codec.getEncodedLength(b[0]), i + " " + codec.lineLength);
520             // assertEquals(b[0], codec.decode(b[1]));
521         }
522     }
523 
524     @Test
525     void testRandomBytesChunked() {
526         for (int i = 0; i < 20; i++) {
527             final Base32 codec = new Base32(10);
528             final byte[][] b = BaseNTestData.randomData(codec, i);
529             assertEquals(b[1].length, codec.getEncodedLength(b[0]), i + " " + codec.lineLength);
530             // assertEquals(b[0], codec.decode(b[1]));
531         }
532     }
533 
534     @Test
535     void testRandomBytesHex() {
536         for (int i = 0; i < 20; i++) {
537             final Base32 codec = new Base32(true);
538             final byte[][] b = BaseNTestData.randomData(codec, i);
539             assertEquals(b[1].length, codec.getEncodedLength(b[0]), i + " " + codec.lineLength);
540             // assertEquals(b[0], codec.decode(b[1]));
541         }
542     }
543 
544     @Test
545     void testSingleCharEncoding() {
546         for (int i = 0; i < 20; i++) {
547             Base32 codec = new Base32();
548             final BaseNCodec.Context context = new BaseNCodec.Context();
549             final byte[] unencoded = new byte[i];
550             final byte[] allInOne = codec.encode(unencoded);
551             codec = new Base32();
552             for (int j = 0; j < unencoded.length; j++) {
553                 codec.encode(unencoded, j, 1, context);
554             }
555             codec.encode(unencoded, 0, -1, context);
556             final byte[] singly = new byte[allInOne.length];
557             codec.readResults(singly, 0, 100, context);
558             if (!Arrays.equals(allInOne, singly)) {
559                 fail();
560             }
561         }
562     }
563 }