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
143 public void setUp() {
144 codec = new BaseNCodec(0, 0, 0, 0) {
145 @Override
146 void decode(final byte[] pArray, final int i, final int length, final Context context) {
147 }
148
149 @Override
150 void encode(final byte[] pArray, final int i, final int length, final Context context) {
151 }
152
153 @Override
154 protected boolean isInAlphabet(final byte b) {
155 return b == 'O' || b == 'K';
156 }
157 };
158 }
159
160 @Test
161 public void testBaseNCodec() {
162 assertNotNull(codec);
163 }
164
165 @Test
166 public void testContainsAlphabetOrPad() {
167 assertFalse(codec.containsAlphabetOrPad(null));
168 assertFalse(codec.containsAlphabetOrPad(new byte[]{}));
169 assertTrue(codec.containsAlphabetOrPad("OK".getBytes()));
170 assertTrue(codec.containsAlphabetOrPad("OK ".getBytes()));
171 assertFalse(codec.containsAlphabetOrPad("ok ".getBytes()));
172 assertTrue(codec.containsAlphabetOrPad(new byte[]{codec.pad}));
173 }
174
175
176
177
178
179
180 @Test
181 public void testContextToString() {
182 final Context context = new Context();
183 context.buffer = new byte[3];
184 context.currentLinePos = 13;
185 context.eof = true;
186 context.ibitWorkArea = 777;
187 context.lbitWorkArea = 999;
188 context.modulus = 5;
189 context.pos = 42;
190 context.readPos = 981;
191 final String text = context.toString();
192 assertTrue(text.contains("[0, 0, 0]"));
193 assertTrue(text.contains("13"));
194 assertTrue(text.contains("true"));
195 assertTrue(text.contains("777"));
196 assertTrue(text.contains("999"));
197 assertTrue(text.contains("5"));
198 assertTrue(text.contains("42"));
199 assertTrue(text.contains("981"));
200 }
201
202
203
204
205
206
207 @Test
208 public void testEnsureBufferSize() {
209 final BaseNCodec ncodec = new NoOpBaseNCodec();
210 final Context context = new Context();
211 assertNull(context.buffer, "Initial buffer should be null");
212
213
214 context.pos = 76979;
215 context.readPos = 273;
216 ncodec.ensureBufferSize(0, context);
217 assertNotNull(context.buffer, "buffer should be initialized");
218 assertEquals(ncodec.getDefaultBufferSize(), context.buffer.length, "buffer should be initialized to default size");
219 assertEquals(0, context.pos, "context position");
220 assertEquals(0, context.readPos, "context read position");
221
222
223 ncodec.ensureBufferSize(1, context);
224 assertEquals(ncodec.getDefaultBufferSize(), context.buffer.length, "buffer should not expand unless required");
225
226
227 int length = context.buffer.length;
228 context.pos = length;
229 int extra = 1;
230 ncodec.ensureBufferSize(extra, context);
231 assertTrue(context.buffer.length >= length + extra, "buffer should expand");
232
233
234
235 length = context.buffer.length;
236 context.pos = length;
237 extra = length * 10;
238 ncodec.ensureBufferSize(extra, context);
239 assertTrue(context.buffer.length >= length + extra, "buffer should expand beyond double capacity");
240 }
241
242
243
244
245
246
247
248 @Test
249 public void testEnsureBufferSizeExpandsToBeyondMaxBufferSize() {
250 assertEnsureBufferSizeExpandsToMaxBufferSize(true);
251 }
252
253
254
255
256 @Test
257 public void testEnsureBufferSizeExpandsToMaxBufferSize() {
258 assertEnsureBufferSizeExpandsToMaxBufferSize(false);
259 }
260
261 @Test
262 public void testEnsureBufferSizeThrowsOnOverflow() {
263 final BaseNCodec ncodec = new NoOpBaseNCodec();
264 final Context context = new Context();
265
266 final int length = 10;
267 context.buffer = new byte[length];
268 context.pos = length;
269 final int extra = Integer.MAX_VALUE;
270 assertThrows(OutOfMemoryError.class, () -> ncodec.ensureBufferSize(extra, context));
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
319 @Test
320 public void testIsInAlphabetByte() {
321 assertFalse(codec.isInAlphabet((byte) 0));
322 assertFalse(codec.isInAlphabet((byte) 'a'));
323 assertTrue(codec.isInAlphabet((byte) 'O'));
324 assertTrue(codec.isInAlphabet((byte) 'K'));
325 }
326
327 @Test
328 public void testIsInAlphabetByteArrayBoolean() {
329 assertTrue(codec.isInAlphabet(new byte[] {}, false));
330 assertTrue(codec.isInAlphabet(new byte[] { 'O' }, false));
331 assertFalse(codec.isInAlphabet(new byte[] { 'O', ' ' }, false));
332 assertFalse(codec.isInAlphabet(new byte[] { ' ' }, false));
333 assertTrue(codec.isInAlphabet(new byte[] {}, true));
334 assertTrue(codec.isInAlphabet(new byte[] { 'O' }, true));
335 assertTrue(codec.isInAlphabet(new byte[] { 'O', ' ' }, true));
336 assertTrue(codec.isInAlphabet(new byte[] { ' ' }, true));
337 }
338
339 @Test
340 public void testIsInAlphabetString() {
341 assertTrue(codec.isInAlphabet("OK"));
342 assertTrue(codec.isInAlphabet("O=K= \t\n\r"));
343 }
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 @Test
366 public void testIsWhiteSpace() {
367 assertTrue(Character.isWhitespace((byte) ' '));
368 assertTrue(Character.isWhitespace((byte) '\n'));
369 assertTrue(Character.isWhitespace((byte) '\r'));
370 assertTrue(Character.isWhitespace((byte) '\t'));
371 assertTrue(Character.isWhitespace((byte) '\f'));
372 assertTrue(Character.isWhitespace((byte) '\u000B'));
373 for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
374 final byte byteToCheck = b;
375 assertEquals(Character.isWhitespace(b), Character.isWhitespace(byteToCheck));
376 }
377 }
378
379 @Test
380 public void testProvidePaddingByte() {
381
382 codec = new BaseNCodec(0, 0, 0, 0, (byte) 0x25) {
383 @Override
384 void decode(final byte[] pArray, final int i, final int length, final Context context) {
385
386 }
387
388 @Override
389 void encode(final byte[] pArray, final int i, final int length, final Context context) {
390
391 }
392
393 @Override
394 protected boolean isInAlphabet(final byte b) {
395 return b == 'O' || b == 'K';
396 }
397 };
398
399
400 final byte actualPaddingByte = codec.pad;
401
402
403 assertEquals(0x25, actualPaddingByte);
404 }
405 }