blob: af608c3ae259745da0fe8150126f9f6c0977245b [file] [log] [blame]
Doug Zongkerd2affae2010-02-12 15:50:01 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Doug Zongkerab69e292010-03-29 13:23:15 -070017package android.util;
Doug Zongkerd2affae2010-02-12 15:50:01 -080018
Aurimas Liutikasbdbde552017-12-19 13:21:10 -080019import android.support.test.filters.LargeTest;
Doug Zongkerd2affae2010-02-12 15:50:01 -080020
Tobias Thierer97c4d132018-07-23 12:53:00 +010021import junit.framework.TestCase;
22
Doug Zongkerd2affae2010-02-12 15:50:01 -080023import java.io.ByteArrayInputStream;
24import java.io.ByteArrayOutputStream;
Aurimas Liutikasbdbde552017-12-19 13:21:10 -080025import java.io.IOException;
26import java.io.InputStream;
Tobias Thierer97c4d132018-07-23 12:53:00 +010027import java.io.OutputStream;
Aurimas Liutikasbdbde552017-12-19 13:21:10 -080028import java.util.Arrays;
Tobias Thierer97c4d132018-07-23 12:53:00 +010029import java.util.Collections;
30import java.util.List;
Doug Zongkerd2affae2010-02-12 15:50:01 -080031import java.util.Random;
Tobias Thierer97c4d132018-07-23 12:53:00 +010032import java.util.stream.Collectors;
Doug Zongkerd2affae2010-02-12 15:50:01 -080033
Aurimas Liutikasbdbde552017-12-19 13:21:10 -080034@LargeTest
Doug Zongkerd2affae2010-02-12 15:50:01 -080035public class Base64Test extends TestCase {
36 private static final String TAG = "Base64Test";
37
38 /** Decodes a string, returning a string. */
39 private String decodeString(String in) throws Exception {
40 byte[] out = Base64.decode(in, 0);
41 return new String(out);
42 }
43
44 /**
45 * Encodes the string 'in' using 'flags'. Asserts that decoding
46 * gives the same string. Returns the encoded string.
47 */
48 private String encodeToString(String in, int flags) throws Exception {
49 String b64 = Base64.encodeToString(in.getBytes(), flags);
50 String dec = decodeString(b64);
51 assertEquals(in, dec);
52 return b64;
53 }
54
55 /** Assert that decoding 'in' throws IllegalArgumentException. */
56 private void assertBad(String in) throws Exception {
57 try {
58 byte[] out = Base64.decode(in, 0);
59 fail("should have failed to decode");
60 } catch (IllegalArgumentException e) {
61 }
62 }
63
64 /** Assert that actual equals the first len bytes of expected. */
65 private void assertEquals(byte[] expected, int len, byte[] actual) {
66 assertEquals(len, actual.length);
67 for (int i = 0; i < len; ++i) {
68 assertEquals(expected[i], actual[i]);
69 }
70 }
71
72 /** Assert that actual equals the first len bytes of expected. */
73 private void assertEquals(byte[] expected, int len, byte[] actual, int alen) {
74 assertEquals(len, alen);
75 for (int i = 0; i < len; ++i) {
76 assertEquals(expected[i], actual[i]);
77 }
78 }
79
80 /** Assert that actual equals the first len bytes of expected. */
81 private void assertEquals(byte[] expected, byte[] actual) {
82 assertEquals(expected.length, actual.length);
83 for (int i = 0; i < expected.length; ++i) {
84 assertEquals(expected[i], actual[i]);
85 }
86 }
87
88 public void testDecodeExtraChars() throws Exception {
89 // padding 0
90 assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
91 assertBad("aGVsbG8sIHdvcmxk=");
92 assertBad("aGVsbG8sIHdvcmxk==");
93 assertBad("aGVsbG8sIHdvcmxk =");
94 assertBad("aGVsbG8sIHdvcmxk = = ");
95 assertEquals("hello, world", decodeString(" aGVs bG8s IHdv cmxk "));
96 assertEquals("hello, world", decodeString(" aGV sbG8 sIHd vcmx k "));
97 assertEquals("hello, world", decodeString(" aG VsbG 8sIH dvcm xk "));
98 assertEquals("hello, world", decodeString(" a GVsb G8sI Hdvc mxk "));
99 assertEquals("hello, world", decodeString(" a G V s b G 8 s I H d v c m x k "));
100 assertEquals("hello, world", decodeString("_a*G_V*s_b*G_8*s_I*H_d*v_c*m_x*k_"));
101 assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
102
103 // padding 1
104 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE="));
105 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE"));
106 assertBad("aGVsbG8sIHdvcmxkPyE==");
107 assertBad("aGVsbG8sIHdvcmxkPyE ==");
108 assertBad("aGVsbG8sIHdvcmxkPyE = = ");
109 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E="));
110 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E"));
111 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E ="));
112 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E "));
113 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E = "));
114 assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E "));
115
116 // padding 2
117 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg=="));
118 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg"));
119 assertBad("aGVsbG8sIHdvcmxkLg=");
120 assertBad("aGVsbG8sIHdvcmxkLg =");
121 assertBad("aGVsbG8sIHdvcmxkLg = ");
122 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g=="));
123 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g"));
124 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g =="));
125 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g "));
126 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g = = "));
127 assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g "));
128 }
129
130 private static final byte[] BYTES = { (byte) 0xff, (byte) 0xee, (byte) 0xdd,
131 (byte) 0xcc, (byte) 0xbb, (byte) 0xaa,
132 (byte) 0x99, (byte) 0x88, (byte) 0x77 };
133
134 public void testBinaryDecode() throws Exception {
135 assertEquals(BYTES, 0, Base64.decode("", 0));
136 assertEquals(BYTES, 1, Base64.decode("/w==", 0));
137 assertEquals(BYTES, 2, Base64.decode("/+4=", 0));
138 assertEquals(BYTES, 3, Base64.decode("/+7d", 0));
139 assertEquals(BYTES, 4, Base64.decode("/+7dzA==", 0));
140 assertEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0));
141 assertEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0));
142 assertEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0));
143 assertEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0));
144 }
145
146 public void testWebSafe() throws Exception {
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800147 assertEquals(BYTES, 0, Base64.decode("", Base64.URL_SAFE));
148 assertEquals(BYTES, 1, Base64.decode("_w==", Base64.URL_SAFE));
149 assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.URL_SAFE));
150 assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.URL_SAFE));
151 assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.URL_SAFE));
152 assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.URL_SAFE));
153 assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.URL_SAFE));
154 assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.URL_SAFE));
155 assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.URL_SAFE));
Doug Zongkerd2affae2010-02-12 15:50:01 -0800156
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800157 assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.URL_SAFE));
158 assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.URL_SAFE));
159 assertEquals("_-4=\n", Base64.encodeToString(BYTES, 0, 2, Base64.URL_SAFE));
160 assertEquals("_-7d\n", Base64.encodeToString(BYTES, 0, 3, Base64.URL_SAFE));
161 assertEquals("_-7dzA==\n", Base64.encodeToString(BYTES, 0, 4, Base64.URL_SAFE));
162 assertEquals("_-7dzLs=\n", Base64.encodeToString(BYTES, 0, 5, Base64.URL_SAFE));
163 assertEquals("_-7dzLuq\n", Base64.encodeToString(BYTES, 0, 6, Base64.URL_SAFE));
164 assertEquals("_-7dzLuqmQ==\n", Base64.encodeToString(BYTES, 0, 7, Base64.URL_SAFE));
165 assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.URL_SAFE));
Doug Zongkerd2affae2010-02-12 15:50:01 -0800166 }
167
168 public void testFlags() throws Exception {
169 assertEquals("YQ==\n", encodeToString("a", 0));
170 assertEquals("YQ==", encodeToString("a", Base64.NO_WRAP));
171 assertEquals("YQ\n", encodeToString("a", Base64.NO_PADDING));
172 assertEquals("YQ", encodeToString("a", Base64.NO_PADDING | Base64.NO_WRAP));
173 assertEquals("YQ==\r\n", encodeToString("a", Base64.CRLF));
174 assertEquals("YQ\r\n", encodeToString("a", Base64.CRLF | Base64.NO_PADDING));
175
176 assertEquals("YWI=\n", encodeToString("ab", 0));
177 assertEquals("YWI=", encodeToString("ab", Base64.NO_WRAP));
178 assertEquals("YWI\n", encodeToString("ab", Base64.NO_PADDING));
179 assertEquals("YWI", encodeToString("ab", Base64.NO_PADDING | Base64.NO_WRAP));
180 assertEquals("YWI=\r\n", encodeToString("ab", Base64.CRLF));
181 assertEquals("YWI\r\n", encodeToString("ab", Base64.CRLF | Base64.NO_PADDING));
182
183 assertEquals("YWJj\n", encodeToString("abc", 0));
184 assertEquals("YWJj", encodeToString("abc", Base64.NO_WRAP));
185 assertEquals("YWJj\n", encodeToString("abc", Base64.NO_PADDING));
186 assertEquals("YWJj", encodeToString("abc", Base64.NO_PADDING | Base64.NO_WRAP));
187 assertEquals("YWJj\r\n", encodeToString("abc", Base64.CRLF));
188 assertEquals("YWJj\r\n", encodeToString("abc", Base64.CRLF | Base64.NO_PADDING));
189
190 assertEquals("YWJjZA==\n", encodeToString("abcd", 0));
191 assertEquals("YWJjZA==", encodeToString("abcd", Base64.NO_WRAP));
192 assertEquals("YWJjZA\n", encodeToString("abcd", Base64.NO_PADDING));
193 assertEquals("YWJjZA", encodeToString("abcd", Base64.NO_PADDING | Base64.NO_WRAP));
194 assertEquals("YWJjZA==\r\n", encodeToString("abcd", Base64.CRLF));
195 assertEquals("YWJjZA\r\n", encodeToString("abcd", Base64.CRLF | Base64.NO_PADDING));
196 }
197
198 public void testLineLength() throws Exception {
199 String in_56 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd";
200 String in_57 = in_56 + "e";
201 String in_58 = in_56 + "ef";
202 String in_59 = in_56 + "efg";
203 String in_60 = in_56 + "efgh";
204 String in_61 = in_56 + "efghi";
205
206 String prefix = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5emFi";
207 String out_56 = prefix + "Y2Q=\n";
208 String out_57 = prefix + "Y2Rl\n";
209 String out_58 = prefix + "Y2Rl\nZg==\n";
210 String out_59 = prefix + "Y2Rl\nZmc=\n";
211 String out_60 = prefix + "Y2Rl\nZmdo\n";
212 String out_61 = prefix + "Y2Rl\nZmdoaQ==\n";
213
214 // no newline for an empty input array.
215 assertEquals("", encodeToString("", 0));
216
217 assertEquals(out_56, encodeToString(in_56, 0));
218 assertEquals(out_57, encodeToString(in_57, 0));
219 assertEquals(out_58, encodeToString(in_58, 0));
220 assertEquals(out_59, encodeToString(in_59, 0));
221 assertEquals(out_60, encodeToString(in_60, 0));
222 assertEquals(out_61, encodeToString(in_61, 0));
223
224 assertEquals(out_56.replaceAll("=", ""), encodeToString(in_56, Base64.NO_PADDING));
225 assertEquals(out_57.replaceAll("=", ""), encodeToString(in_57, Base64.NO_PADDING));
226 assertEquals(out_58.replaceAll("=", ""), encodeToString(in_58, Base64.NO_PADDING));
227 assertEquals(out_59.replaceAll("=", ""), encodeToString(in_59, Base64.NO_PADDING));
228 assertEquals(out_60.replaceAll("=", ""), encodeToString(in_60, Base64.NO_PADDING));
229 assertEquals(out_61.replaceAll("=", ""), encodeToString(in_61, Base64.NO_PADDING));
230
231 assertEquals(out_56.replaceAll("\n", ""), encodeToString(in_56, Base64.NO_WRAP));
232 assertEquals(out_57.replaceAll("\n", ""), encodeToString(in_57, Base64.NO_WRAP));
233 assertEquals(out_58.replaceAll("\n", ""), encodeToString(in_58, Base64.NO_WRAP));
234 assertEquals(out_59.replaceAll("\n", ""), encodeToString(in_59, Base64.NO_WRAP));
235 assertEquals(out_60.replaceAll("\n", ""), encodeToString(in_60, Base64.NO_WRAP));
236 assertEquals(out_61.replaceAll("\n", ""), encodeToString(in_61, Base64.NO_WRAP));
237 }
238
239 /**
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800240 * Tests that Base64.Encoder.encode() does correct handling of the
Doug Zongkerd2affae2010-02-12 15:50:01 -0800241 * tail for each call.
242 *
243 * This test is disabled because while it passes if you can get it
244 * to run, android's test infrastructure currently doesn't allow
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800245 * us to get at package-private members (Base64.Encoder in
Doug Zongkerd2affae2010-02-12 15:50:01 -0800246 * this case).
247 */
248 public void XXXtestEncodeInternal() throws Exception {
249 byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
250 byte[] output = new byte[100];
251
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800252 Base64.Encoder encoder = new Base64.Encoder(Base64.NO_PADDING | Base64.NO_WRAP,
253 output);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800254
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800255 encoder.process(input, 0, 3, false);
256 assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
257 assertEquals(0, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800258
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800259 encoder.process(input, 0, 3, false);
260 assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
261 assertEquals(0, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800262
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800263 encoder.process(input, 0, 1, false);
264 assertEquals(0, encoder.op);
265 assertEquals(1, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800266
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800267 encoder.process(input, 0, 1, false);
268 assertEquals(0, encoder.op);
269 assertEquals(2, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800270
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800271 encoder.process(input, 0, 1, false);
272 assertEquals("YWFh".getBytes(), 4, encoder.output, encoder.op);
273 assertEquals(0, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800274
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800275 encoder.process(input, 0, 2, false);
276 assertEquals(0, encoder.op);
277 assertEquals(2, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800278
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800279 encoder.process(input, 0, 2, false);
280 assertEquals("YWJh".getBytes(), 4, encoder.output, encoder.op);
281 assertEquals(1, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800282
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800283 encoder.process(input, 0, 2, false);
284 assertEquals("YmFi".getBytes(), 4, encoder.output, encoder.op);
285 assertEquals(0, encoder.tailLen);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800286
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800287 encoder.process(input, 0, 1, true);
288 assertEquals("YQ".getBytes(), 2, encoder.output, encoder.op);
Doug Zongkerd2affae2010-02-12 15:50:01 -0800289 }
290
291 private static final String lipsum =
292 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
293 "Quisque congue eleifend odio, eu ornare nulla facilisis eget. " +
294 "Integer eget elit diam, sit amet laoreet nibh. Quisque enim " +
295 "urna, pharetra vitae consequat eget, adipiscing eu ante. " +
296 "Aliquam venenatis arcu nec nibh imperdiet tempor. In id dui " +
297 "eget lorem aliquam rutrum vel vitae eros. In placerat ornare " +
298 "pretium. Curabitur non fringilla mi. Fusce ultricies, turpis " +
299 "eu ultrices suscipit, ligula nisi consectetur eros, dapibus " +
300 "aliquet dui sapien a turpis. Donec ultricies varius ligula, " +
301 "ut hendrerit arcu malesuada at. Praesent sed elit pretium " +
302 "eros luctus gravida. In ac dolor lorem. Cras condimentum " +
303 "convallis elementum. Phasellus vel felis in nulla ultrices " +
304 "venenatis. Nam non tortor non orci convallis convallis. " +
305 "Nam tristique lacinia hendrerit. Pellentesque habitant morbi " +
306 "tristique senectus et netus et malesuada fames ac turpis " +
307 "egestas. Vivamus cursus, nibh eu imperdiet porta, magna " +
308 "ipsum mollis mauris, sit amet fringilla mi nisl eu mi. " +
309 "Phasellus posuere, leo at ultricies vehicula, massa risus " +
310 "volutpat sapien, eu tincidunt diam ipsum eget nulla. Cras " +
311 "molestie dapibus commodo. Ut vel tellus at massa gravida " +
312 "semper non sed orci.";
313
314 public void testInputStream() throws Exception {
315 int[] flagses = { Base64.DEFAULT,
316 Base64.NO_PADDING,
317 Base64.NO_WRAP,
318 Base64.NO_PADDING | Base64.NO_WRAP,
319 Base64.CRLF,
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800320 Base64.URL_SAFE };
Doug Zongkerd2affae2010-02-12 15:50:01 -0800321 int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
322 Random rng = new Random(32176L);
323
324 // Test input needs to be at least 2048 bytes to fill up the
325 // read buffer of Base64InputStream.
326 byte[] plain = (lipsum + lipsum + lipsum + lipsum + lipsum).getBytes();
327
328 for (int flags: flagses) {
329 byte[] encoded = Base64.encode(plain, flags);
330
331 ByteArrayInputStream bais;
332 Base64InputStream b64is;
333 byte[] actual = new byte[plain.length * 2];
334 int ap;
335 int b;
336
337 // ----- test decoding ("encoded" -> "plain") -----
338
339 // read as much as it will give us in one chunk
340 bais = new ByteArrayInputStream(encoded);
341 b64is = new Base64InputStream(bais, flags);
342 ap = 0;
343 while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
344 ap += b;
345 }
346 assertEquals(actual, ap, plain);
347
348 // read individual bytes
349 bais = new ByteArrayInputStream(encoded);
350 b64is = new Base64InputStream(bais, flags);
351 ap = 0;
352 while ((b = b64is.read()) != -1) {
353 actual[ap++] = (byte) b;
354 }
355 assertEquals(actual, ap, plain);
356
357 // mix reads of variously-sized arrays with one-byte reads
358 bais = new ByteArrayInputStream(encoded);
359 b64is = new Base64InputStream(bais, flags);
360 ap = 0;
361 readloop: while (true) {
362 int l = writeLengths[rng.nextInt(writeLengths.length)];
363 if (l >= 0) {
364 b = b64is.read(actual, ap, l);
365 if (b == -1) break readloop;
366 ap += b;
367 } else {
368 for (int i = 0; i < -l; ++i) {
369 if ((b = b64is.read()) == -1) break readloop;
370 actual[ap++] = (byte) b;
371 }
372 }
373 }
374 assertEquals(actual, ap, plain);
375
376 // ----- test encoding ("plain" -> "encoded") -----
377
378 // read as much as it will give us in one chunk
379 bais = new ByteArrayInputStream(plain);
380 b64is = new Base64InputStream(bais, flags, true);
381 ap = 0;
382 while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
383 ap += b;
384 }
385 assertEquals(actual, ap, encoded);
386
387 // read individual bytes
388 bais = new ByteArrayInputStream(plain);
389 b64is = new Base64InputStream(bais, flags, true);
390 ap = 0;
391 while ((b = b64is.read()) != -1) {
392 actual[ap++] = (byte) b;
393 }
394 assertEquals(actual, ap, encoded);
395
396 // mix reads of variously-sized arrays with one-byte reads
397 bais = new ByteArrayInputStream(plain);
398 b64is = new Base64InputStream(bais, flags, true);
399 ap = 0;
400 readloop: while (true) {
401 int l = writeLengths[rng.nextInt(writeLengths.length)];
402 if (l >= 0) {
403 b = b64is.read(actual, ap, l);
404 if (b == -1) break readloop;
405 ap += b;
406 } else {
407 for (int i = 0; i < -l; ++i) {
408 if ((b = b64is.read()) == -1) break readloop;
409 actual[ap++] = (byte) b;
410 }
411 }
412 }
413 assertEquals(actual, ap, encoded);
414 }
415 }
416
Jesse Wilson64b25cf2010-09-22 10:28:27 -0700417 /** http://b/3026478 */
418 public void testSingleByteReads() throws IOException {
419 InputStream in = new Base64InputStream(
420 new ByteArrayInputStream("/v8=".getBytes()), Base64.DEFAULT);
421 assertEquals(254, in.read());
422 assertEquals(255, in.read());
423 }
424
Doug Zongkerd2affae2010-02-12 15:50:01 -0800425 /**
426 * Tests that Base64OutputStream produces exactly the same results
427 * as calling Base64.encode/.decode on an in-memory array.
428 */
429 public void testOutputStream() throws Exception {
430 int[] flagses = { Base64.DEFAULT,
431 Base64.NO_PADDING,
432 Base64.NO_WRAP,
433 Base64.NO_PADDING | Base64.NO_WRAP,
434 Base64.CRLF,
Doug Zongker9df2ffd2010-02-14 13:48:49 -0800435 Base64.URL_SAFE };
Doug Zongkerd2affae2010-02-12 15:50:01 -0800436 int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
437 Random rng = new Random(32176L);
438
439 // Test input needs to be at least 1024 bytes to test filling
440 // up the write(int) buffer of Base64OutputStream.
441 byte[] plain = (lipsum + lipsum).getBytes();
442
443 for (int flags: flagses) {
444 byte[] encoded = Base64.encode(plain, flags);
445
446 ByteArrayOutputStream baos;
447 Base64OutputStream b64os;
448 byte[] actual;
449 int p;
450
451 // ----- test encoding ("plain" -> "encoded") -----
452
453 // one large write(byte[]) of the whole input
454 baos = new ByteArrayOutputStream();
455 b64os = new Base64OutputStream(baos, flags);
456 b64os.write(plain);
457 b64os.close();
458 actual = baos.toByteArray();
459 assertEquals(encoded, actual);
460
461 // many calls to write(int)
462 baos = new ByteArrayOutputStream();
463 b64os = new Base64OutputStream(baos, flags);
464 for (int i = 0; i < plain.length; ++i) {
465 b64os.write(plain[i]);
466 }
467 b64os.close();
468 actual = baos.toByteArray();
469 assertEquals(encoded, actual);
470
471 // intermixed sequences of write(int) with
472 // write(byte[],int,int) of various lengths.
473 baos = new ByteArrayOutputStream();
474 b64os = new Base64OutputStream(baos, flags);
475 p = 0;
476 while (p < plain.length) {
477 int l = writeLengths[rng.nextInt(writeLengths.length)];
478 l = Math.min(l, plain.length-p);
479 if (l >= 0) {
480 b64os.write(plain, p, l);
481 p += l;
482 } else {
483 l = Math.min(-l, plain.length-p);
484 for (int i = 0; i < l; ++i) {
485 b64os.write(plain[p+i]);
486 }
487 p += l;
488 }
489 }
490 b64os.close();
491 actual = baos.toByteArray();
492 assertEquals(encoded, actual);
493
494 // ----- test decoding ("encoded" -> "plain") -----
495
496 // one large write(byte[]) of the whole input
497 baos = new ByteArrayOutputStream();
498 b64os = new Base64OutputStream(baos, flags, false);
499 b64os.write(encoded);
500 b64os.close();
501 actual = baos.toByteArray();
502 assertEquals(plain, actual);
503
504 // many calls to write(int)
505 baos = new ByteArrayOutputStream();
506 b64os = new Base64OutputStream(baos, flags, false);
507 for (int i = 0; i < encoded.length; ++i) {
508 b64os.write(encoded[i]);
509 }
510 b64os.close();
511 actual = baos.toByteArray();
512 assertEquals(plain, actual);
513
514 // intermixed sequences of write(int) with
515 // write(byte[],int,int) of various lengths.
516 baos = new ByteArrayOutputStream();
517 b64os = new Base64OutputStream(baos, flags, false);
518 p = 0;
519 while (p < encoded.length) {
520 int l = writeLengths[rng.nextInt(writeLengths.length)];
521 l = Math.min(l, encoded.length-p);
522 if (l >= 0) {
523 b64os.write(encoded, p, l);
524 p += l;
525 } else {
526 l = Math.min(-l, encoded.length-p);
527 for (int i = 0; i < l; ++i) {
528 b64os.write(encoded[p+i]);
529 }
530 p += l;
531 }
532 }
533 b64os.close();
534 actual = baos.toByteArray();
535 assertEquals(plain, actual);
536 }
537 }
Tobias Thierer97c4d132018-07-23 12:53:00 +0100538
539 public void testOutputStream_ioExceptionDuringClose() {
540 OutputStream out = new OutputStream() {
541 @Override public void write(int b) throws IOException { }
542 @Override public void close() throws IOException {
543 throw new IOException("close()");
544 }
545 };
546 OutputStream out2 = new Base64OutputStream(out, Base64.DEFAULT);
547 try {
548 out2.close();
549 fail();
550 } catch (IOException expected) {
551 }
552 }
553
554 public void testOutputStream_ioExceptionDuringCloseAndWrite() {
555 OutputStream out = new OutputStream() {
556 @Override public void write(int b) throws IOException {
557 throw new IOException("write()");
558 }
559 @Override public void write(byte[] b) throws IOException {
560 throw new IOException("write()");
561 }
562 @Override public void write(byte[] b, int off, int len) throws IOException {
563 throw new IOException("write()");
564 }
565 @Override public void close() throws IOException {
566 throw new IOException("close()");
567 }
568 };
569 OutputStream out2 = new Base64OutputStream(out, Base64.DEFAULT);
570 try {
571 out2.close();
572 fail();
573 } catch (IOException expected) {
574 // Base64OutputStream write()s pending (possibly empty) data
575 // before close(), so the IOE from write() should be thrown and
576 // any later exception suppressed.
577 assertEquals("write()", expected.getMessage());
578 Throwable[] suppressed = expected.getSuppressed();
579 List<String> suppressedMessages = Arrays.asList(suppressed).stream()
580 .map((e) -> e.getMessage())
581 .collect(Collectors.toList());
582 assertEquals(Collections.singletonList("close()"), suppressedMessages);
583 }
584 }
585
586 public void testOutputStream_ioExceptionDuringWrite() {
587 OutputStream out = new OutputStream() {
588 @Override public void write(int b) throws IOException {
589 throw new IOException("write()");
590 }
591 @Override public void write(byte[] b) throws IOException {
592 throw new IOException("write()");
593 }
594 @Override public void write(byte[] b, int off, int len) throws IOException {
595 throw new IOException("write()");
596 }
597 };
598 // Base64OutputStream write()s pending (possibly empty) data
599 // before close(), so the IOE from write() should be thrown.
600 OutputStream out2 = new Base64OutputStream(out, Base64.DEFAULT);
601 try {
602 out2.close();
603 fail();
604 } catch (IOException expected) {
605 }
606 }
607
Doug Zongkerd2affae2010-02-12 15:50:01 -0800608}