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 testBuilderCustomEncodeTableAffectsDecodeTable() {
394         final byte[] encodeTable = ENCODE_TABLE.clone();
395         final byte temp = encodeTable[0];
396         encodeTable[0] = encodeTable[1];
397         encodeTable[1] = temp;
398         final Base32 base32 = Base32.builder().setEncodeTable(encodeTable).setLineLength(0).get();
399         final byte[] data = { 0 };
400         final byte[] encoded = base32.encode(data);
401         assertEquals("BB======", new String(encoded, StandardCharsets.US_ASCII));
402         assertArrayEquals(data, base32.decode(encoded));
403     }
404 
405     @Test
406     void testBuilderCustomEncodeTableRejectsDuplicateEntries() {
407         final byte[] encodeTable = ENCODE_TABLE.clone();
408         encodeTable[1] = encodeTable[0];
409         assertThrows(IllegalArgumentException.class, () -> Base32.builder().setEncodeTable(encodeTable));
410     }
411 
412     @Test
413     void testBuilderCustomEncodeTableRejectsInvalidLength() {
414         assertThrows(IllegalArgumentException.class, () -> Base32.builder().setEncodeTable(Arrays.copyOf(ENCODE_TABLE, ENCODE_TABLE.length - 1)));
415     }
416 
417     @Test
418     void testBuilderCustomEncodeTableWithNonAsciiBytes() {
419         final byte[] encodeTable = new byte[32];
420         for (int i = 0; i < encodeTable.length; i++) {
421             encodeTable[i] = (byte) (0x80 + i);
422         }
423         final Base32 base32 = Base32.builder().setEncodeTable(encodeTable).setLineLength(0).get();
424         final byte[] data = { 0 };
425         final byte[] encoded = base32.encode(data);
426         assertArrayEquals(new byte[] { (byte) 0x80, (byte) 0x80, '=', '=', '=', '=', '=', '=' }, encoded);
427         assertTrue(base32.isInAlphabet((byte) 0x80));
428         assertArrayEquals(data, base32.decode(encoded));
429     }
430 
431     @Test
432     void testBuilderLineAttributes() {
433         assertNull(Base32.builder().get().getLineSeparator());
434         assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
435         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
436         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator());
437         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator());
438         assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator());
439         assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator());
440         assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator());
441         assertEquals("MZXXQ===", Base32.builder().setLineLength(4).get().encodeToString("fox".getBytes(CHARSET_UTF8)));
442     }
443 
444     @Test
445     void testBuilderPadingByte() {
446         assertNull(Base32.builder().get().getLineSeparator());
447         assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
448         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
449         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator());
450         assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator());
451         assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator());
452         assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator());
453         assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator());
454         assertEquals("MZXXQ___", Base32.builder().setLineLength(4).setPadding((byte) '_').get().encodeToString("fox".getBytes(CHARSET_UTF8)));
455     }
456 
457     @Test
458     void testBuilderSetHexDecodeTableDecodesOwnOutput() {
459         final Base32 base32 = Base32.builder().setHexDecodeTable(true).setLineLength(0).get();
460         final byte[] data = { 0 };
461         final byte[] encoded = base32.encode(data);
462         assertEquals("00======", new String(encoded, StandardCharsets.US_ASCII));
463         assertArrayEquals(data, base32.decode(encoded));
464     }
465 
466     @Test
467     void testCodec200() {
468         final Base32 codec = new Base32(true, (byte) 'W'); // should be allowed
469         assertNotNull(codec);
470     }
471 
472     @Test
473     void testConstructors() {
474         Base32 base32;
475         base32 = new Base32();
476         base32 = new Base32(-1);
477         base32 = new Base32(-1, new byte[] {});
478         base32 = new Base32(32, new byte[] {});
479         base32 = new Base32(32, new byte[] {}, false);
480         // This is different behavior than Base64 which validates the separator
481         // even when line length is negative.
482         base32 = new Base32(-1, new byte[] { 'A' });
483         base32 = new Base32(32, new byte[] { '$' }); // OK
484         assertArrayEquals(new byte[0], new Base32(32, null).getLineSeparator(), "null line separator use an empty array");
485         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { 'A' }), "'A' as a line separator");
486         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '=' }), "'=' as a line separator");
487         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { 'A', '$' }), "'A$' as a line separator");
488         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '\n' }, false, (byte) 'A'), "'A' as padding");
489         assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '\n' }, false, (byte) ' '), "' ' as padding");
490         base32 = new Base32(32, new byte[] { ' ', '$', '\n', '\r', '\t' }); // OK
491         assertNotNull(base32);
492     }
493 
494     /**
495      * Test encode and decode of empty byte array.
496      */
497     @Test
498     void testEmptyBase32() {
499         byte[] empty = {};
500         byte[] result = new Base32().encode(empty);
501         assertEquals(0, result.length, "empty Base32 encode");
502         assertNull(new Base32().encode(null), "empty Base32 encode");
503         result = new Base32().encode(empty, 0, 1);
504         assertEquals(0, result.length, "empty Base32 encode with offset");
505         assertNull(new Base32().encode(null), "empty Base32 encode with offset");
506 
507         empty = new byte[0];
508         result = new Base32().decode(empty);
509         assertEquals(0, result.length, "empty Base32 decode");
510         assertNull(new Base32().decode((byte[]) null), "empty Base32 encode");
511     }
512 
513     private void testImpossibleCases(final Base32 codec, final String[] impossible_cases) {
514         for (final String impossible : impossible_cases) {
515             assertThrows(IllegalArgumentException.class, () -> codec.decode(impossible));
516         }
517     }
518 
519     @Test
520     void testIsInAlphabet() {
521         // invalid bounds
522         Base32 b32 = new Base32(true);
523         assertFalse(b32.isInAlphabet((byte) 0));
524         assertFalse(b32.isInAlphabet((byte) 1));
525         assertFalse(b32.isInAlphabet((byte) -1));
526         assertFalse(b32.isInAlphabet((byte) -15));
527         assertFalse(b32.isInAlphabet((byte) -32));
528         assertFalse(b32.isInAlphabet((byte) 127));
529         assertFalse(b32.isInAlphabet((byte) 128));
530         assertFalse(b32.isInAlphabet((byte) 255));
531 
532         // default table
533         b32 = new Base32(false);
534         for (char c = '2'; c <= '7'; c++) {
535             assertTrue(b32.isInAlphabet((byte) c));
536         }
537         for (char c = 'A'; c <= 'Z'; c++) {
538             assertTrue(b32.isInAlphabet((byte) c));
539         }
540         for (char c = 'a'; c <= 'z'; c++) {
541             assertTrue(b32.isInAlphabet((byte) c));
542         }
543         assertFalse(b32.isInAlphabet((byte) '1'));
544         assertFalse(b32.isInAlphabet((byte) '8'));
545         assertFalse(b32.isInAlphabet((byte) ('A' - 1)));
546         assertFalse(b32.isInAlphabet((byte) ('Z' + 1)));
547 
548         // hex table
549         b32 = new Base32(true);
550         for (char c = '0'; c <= '9'; c++) {
551             assertTrue(b32.isInAlphabet((byte) c), String.valueOf(c));
552         }
553         for (char c = 'A'; c <= 'V'; c++) {
554             assertTrue(b32.isInAlphabet((byte) c));
555         }
556         for (char c = 'a'; c <= 'v'; c++) {
557             assertTrue(b32.isInAlphabet((byte) c));
558         }
559         assertFalse(b32.isInAlphabet((byte) ('0' - 1)));
560         assertFalse(b32.isInAlphabet((byte) ('9' + 1)));
561         assertFalse(b32.isInAlphabet((byte) ('A' - 1)));
562         assertFalse(b32.isInAlphabet((byte) ('V' + 1)));
563         assertFalse(b32.isInAlphabet((byte) ('a' - 1)));
564         assertFalse(b32.isInAlphabet((byte) ('v' + 1)));
565     }
566 
567     @ParameterizedTest
568     @MethodSource("rangeProvider")
569     void testRandomBytes(final int i) {
570         final Base32 codec = new Base32();
571         final byte[][] b = BaseNTestData.randomData(codec, i);
572         assertEquals(b[1].length, codec.getEncodedLength(b[0]), i + " " + codec.lineLength);
573         // assertEquals(b[0], codec.decode(b[1]));
574     }
575 
576     @ParameterizedTest
577     @MethodSource("rangeProvider")
578     void testRandomBytesChunked(final int i) {
579         final Base32 codec = new Base32(10);
580         final byte[][] b = BaseNTestData.randomData(codec, i);
581         assertEquals(b[1].length, codec.getEncodedLength(b[0]), i + " " + codec.lineLength);
582         // assertEquals(b[0], codec.decode(b[1]));
583     }
584 
585     @ParameterizedTest
586     @MethodSource("rangeProvider")
587     void testRandomBytesHex(final int i) {
588         final Base32 codec = new Base32(true);
589         final byte[][] b = BaseNTestData.randomData(codec, i);
590         assertEquals(b[1].length, codec.getEncodedLength(b[0]), i + " " + codec.lineLength);
591         // assertEquals(b[0], codec.decode(b[1]));
592     }
593 
594     @ParameterizedTest
595     @MethodSource("rangeProvider")
596     void testSingleCharEncoding(final int i) {
597         Base32 codec = new Base32();
598         final BaseNCodec.Context context = new BaseNCodec.Context();
599         final byte[] unencoded = new byte[i];
600         final byte[] allInOne = codec.encode(unencoded);
601         codec = new Base32();
602         for (int j = 0; j < unencoded.length; j++) {
603             codec.encode(unencoded, j, 1, context);
604         }
605         codec.encode(unencoded, 0, -1, context);
606         final byte[] singly = new byte[allInOne.length];
607         codec.readResults(singly, 0, 100, context);
608         assertArrayEquals(allInOne, singly);
609     }
610 }