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