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
110 static long getPresumableFreeMemory() {
111 System.gc();
112 final long allocatedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
113 return Runtime.getRuntime().maxMemory() - allocatedMemory;
114 }
115
116 BaseNCodec codec;
117
118 @BeforeEach
119 void setUp() {
120 codec = new BaseNCodec(0, 0, 0, 0) {
121 @Override
122 void decode(final byte[] array, final int i, final int length, final Context context) {
123 }
124
125 @Override
126 void encode(final byte[] array, final int i, final int length, final Context context) {
127 }
128
129 @Override
130 protected boolean isInAlphabet(final byte b) {
131 return b == 'O' || b == 'K';
132 }
133 };
134 }
135
136 @Test
137 void testBaseNCodec() {
138 assertNotNull(codec);
139 }
140
141 @Test
142 void testContainsAlphabetOrPad() {
143 assertFalse(codec.containsAlphabetOrPad(null));
144 assertFalse(codec.containsAlphabetOrPad(new byte[]{}));
145 assertTrue(codec.containsAlphabetOrPad("OK".getBytes()));
146 assertTrue(codec.containsAlphabetOrPad("OK ".getBytes()));
147 assertFalse(codec.containsAlphabetOrPad("ok ".getBytes()));
148 assertTrue(codec.containsAlphabetOrPad(new byte[]{codec.pad}));
149 }
150
151
152
153
154
155
156 @Test
157 void testContextToString() {
158 final Context context = new Context();
159 context.buffer = new byte[3];
160 context.currentLinePos = 13;
161 context.eof = true;
162 context.ibitWorkArea = 777;
163 context.lbitWorkArea = 999;
164 context.modulus = 5;
165 context.pos = 42;
166 context.readPos = 981;
167 final String text = context.toString();
168 assertTrue(text.contains("[0, 0, 0]"));
169 assertTrue(text.contains("13"));
170 assertTrue(text.contains("true"));
171 assertTrue(text.contains("777"));
172 assertTrue(text.contains("999"));
173 assertTrue(text.contains("5"));
174 assertTrue(text.contains("42"));
175 assertTrue(text.contains("981"));
176 }
177
178
179
180
181
182
183 @Test
184 void testEnsureBufferSize() {
185 final BaseNCodec ncodec = new NoOpBaseNCodec();
186 final Context context = new Context();
187 assertNull(context.buffer, "Initial buffer should be null");
188
189
190 context.pos = 76979;
191 context.readPos = 273;
192 ncodec.ensureBufferSize(0, context);
193 assertNotNull(context.buffer, "buffer should be initialized");
194 assertEquals(ncodec.getDefaultBufferSize(), context.buffer.length, "buffer should be initialized to default size");
195 assertEquals(0, context.pos, "context position");
196 assertEquals(0, context.readPos, "context read position");
197
198
199 ncodec.ensureBufferSize(1, context);
200 assertEquals(ncodec.getDefaultBufferSize(), context.buffer.length, "buffer should not expand unless required");
201
202
203 int length = context.buffer.length;
204 context.pos = length;
205 int extra = 1;
206 ncodec.ensureBufferSize(extra, context);
207 assertTrue(context.buffer.length >= length + extra, "buffer should expand");
208
209
210
211 length = context.buffer.length;
212 context.pos = length;
213 extra = length * 10;
214 ncodec.ensureBufferSize(extra, context);
215 assertTrue(context.buffer.length >= length + extra, "buffer should expand beyond double capacity");
216 }
217
218
219
220
221
222
223
224
225
226 @Test
227 void testEnsureBufferSizeExpandsToBeyondMaxBufferSize() {
228 assertEnsureBufferSizeExpandsToMaxBufferSize(true);
229 }
230
231
232
233
234 @Test
235 void testEnsureBufferSizeExpandsToMaxBufferSize() {
236 assertEnsureBufferSizeExpandsToMaxBufferSize(false);
237 }
238
239 @Test
240 void testEnsureBufferSizeThrowsOnOverflow() {
241 final BaseNCodec ncodec = new NoOpBaseNCodec();
242 final Context context = new Context();
243
244 final int length = 10;
245 context.buffer = new byte[length];
246 context.pos = length;
247 final int extra = Integer.MAX_VALUE;
248 assertThrows(OutOfMemoryError.class, () -> ncodec.ensureBufferSize(extra, context));
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
295
296
297 @Test
298 void testIsInAlphabetByte() {
299 assertFalse(codec.isInAlphabet((byte) 0));
300 assertFalse(codec.isInAlphabet((byte) 'a'));
301 assertTrue(codec.isInAlphabet((byte) 'O'));
302 assertTrue(codec.isInAlphabet((byte) 'K'));
303 }
304
305 @Test
306 void testIsInAlphabetByteArrayBoolean() {
307 assertTrue(codec.isInAlphabet(new byte[] {}, false));
308 assertTrue(codec.isInAlphabet(new byte[] { 'O' }, false));
309 assertFalse(codec.isInAlphabet(new byte[] { 'O', ' ' }, false));
310 assertFalse(codec.isInAlphabet(new byte[] { ' ' }, false));
311 assertTrue(codec.isInAlphabet(new byte[] {}, true));
312 assertTrue(codec.isInAlphabet(new byte[] { 'O' }, true));
313 assertTrue(codec.isInAlphabet(new byte[] { 'O', ' ' }, true));
314 assertTrue(codec.isInAlphabet(new byte[] { ' ' }, true));
315 }
316
317 @Test
318 void testIsInAlphabetString() {
319 assertTrue(codec.isInAlphabet("OK"));
320 assertTrue(codec.isInAlphabet("O=K= \t\n\r"));
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343 @Test
344 void testIsWhiteSpace() {
345 assertTrue(Character.isWhitespace((byte) ' '));
346 assertTrue(Character.isWhitespace((byte) '\n'));
347 assertTrue(Character.isWhitespace((byte) '\r'));
348 assertTrue(Character.isWhitespace((byte) '\t'));
349 assertTrue(Character.isWhitespace((byte) '\f'));
350 assertTrue(Character.isWhitespace((byte) '\u000B'));
351 for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
352 final byte byteToCheck = b;
353 assertEquals(Character.isWhitespace(b), Character.isWhitespace(byteToCheck));
354 }
355 }
356
357 @Test
358 void testProvidePaddingByte() {
359
360 codec = new BaseNCodec(0, 0, 0, 0, (byte) 0x25) {
361 @Override
362 void decode(final byte[] array, final int i, final int length, final Context context) {
363
364 }
365
366 @Override
367 void encode(final byte[] array, final int i, final int length, final Context context) {
368
369 }
370
371 @Override
372 protected boolean isInAlphabet(final byte b) {
373 return b == 'O' || b == 'K';
374 }
375 };
376
377
378 final byte actualPaddingByte = codec.pad;
379
380
381 assertEquals(0x25, actualPaddingByte);
382 }
383 }