Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 1 | /* |
| 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 Zongker | ab69e29 | 2010-03-29 13:23:15 -0700 | [diff] [blame] | 17 | package android.util; |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 18 | |
Aurimas Liutikas | bdbde55 | 2017-12-19 13:21:10 -0800 | [diff] [blame] | 19 | import android.support.test.filters.LargeTest; |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 20 | |
Tobias Thierer | 97c4d13 | 2018-07-23 12:53:00 +0100 | [diff] [blame] | 21 | import junit.framework.TestCase; |
| 22 | |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 23 | import java.io.ByteArrayInputStream; |
| 24 | import java.io.ByteArrayOutputStream; |
Aurimas Liutikas | bdbde55 | 2017-12-19 13:21:10 -0800 | [diff] [blame] | 25 | import java.io.IOException; |
| 26 | import java.io.InputStream; |
Tobias Thierer | 97c4d13 | 2018-07-23 12:53:00 +0100 | [diff] [blame] | 27 | import java.io.OutputStream; |
Aurimas Liutikas | bdbde55 | 2017-12-19 13:21:10 -0800 | [diff] [blame] | 28 | import java.util.Arrays; |
Tobias Thierer | 97c4d13 | 2018-07-23 12:53:00 +0100 | [diff] [blame] | 29 | import java.util.Collections; |
| 30 | import java.util.List; |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 31 | import java.util.Random; |
Tobias Thierer | 97c4d13 | 2018-07-23 12:53:00 +0100 | [diff] [blame] | 32 | import java.util.stream.Collectors; |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 33 | |
Aurimas Liutikas | bdbde55 | 2017-12-19 13:21:10 -0800 | [diff] [blame] | 34 | @LargeTest |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 35 | public 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 Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 147 | 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 Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 156 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 157 | 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 Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 166 | } |
| 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 Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 240 | * Tests that Base64.Encoder.encode() does correct handling of the |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 241 | * 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 Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 245 | * us to get at package-private members (Base64.Encoder in |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 246 | * 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 Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 252 | Base64.Encoder encoder = new Base64.Encoder(Base64.NO_PADDING | Base64.NO_WRAP, |
| 253 | output); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 254 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 255 | encoder.process(input, 0, 3, false); |
| 256 | assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op); |
| 257 | assertEquals(0, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 258 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 259 | encoder.process(input, 0, 3, false); |
| 260 | assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op); |
| 261 | assertEquals(0, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 262 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 263 | encoder.process(input, 0, 1, false); |
| 264 | assertEquals(0, encoder.op); |
| 265 | assertEquals(1, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 266 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 267 | encoder.process(input, 0, 1, false); |
| 268 | assertEquals(0, encoder.op); |
| 269 | assertEquals(2, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 270 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 271 | encoder.process(input, 0, 1, false); |
| 272 | assertEquals("YWFh".getBytes(), 4, encoder.output, encoder.op); |
| 273 | assertEquals(0, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 274 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 275 | encoder.process(input, 0, 2, false); |
| 276 | assertEquals(0, encoder.op); |
| 277 | assertEquals(2, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 278 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 279 | encoder.process(input, 0, 2, false); |
| 280 | assertEquals("YWJh".getBytes(), 4, encoder.output, encoder.op); |
| 281 | assertEquals(1, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 282 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 283 | encoder.process(input, 0, 2, false); |
| 284 | assertEquals("YmFi".getBytes(), 4, encoder.output, encoder.op); |
| 285 | assertEquals(0, encoder.tailLen); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 286 | |
Doug Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 287 | encoder.process(input, 0, 1, true); |
| 288 | assertEquals("YQ".getBytes(), 2, encoder.output, encoder.op); |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 289 | } |
| 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 Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 320 | Base64.URL_SAFE }; |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 321 | 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 Wilson | 64b25cf | 2010-09-22 10:28:27 -0700 | [diff] [blame] | 417 | /** 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 Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 425 | /** |
| 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 Zongker | 9df2ffd | 2010-02-14 13:48:49 -0800 | [diff] [blame] | 435 | Base64.URL_SAFE }; |
Doug Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 436 | 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 Thierer | 97c4d13 | 2018-07-23 12:53:00 +0100 | [diff] [blame] | 538 | |
| 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 Zongker | d2affae | 2010-02-12 15:50:01 -0800 | [diff] [blame] | 608 | } |