1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.codec.binary;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26 import static org.junit.jupiter.api.Assumptions.assumeTrue;
27
28 import org.apache.commons.codec.binary.BaseNCodec.Context;
29 import org.junit.jupiter.api.BeforeEach;
30 import org.junit.jupiter.api.Test;
31
32 public class BaseNCodecTest {
33
34
35
36
37
38 private static final class NoOpBaseNCodec extends BaseNCodec {
39 NoOpBaseNCodec() {
40 super(0, 0, 0, 0);
41 }
42
43 @Override
44 void decode(final byte[] pArray, final int i, final int length, final Context context) {
45
46 }
47
48 @Override
49 void encode(final byte[] pArray, final int i, final int length, final Context context) {
50
51 }
52
53 @Override
54 protected boolean isInAlphabet(final byte value) {
55 return false;
56 }
57 }
58
59 private static void assertEnsureBufferSizeExpandsToMaxBufferSize(final boolean exceedMaxBufferSize) {
60
61
62
63
64
65
66
67
68
69 final int length = 0;
70
71 final long presumableFreeMemory = getPresumableFreeMemory();
72
73
74
75
76 final long estimatedMemory = (1L << 31) + 32 * 1024 + length;
77 assumeTrue(presumableFreeMemory > estimatedMemory, "Not enough free memory for the test");
78
79 final int max = Integer.MAX_VALUE - 8;
80
81
82
83 if (exceedMaxBufferSize) {
84 assumeCanAllocateBufferSize(max + 1);
85
86
87 System.gc();
88 }
89
90 final BaseNCodec ncodec = new NoOpBaseNCodec();
91 final Context context = new Context();
92
93
94 context.buffer = new byte[length];
95 context.pos = length;
96
97 int extra = max - length;
98 if (exceedMaxBufferSize) {
99 extra++;
100 }
101 ncodec.ensureBufferSize(extra, context);
102 assertTrue(context.buffer.length >= length + extra);
103 }
104
105
106
107
108 private static void assumeCanAllocateBufferSize(final int size) {
109 byte[] bytes = null;
110 try {
111 bytes = new byte[size];
112 } catch (final OutOfMemoryError ignore) {
113
114 }
115 assumeTrue(bytes != null, "Cannot allocate array of size: " + size);
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 static long getPresumableFreeMemory() {
135 System.gc();
136 final long allocatedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
137 return Runtime.getRuntime().maxMemory() - allocatedMemory;
138 }
139
140 BaseNCodec codec;
141 @BeforeEach
142 public void setUp() {
143 codec = new BaseNCodec(0, 0, 0, 0) {
144 @Override
145 void decode(final byte[] pArray, final int i, final int length, final Context context) {
146 }
147
148 @Override
149 void encode(final byte[] pArray, final int i, final int length, final Context context) {
150 }
151
152 @Override
153 protected boolean isInAlphabet(final byte b) {
154 return b=='O' || b == 'K';
155 }
156 };
157 }
158
159 @Test
160 public void testBaseNCodec() {
161 assertNotNull(codec);
162 }
163
164 @Test
165 public void testContainsAlphabetOrPad() {
166 assertFalse(codec.containsAlphabetOrPad(null));
167 assertFalse(codec.containsAlphabetOrPad(new byte[]{}));
168 assertTrue(codec.containsAlphabetOrPad("OK".getBytes()));
169 assertTrue(codec.containsAlphabetOrPad("OK ".getBytes()));
170 assertFalse(codec.containsAlphabetOrPad("ok ".getBytes()));
171 assertTrue(codec.containsAlphabetOrPad(new byte[]{codec.pad}));
172 }
173
174
175
176
177
178
179 @Test
180 public void testContextToString() {
181 final Context context = new Context();
182 context.buffer = new byte[3];
183 context.currentLinePos = 13;
184 context.eof = true;
185 context.ibitWorkArea = 777;
186 context.lbitWorkArea = 999;
187 context.modulus = 5;
188 context.pos = 42;
189 context.readPos = 981;
190 final String text = context.toString();
191 assertTrue(text.contains("[0, 0, 0]"));
192 assertTrue(text.contains("13"));
193 assertTrue(text.contains("true"));
194 assertTrue(text.contains("777"));
195 assertTrue(text.contains("999"));
196 assertTrue(text.contains("5"));
197 assertTrue(text.contains("42"));
198 assertTrue(text.contains("981"));
199 }
200
201
202
203
204
205
206 @Test
207 public void testEnsureBufferSize() {
208 final BaseNCodec ncodec = new NoOpBaseNCodec();
209 final Context context = new Context();
210 assertNull(context.buffer, "Initial buffer should be null");
211
212
213 context.pos = 76979;
214 context.readPos = 273;
215 ncodec.ensureBufferSize(0, context);
216 assertNotNull(context.buffer, "buffer should be initialized");
217 assertEquals(ncodec.getDefaultBufferSize(), context.buffer.length, "buffer should be initialized to default size");
218 assertEquals(0, context.pos, "context position");
219 assertEquals(0, context.readPos, "context read position");
220
221
222 ncodec.ensureBufferSize(1, context);
223 assertEquals(ncodec.getDefaultBufferSize(), context.buffer.length, "buffer should not expand unless required");
224
225
226 int length = context.buffer.length;
227 context.pos = length;
228 int extra = 1;
229 ncodec.ensureBufferSize(extra, context);
230 assertTrue(context.buffer.length >= length + extra, "buffer should expand");
231
232
233
234 length = context.buffer.length;
235 context.pos = length;
236 extra = length * 10;
237 ncodec.ensureBufferSize(extra, context);
238 assertTrue(context.buffer.length >= length + extra, "buffer should expand beyond double capacity");
239 }
240
241
242
243
244
245
246
247 @Test
248 public void testEnsureBufferSizeExpandsToBeyondMaxBufferSize() {
249 assertEnsureBufferSizeExpandsToMaxBufferSize(true);
250 }
251
252
253
254
255 @Test
256 public void testEnsureBufferSizeExpandsToMaxBufferSize() {
257 assertEnsureBufferSizeExpandsToMaxBufferSize(false);
258 }
259
260 @Test
261 public void testEnsureBufferSizeThrowsOnOverflow() {
262 final BaseNCodec ncodec = new NoOpBaseNCodec();
263 final Context context = new Context();
264
265 final int length = 10;
266 context.buffer = new byte[length];
267 context.pos = length;
268 final int extra = Integer.MAX_VALUE;
269 assertThrows(OutOfMemoryError.class, () -> ncodec.ensureBufferSize(extra, context));
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318 @Test
319 public void testIsInAlphabetByte() {
320 assertFalse(codec.isInAlphabet((byte) 0));
321 assertFalse(codec.isInAlphabet((byte) 'a'));
322 assertTrue(codec.isInAlphabet((byte) 'O'));
323 assertTrue(codec.isInAlphabet((byte) 'K'));
324 }
325
326 @Test
327 public void testIsInAlphabetByteArrayBoolean() {
328 assertTrue(codec.isInAlphabet(new byte[] {}, false));
329 assertTrue(codec.isInAlphabet(new byte[] { 'O' }, false));
330 assertFalse(codec.isInAlphabet(new byte[] { 'O', ' ' }, false));
331 assertFalse(codec.isInAlphabet(new byte[] { ' ' }, false));
332 assertTrue(codec.isInAlphabet(new byte[] {}, true));
333 assertTrue(codec.isInAlphabet(new byte[] { 'O' }, true));
334 assertTrue(codec.isInAlphabet(new byte[] { 'O', ' ' }, true));
335 assertTrue(codec.isInAlphabet(new byte[] { ' ' }, true));
336 }
337
338 @Test
339 public void testIsInAlphabetString() {
340 assertTrue(codec.isInAlphabet("OK"));
341 assertTrue(codec.isInAlphabet("O=K= \t\n\r"));
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364 @Test
365 public void testIsWhiteSpace() {
366 assertTrue(Character.isWhitespace((byte) ' '));
367 assertTrue(Character.isWhitespace((byte) '\n'));
368 assertTrue(Character.isWhitespace((byte) '\r'));
369 assertTrue(Character.isWhitespace((byte) '\t'));
370 assertTrue(Character.isWhitespace((byte) '\f'));
371 assertTrue(Character.isWhitespace((byte) '\u000B'));
372 for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
373 final byte byteToCheck = b;
374 assertEquals(Character.isWhitespace(b), Character.isWhitespace(byteToCheck));
375 }
376 }
377
378 @Test
379 public void testProvidePaddingByte() {
380
381 codec = new BaseNCodec(0, 0, 0, 0, (byte) 0x25) {
382 @Override
383 void decode(final byte[] pArray, final int i, final int length, final Context context) {
384
385 }
386
387 @Override
388 void encode(final byte[] pArray, final int i, final int length, final Context context) {
389
390 }
391
392 @Override
393 protected boolean isInAlphabet(final byte b) {
394 return b == 'O' || b == 'K';
395 }
396 };
397
398
399 final byte actualPaddingByte = codec.pad;
400
401
402 assertEquals(0x25, actualPaddingByte);
403 }
404 }