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