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.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.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.io.ByteArrayOutputStream;
27 import java.io.OutputStream;
28
29 import org.apache.commons.codec.CodecPolicy;
30 import org.junit.jupiter.api.Test;
31
32
33
34 public class Base64OutputStreamTest {
35
36 private final static byte[] CR_LF = {(byte) '\r', (byte) '\n'};
37
38 private final static byte[] LF = {(byte) '\n'};
39
40 private static final String STRING_FIXTURE = "Hello World";
41
42 private void testBase64EmptyOutputStream(final int chunkSize) throws Exception {
43 final byte[] emptyEncoded = {};
44 final byte[] emptyDecoded = {};
45 testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
46 testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
47 }
48
49
50
51
52
53
54
55 @Test
56 public void testBase64EmptyOutputStreamMimeChunkSize() throws Exception {
57 testBase64EmptyOutputStream(BaseNCodec.MIME_CHUNK_SIZE);
58 }
59
60
61
62
63
64
65
66 @Test
67 public void testBase64EmptyOutputStreamPemChunkSize() throws Exception {
68 testBase64EmptyOutputStream(BaseNCodec.PEM_CHUNK_SIZE);
69 }
70
71
72
73
74
75
76
77 @Test
78 public void testBase64OutputStreamByChunk() throws Exception {
79
80 byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n");
81 byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
82 testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CR_LF);
83
84
85 encoded = StringUtils.getBytesUtf8("AA==\r\n");
86 decoded = new byte[]{(byte) 0};
87 testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CR_LF);
88
89
90 encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
91 decoded = BaseNTestData.DECODED;
92 testByChunk(encoded, decoded, BaseNCodec.PEM_CHUNK_SIZE, LF);
93
94
95 final String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replace("\n", "");
96 encoded = StringUtils.getBytesUtf8(singleLine);
97 decoded = BaseNTestData.DECODED;
98 testByChunk(encoded, decoded, 0, LF);
99
100
101 final BaseNCodec codec = new Base64(0, null, false);
102 for (int i = 0; i <= 150; i++) {
103 final byte[][] randomData = BaseNTestData.randomData(codec, i);
104 encoded = randomData[1];
105 decoded = randomData[0];
106 testByChunk(encoded, decoded, 0, LF);
107 }
108 }
109
110
111
112
113
114
115
116 @Test
117 public void testBase64OutputStreamByteByByte() throws Exception {
118
119 byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n");
120 byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
121 testByteByByte(encoded, decoded, 76, CR_LF);
122
123
124 encoded = StringUtils.getBytesUtf8("AA==\r\n");
125 decoded = new byte[]{(byte) 0};
126 testByteByByte(encoded, decoded, 76, CR_LF);
127
128
129 encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
130 decoded = BaseNTestData.DECODED;
131 testByteByByte(encoded, decoded, 64, LF);
132
133
134 final String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replace("\n", "");
135 encoded = StringUtils.getBytesUtf8(singleLine);
136 decoded = BaseNTestData.DECODED;
137 testByteByByte(encoded, decoded, 0, LF);
138
139
140 final BaseNCodec codec = new Base64(0, null, false);
141 for (int i = 0; i <= 150; i++) {
142 final byte[][] randomData = BaseNTestData.randomData(codec, i);
143 encoded = randomData[1];
144 decoded = randomData[0];
145 testByteByByte(encoded, decoded, 0, LF);
146 }
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 private void testByChunk(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception {
168
169
170 ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
171 try (OutputStream out = new Base64OutputStream(byteOut, true, chunkSize, separator)) {
172 out.write(decoded);
173 }
174 byte[] output = byteOut.toByteArray();
175 assertArrayEquals(encoded, output, "Streaming chunked base64 encode");
176
177
178 byteOut = new ByteArrayOutputStream();
179 try (OutputStream out = new Base64OutputStream(byteOut, false)) {
180 out.write(encoded);
181 }
182 output = byteOut.toByteArray();
183 assertArrayEquals(decoded, output, "Streaming chunked base64 decode");
184
185
186 byteOut = new ByteArrayOutputStream();
187 OutputStream out = byteOut;
188 for (int i = 0; i < 10; i++) {
189 out = new Base64OutputStream(out, false);
190 out = new Base64OutputStream(out, true, chunkSize, separator);
191 }
192 out.write(decoded);
193 out.close();
194 output = byteOut.toByteArray();
195
196 assertArrayEquals(decoded, output, "Streaming chunked base64 wrap-wrap-wrap!");
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 private void testByteByByte(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception {
218
219
220 ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
221 try (OutputStream out = new Base64OutputStream(byteOut, true, chunkSize, separator)) {
222 for (final byte element : decoded) {
223 out.write(element);
224 }
225 }
226 byte[] output = byteOut.toByteArray();
227 assertArrayEquals(encoded, output, "Streaming byte-by-byte base64 encode");
228
229
230 byteOut = new ByteArrayOutputStream();
231 try (OutputStream out = new Base64OutputStream(byteOut, false)) {
232 for (final byte element : encoded) {
233 out.write(element);
234 }
235 }
236 output = byteOut.toByteArray();
237 assertArrayEquals(decoded, output, "Streaming byte-by-byte base64 decode");
238
239
240 byteOut = new ByteArrayOutputStream();
241 try (OutputStream out = new Base64OutputStream(byteOut, false)) {
242 for (final byte element : encoded) {
243 out.write(element);
244 out.flush();
245 }
246 }
247 output = byteOut.toByteArray();
248 assertArrayEquals(decoded, output, "Streaming byte-by-byte flush() base64 decode");
249
250
251 byteOut = new ByteArrayOutputStream();
252 OutputStream out = byteOut;
253 for (int i = 0; i < 10; i++) {
254 out = new Base64OutputStream(out, false);
255 out = new Base64OutputStream(out, true, chunkSize, separator);
256 }
257 for (final byte element : decoded) {
258 out.write(element);
259 }
260 out.close();
261 output = byteOut.toByteArray();
262
263 assertArrayEquals(decoded, output, "Streaming byte-by-byte base64 wrap-wrap-wrap!");
264 }
265
266
267
268
269
270
271
272 @Test
273 public void testCodec98NPE() throws Exception {
274 final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
275 final byte[] codec98_1024 = new byte[1024];
276 System.arraycopy(codec98, 0, codec98_1024, 0, codec98.length);
277 final ByteArrayOutputStream data = new ByteArrayOutputStream(1024);
278 try (final Base64OutputStream stream = new Base64OutputStream(data, false)) {
279 stream.write(codec98_1024, 0, 1024);
280 }
281
282 final byte[] decodedBytes = data.toByteArray();
283 final String decoded = StringUtils.newStringUtf8(decodedBytes);
284 assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64OutputStream");
285 }
286
287
288
289
290
291
292
293 @Test
294 public void testStrictDecoding() throws Exception {
295 for (final String impossibleStr : Base64Test.BASE64_IMPOSSIBLE_CASES) {
296 final byte[] impossibleEncoded = StringUtils.getBytesUtf8(impossibleStr);
297 ByteArrayOutputStream bout = new ByteArrayOutputStream();
298 try (Base64OutputStream out = new Base64OutputStream(bout, false)) {
299
300 assertFalse(out.isStrictDecoding());
301 out.write(impossibleEncoded);
302 }
303 assertTrue(bout.size() > 0);
304
305
306 bout = new ByteArrayOutputStream();
307 final Base64OutputStream out = new Base64OutputStream(bout, false, 0, null, CodecPolicy.STRICT);
308
309
310 assertThrows(IllegalArgumentException.class, () -> {
311 out.write(impossibleEncoded);
312 out.close();
313 });
314 }
315 }
316
317
318
319
320
321
322
323 @Test
324 public void testWriteOutOfBounds() throws Exception {
325 final byte[] buf = new byte[1024];
326 final ByteArrayOutputStream bout = new ByteArrayOutputStream();
327 try (final Base64OutputStream out = new Base64OutputStream(bout)) {
328 assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, -1, 1), "Base64OutputStream.write(buf, -1, 1)");
329 assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, 1, -1), "Base64OutputStream.write(buf, 1, -1)");
330 assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, buf.length + 1, 0), "Base64OutputStream.write(buf, buf.length + 1, 0)");
331 assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, buf.length - 1, 2), "Base64OutputStream.write(buf, buf.length - 1, 2)");
332 }
333 }
334
335
336
337
338
339
340
341 @Test
342 public void testWriteToNullCoverage() throws Exception {
343 final ByteArrayOutputStream bout = new ByteArrayOutputStream();
344 try (final Base64OutputStream out = new Base64OutputStream(bout)) {
345 assertThrows(NullPointerException.class, () -> out.write(null, 0, 0));
346 }
347 }
348 }