/
BASE64Test.java
326 lines (289 loc) · 9.8 KB
/
BASE64Test.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
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
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
320
321
322
323
324
325
326
/*
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.mail.util;
import java.io.*;
import java.util.*;
import javax.mail.*;
import org.junit.Test;
import org.junit.Assert;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
/**
* Test base64 encoding/decoding.
*
* @author Bill Shannon
*/
public class BASE64Test {
@Test
public void test() throws IOException {
// test a range of buffer sizes
for (int bufsize = 1; bufsize < 100; bufsize++) {
//System.out.println("Buffer size: " + bufsize);
byte[] buf = new byte[bufsize];
// test a set of patterns
// first, all zeroes
Arrays.fill(buf, (byte)0);
test("Zeroes", buf);
// now, all ones
Arrays.fill(buf, (byte)0xff);
test("Ones", buf);
// now, small integers
for (int i = 0; i < bufsize; i++)
buf[i] = (byte)i;
test("Ints", buf);
// finally, random numbers
Random rnd = new Random();
rnd.nextBytes(buf);
test("Random", buf);
}
}
/**
* Encode and decode the buffer and check that we get back the
* same data. Encoding is done both with the static encode
* method and using the encoding stream. Likewise, decoding
* is done both with the static decode method and using the
* decoding stream. Check all combinations.
*/
private static void test(String name, byte[] buf) throws IOException {
// first encode and decode with method
byte[] encoded = BASE64EncoderStream.encode(buf);
byte[] nbuf = BASE64DecoderStream.decode(encoded);
compare(name, "method", buf, nbuf);
// encode with stream, compare with method encoded version
ByteArrayOutputStream bos = new ByteArrayOutputStream();
BASE64EncoderStream os =
new BASE64EncoderStream(bos, Integer.MAX_VALUE);
os.write(buf);
os.flush();
os.close();
byte[] sbuf = bos.toByteArray();
compare(name, "encoded", encoded, sbuf);
// encode with stream, decode with method
nbuf = BASE64DecoderStream.decode(sbuf);
compare(name, "stream->method", buf, nbuf);
// encode with stream, decode with stream
ByteArrayInputStream bin = new ByteArrayInputStream(sbuf);
BASE64DecoderStream in = new BASE64DecoderStream(bin);
readAll(in, nbuf, nbuf.length);
compare(name, "stream", buf, nbuf);
// encode with method, decode with stream
for (int i = 1; i <= nbuf.length; i++) {
bin = new ByteArrayInputStream(encoded);
in = new BASE64DecoderStream(bin);
readAll(in, nbuf, i);
compare(name, "method->stream " + i, buf, nbuf);
}
// encode with stream, decode with stream, many buffers
// first, fill the output with multiple buffers, up to the limit
int limit = 10000; // more than 8K
bos = new ByteArrayOutputStream();
os = new BASE64EncoderStream(bos);
for (int size = 0, blen = buf.length; size < limit; size += blen) {
if (size + blen > limit) {
blen = limit - size;
// write out partial buffer, starting at non-zero offset
os.write(buf, buf.length - blen, blen);
} else
os.write(buf);
}
os.flush();
os.close();
// read the encoded output and check the line length
String type = "big stream"; // for error messages below
sbuf = bos.toByteArray();
bin = new ByteArrayInputStream(sbuf);
byte[] inbuf = new byte[78];
for (int size = 0, blen = 76; size < limit; size += blen) {
if (size + blen > limit) {
blen = limit - size;
int n = bin.read(inbuf, 0, blen);
Assert.assertEquals(name + ": " + type +
" read wrong size at offset " + (size + blen), blen, n);
} else {
int n = bin.read(inbuf, 0, blen + 2);
Assert.assertEquals(name + ": " + type +
" read wrong size at offset " + (size + blen), blen + 2, n);
Assert.assertTrue(name + ": " + type +
" no CRLF: at offset " + (size + blen),
inbuf[blen] == (byte)'\r' && inbuf[blen+1] == (byte)'\n');
}
}
// decode the output and check the data
bin = new ByteArrayInputStream(sbuf);
in = new BASE64DecoderStream(bin);
inbuf = new byte[buf.length];
for (int size = 0, blen = buf.length; size < limit; size += blen) {
if (size + blen > limit)
blen = limit - size;
int n = in.read(nbuf, 0, blen);
Assert.assertEquals(name + ": " + type +
" read decoded wrong size at offset " + (size + blen), blen, n);
if (blen != buf.length) {
// have to compare with end of original buffer
byte[] cbuf = new byte[blen];
System.arraycopy(buf, buf.length - blen, cbuf, 0, blen);
// need a version of the read buffer that's the right size
byte[] cnbuf = new byte[blen];
System.arraycopy(nbuf, 0, cnbuf, 0, blen);
compare(name, type, cbuf, cnbuf);
} else {
compare(name, type, buf, nbuf);
}
}
}
private static byte[] origLine;
private static byte[] encodedLine;
static {
try {
origLine =
"000000000000000000000000000000000000000000000000000000000".
getBytes("us-ascii");
encodedLine =
("MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw" +
"MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw" + "\r\n").
getBytes("us-ascii");
} catch (UnsupportedEncodingException uex) {
// should never happen;
}
}
/**
* Test that CRLF is inserted at the right place.
* Test combinations of array writes of different sizes
* and single byte writes.
*/
@Test
public void testLineLength() throws Exception {
for (int i = 0; i < origLine.length; i++) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStream os = new BASE64EncoderStream(bos);
os.write(origLine, 0, i);
os.write(origLine, i, origLine.length - i);
os.write((byte)'0');
os.flush();
os.close();
byte[] line = new byte[encodedLine.length];
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
Assert.assertArrayEquals("encoded line " + i, encodedLine, line);
}
for (int i = 0; i < origLine.length; i++) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStream os = new BASE64EncoderStream(bos);
os.write(origLine, 0, i);
os.write(origLine, i, origLine.length - i);
os.write(origLine);
os.flush();
os.close();
byte[] line = new byte[encodedLine.length];
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
Assert.assertArrayEquals("all arrays, encoded line " + i,
encodedLine, line);
}
for (int i = 1; i < 5; i++) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStream os = new BASE64EncoderStream(bos);
for (int j = 0; j < i; j++)
os.write((byte)'0');
os.write(origLine, i, origLine.length - i);
os.write((byte)'0');
os.flush();
os.close();
byte[] line = new byte[encodedLine.length];
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
Assert.assertArrayEquals("single byte first encoded line " + i,
encodedLine, line);
}
for (int i = origLine.length - 5; i < origLine.length; i++) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStream os = new BASE64EncoderStream(bos);
os.write(origLine, 0, i);
for (int j = 0; j < origLine.length - i; j++)
os.write((byte)'0');
os.write((byte)'0');
os.flush();
os.close();
byte[] line = new byte[encodedLine.length];
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
Assert.assertArrayEquals("single byte last encoded line " + i,
encodedLine, line);
}
}
@Test
public void testReadZeroBytes() throws Exception {
byte[] decoded = new byte[10000];
for (int i = 0; i < 1000; i++)
decoded[i] = (byte)'A';
byte[] encoded = java.util.Base64.getEncoder().encode(decoded);
// Exceed InputStream.DEFAULT_BUFFER_SIZE
assertTrue(decoded.length > 8192);
BASE64DecoderStream sut =
new BASE64DecoderStream(new ByteArrayInputStream(encoded));
// XXX - should test this using something equivalent to JDK 9's
// InputStream.readAllBytes, but for now...
int n = sut.read(decoded, 0, 0);
assertEquals(n, 0);
// Exercise
//byte[] result = sut.readAllBytes();
// Verify
//assertArrayEquals(decoded, result);
}
/**
* Fill the buffer from the stream.
*/
private static void readAll(InputStream in, byte[] buf, int readsize)
throws IOException {
int need = buf.length;
int off = 0;
int got;
while (need > 0) {
got = in.read(buf, off, need > readsize ? readsize : need);
if (got <= 0)
break;
off += got;
need -= got;
}
if (need != 0)
System.out.println("couldn't read all bytes");
}
/**
* Compare the two buffers.
*/
private static void compare(String name, String type,
byte[] buf, byte[] nbuf) {
/*
if (nbuf.length != buf.length) {
System.out.println(name + ": " + type +
" decoded array size wrong: " +
"got " + nbuf.length + ", expected " + buf.length);
dump(name + " buf", buf);
dump(name + " nbuf", nbuf);
}
*/
Assert.assertEquals(name + ": " + type + " decoded array size wrong",
buf.length, nbuf.length);
for (int i = 0; i < buf.length; i++) {
Assert.assertEquals(name + ": " + type + " data wrong: index " + i,
buf[i], nbuf[i]);
}
}
/**
* Dump the contents of the buffer.
*/
private static void dump(String name, byte[] buf) {
System.out.println(name);
for (int i = 0; i < buf.length; i++)
System.out.println(buf[i]);
}
}