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