1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.io;
16
17 import static com.google.common.io.BaseEncoding.base16;
18 import static com.google.common.io.BaseEncoding.base32;
19 import static com.google.common.io.BaseEncoding.base32Hex;
20 import static com.google.common.io.BaseEncoding.base64;
21
22 import com.google.common.annotations.GwtCompatible;
23 import com.google.common.annotations.GwtIncompatible;
24 import com.google.common.base.Ascii;
25 import com.google.common.base.Joiner;
26 import com.google.common.base.Splitter;
27 import com.google.common.collect.ImmutableList;
28 import com.google.common.io.BaseEncoding.DecodingException;
29
30 import junit.framework.TestCase;
31
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.OutputStream;
35 import java.io.StringReader;
36 import java.io.StringWriter;
37 import java.io.UnsupportedEncodingException;
38
39
40
41
42
43
44 @GwtCompatible(emulated = true)
45 public class BaseEncodingTest extends TestCase {
46 public static void assertEquals(byte[] expected, byte[] actual) {
47 assertEquals(expected.length, actual.length);
48 for (int i = 0; i < expected.length; i++) {
49 assertEquals(expected[i], actual[i]);
50 }
51 }
52
53 public void testSeparatorsExplicitly() {
54 testEncodes(base64().withSeparator("\n", 3), "foobar", "Zm9\nvYm\nFy");
55 testEncodes(base64().withSeparator("$", 4), "foobar", "Zm9v$YmFy");
56 testEncodes(base32().withSeparator("*", 4), "foobar", "MZXW*6YTB*OI==*====");
57 }
58
59 @SuppressWarnings("ReturnValueIgnored")
60 public void testSeparatorSameAsPadChar() {
61 try {
62 base64().withSeparator("=", 3);
63 fail("Expected IllegalArgumentException");
64 } catch (IllegalArgumentException expected) {}
65
66 try {
67 base64().withPadChar('#').withSeparator("!#!", 3);
68 fail("Expected IllegalArgumentException");
69 } catch (IllegalArgumentException expected) {}
70 }
71
72 @SuppressWarnings("ReturnValueIgnored")
73 public void testAtMostOneSeparator() {
74 BaseEncoding separated = base64().withSeparator("\n", 3);
75 try {
76 separated.withSeparator("$", 4);
77 fail("Expected UnsupportedOperationException");
78 } catch (UnsupportedOperationException expected) {}
79 }
80
81 public void testBase64() {
82
83 testEncodingWithSeparators(base64(), "", "");
84 testEncodingWithSeparators(base64(), "f", "Zg==");
85 testEncodingWithSeparators(base64(), "fo", "Zm8=");
86 testEncodingWithSeparators(base64(), "foo", "Zm9v");
87 testEncodingWithSeparators(base64(), "foob", "Zm9vYg==");
88 testEncodingWithSeparators(base64(), "fooba", "Zm9vYmE=");
89 testEncodingWithSeparators(base64(), "foobar", "Zm9vYmFy");
90 }
91
92 @GwtIncompatible("Reader/Writer")
93 public void testBase64Streaming() throws IOException {
94
95 testStreamingEncodingWithSeparators(base64(), "", "");
96 testStreamingEncodingWithSeparators(base64(), "f", "Zg==");
97 testStreamingEncodingWithSeparators(base64(), "fo", "Zm8=");
98 testStreamingEncodingWithSeparators(base64(), "foo", "Zm9v");
99 testStreamingEncodingWithSeparators(base64(), "foob", "Zm9vYg==");
100 testStreamingEncodingWithSeparators(base64(), "fooba", "Zm9vYmE=");
101 testStreamingEncodingWithSeparators(base64(), "foobar", "Zm9vYmFy");
102 }
103
104 public void testBase64LenientPadding() {
105 testDecodes(base64(), "Zg", "f");
106 testDecodes(base64(), "Zg=", "f");
107 testDecodes(base64(), "Zg==", "f");
108 testDecodes(base64(), "Zg===", "f");
109 testDecodes(base64(), "Zg====", "f");
110 }
111
112 public void testBase64InvalidDecodings() {
113
114 assertFailsToDecode(base64(), "\u007f");
115 assertFailsToDecode(base64(), "Wf2!");
116
117 assertFailsToDecode(base64(), "let's not talk of love or chains!");
118
119 assertFailsToDecode(base64(), "12345");
120 }
121
122 @SuppressWarnings("ReturnValueIgnored")
123 public void testBase64CannotUpperCase() {
124 try {
125 base64().upperCase();
126 fail();
127 } catch (IllegalStateException expected) {
128
129 }
130 }
131
132 @SuppressWarnings("ReturnValueIgnored")
133 public void testBase64CannotLowerCase() {
134 try {
135 base64().lowerCase();
136 fail();
137 } catch (IllegalStateException expected) {
138
139 }
140 }
141
142 public void testBase64AlternatePadding() {
143 BaseEncoding enc = base64().withPadChar('~');
144 testEncodingWithSeparators(enc, "", "");
145 testEncodingWithSeparators(enc, "f", "Zg~~");
146 testEncodingWithSeparators(enc, "fo", "Zm8~");
147 testEncodingWithSeparators(enc, "foo", "Zm9v");
148 testEncodingWithSeparators(enc, "foob", "Zm9vYg~~");
149 testEncodingWithSeparators(enc, "fooba", "Zm9vYmE~");
150 testEncodingWithSeparators(enc, "foobar", "Zm9vYmFy");
151 }
152
153 @GwtIncompatible("Reader/Writer")
154 public void testBase64StreamingAlternatePadding() throws IOException {
155 BaseEncoding enc = base64().withPadChar('~');
156 testStreamingEncodingWithSeparators(enc, "", "");
157 testStreamingEncodingWithSeparators(enc, "f", "Zg~~");
158 testStreamingEncodingWithSeparators(enc, "fo", "Zm8~");
159 testStreamingEncodingWithSeparators(enc, "foo", "Zm9v");
160 testStreamingEncodingWithSeparators(enc, "foob", "Zm9vYg~~");
161 testStreamingEncodingWithSeparators(enc, "fooba", "Zm9vYmE~");
162 testStreamingEncodingWithSeparators(enc, "foobar", "Zm9vYmFy");
163 }
164
165 public void testBase64OmitPadding() {
166 BaseEncoding enc = base64().omitPadding();
167 testEncodingWithSeparators(enc, "", "");
168 testEncodingWithSeparators(enc, "f", "Zg");
169 testEncodingWithSeparators(enc, "fo", "Zm8");
170 testEncodingWithSeparators(enc, "foo", "Zm9v");
171 testEncodingWithSeparators(enc, "foob", "Zm9vYg");
172 testEncodingWithSeparators(enc, "fooba", "Zm9vYmE");
173 testEncodingWithSeparators(enc, "foobar", "Zm9vYmFy");
174 }
175
176 @GwtIncompatible("Reader/Writer")
177 public void testBase64StreamingOmitPadding() throws IOException {
178 BaseEncoding enc = base64().omitPadding();
179 testStreamingEncodingWithSeparators(enc, "", "");
180 testStreamingEncodingWithSeparators(enc, "f", "Zg");
181 testStreamingEncodingWithSeparators(enc, "fo", "Zm8");
182 testStreamingEncodingWithSeparators(enc, "foo", "Zm9v");
183 testStreamingEncodingWithSeparators(enc, "foob", "Zm9vYg");
184 testStreamingEncodingWithSeparators(enc, "fooba", "Zm9vYmE");
185 testStreamingEncodingWithSeparators(enc, "foobar", "Zm9vYmFy");
186 }
187
188 public void testBase32() {
189
190 testEncodingWithCasing(base32(), "", "");
191 testEncodingWithCasing(base32(), "f", "MY======");
192 testEncodingWithCasing(base32(), "fo", "MZXQ====");
193 testEncodingWithCasing(base32(), "foo", "MZXW6===");
194 testEncodingWithCasing(base32(), "foob", "MZXW6YQ=");
195 testEncodingWithCasing(base32(), "fooba", "MZXW6YTB");
196 testEncodingWithCasing(base32(), "foobar", "MZXW6YTBOI======");
197 }
198
199 @GwtIncompatible("Reader/Writer")
200 public void testBase32Streaming() throws IOException {
201
202 testStreamingEncodingWithCasing(base32(), "", "");
203 testStreamingEncodingWithCasing(base32(), "f", "MY======");
204 testStreamingEncodingWithCasing(base32(), "fo", "MZXQ====");
205 testStreamingEncodingWithCasing(base32(), "foo", "MZXW6===");
206 testStreamingEncodingWithCasing(base32(), "foob", "MZXW6YQ=");
207 testStreamingEncodingWithCasing(base32(), "fooba", "MZXW6YTB");
208 testStreamingEncodingWithCasing(base32(), "foobar", "MZXW6YTBOI======");
209 }
210
211 public void testBase32LenientPadding() {
212 testDecodes(base32(), "MZXW6", "foo");
213 testDecodes(base32(), "MZXW6=", "foo");
214 testDecodes(base32(), "MZXW6==", "foo");
215 testDecodes(base32(), "MZXW6===", "foo");
216 testDecodes(base32(), "MZXW6====", "foo");
217 testDecodes(base32(), "MZXW6=====", "foo");
218 }
219
220 public void testBase32AlternatePadding() {
221 BaseEncoding enc = base32().withPadChar('~');
222 testEncodingWithCasing(enc, "", "");
223 testEncodingWithCasing(enc, "f", "MY~~~~~~");
224 testEncodingWithCasing(enc, "fo", "MZXQ~~~~");
225 testEncodingWithCasing(enc, "foo", "MZXW6~~~");
226 testEncodingWithCasing(enc, "foob", "MZXW6YQ~");
227 testEncodingWithCasing(enc, "fooba", "MZXW6YTB");
228 testEncodingWithCasing(enc, "foobar", "MZXW6YTBOI~~~~~~");
229 }
230
231 public void testBase32InvalidDecodings() {
232
233 assertFailsToDecode(base32(), "\u007f");
234 assertFailsToDecode(base32(), "Wf2!");
235
236 assertFailsToDecode(base32(), "let's not talk of love or chains!");
237
238 assertFailsToDecode(base32(), "A");
239 assertFailsToDecode(base32(), "ABC");
240 assertFailsToDecode(base32(), "ABCDEF");
241 }
242
243 public void testBase32UpperCaseIsNoOp() {
244 assertSame(base32(), base32().upperCase());
245 }
246
247 public void testBase32Hex() {
248
249 testEncodingWithCasing(base32Hex(), "", "");
250 testEncodingWithCasing(base32Hex(), "f", "CO======");
251 testEncodingWithCasing(base32Hex(), "fo", "CPNG====");
252 testEncodingWithCasing(base32Hex(), "foo", "CPNMU===");
253 testEncodingWithCasing(base32Hex(), "foob", "CPNMUOG=");
254 testEncodingWithCasing(base32Hex(), "fooba", "CPNMUOJ1");
255 testEncodingWithCasing(base32Hex(), "foobar", "CPNMUOJ1E8======");
256 }
257
258 @GwtIncompatible("Reader/Writer")
259 public void testBase32HexStreaming() throws IOException {
260
261 testStreamingEncodingWithCasing(base32Hex(), "", "");
262 testStreamingEncodingWithCasing(base32Hex(), "f", "CO======");
263 testStreamingEncodingWithCasing(base32Hex(), "fo", "CPNG====");
264 testStreamingEncodingWithCasing(base32Hex(), "foo", "CPNMU===");
265 testStreamingEncodingWithCasing(base32Hex(), "foob", "CPNMUOG=");
266 testStreamingEncodingWithCasing(base32Hex(), "fooba", "CPNMUOJ1");
267 testStreamingEncodingWithCasing(base32Hex(), "foobar", "CPNMUOJ1E8======");
268 }
269
270 public void testBase32HexLenientPadding() {
271 testDecodes(base32Hex(), "CPNMU", "foo");
272 testDecodes(base32Hex(), "CPNMU=", "foo");
273 testDecodes(base32Hex(), "CPNMU==", "foo");
274 testDecodes(base32Hex(), "CPNMU===", "foo");
275 testDecodes(base32Hex(), "CPNMU====", "foo");
276 testDecodes(base32Hex(), "CPNMU=====", "foo");
277 }
278
279 public void testBase32HexInvalidDecodings() {
280
281 assertFailsToDecode(base32Hex(), "\u007f");
282 assertFailsToDecode(base32Hex(), "Wf2!");
283
284 assertFailsToDecode(base32Hex(), "let's not talk of love or chains!");
285
286 assertFailsToDecode(base32Hex(), "A");
287 assertFailsToDecode(base32Hex(), "ABC");
288 assertFailsToDecode(base32Hex(), "ABCDEF");
289 }
290
291 public void testBase32HexUpperCaseIsNoOp() {
292 assertSame(base32Hex(), base32Hex().upperCase());
293 }
294
295 public void testBase16() {
296 testEncodingWithCasing(base16(), "", "");
297 testEncodingWithCasing(base16(), "f", "66");
298 testEncodingWithCasing(base16(), "fo", "666F");
299 testEncodingWithCasing(base16(), "foo", "666F6F");
300 testEncodingWithCasing(base16(), "foob", "666F6F62");
301 testEncodingWithCasing(base16(), "fooba", "666F6F6261");
302 testEncodingWithCasing(base16(), "foobar", "666F6F626172");
303 }
304
305 public void testBase16UpperCaseIsNoOp() {
306 assertSame(base16(), base16().upperCase());
307 }
308
309 private static void testEncodingWithCasing(
310 BaseEncoding encoding, String decoded, String encoded) {
311 testEncodingWithSeparators(encoding, decoded, encoded);
312 testEncodingWithSeparators(encoding.upperCase(), decoded, Ascii.toUpperCase(encoded));
313 testEncodingWithSeparators(encoding.lowerCase(), decoded, Ascii.toLowerCase(encoded));
314 }
315
316 private static void testEncodingWithSeparators(
317 BaseEncoding encoding, String decoded, String encoded) {
318 testEncoding(encoding, decoded, encoded);
319
320
321 for (int sepLength = 3; sepLength <= 5; sepLength++) {
322 for (String separator : ImmutableList.of(",", "\n", ";;", "")) {
323 testEncoding(encoding.withSeparator(separator, sepLength), decoded,
324 Joiner.on(separator).join(Splitter.fixedLength(sepLength).split(encoded)));
325 }
326 }
327 }
328
329 private static void testEncoding(BaseEncoding encoding, String decoded, String encoded) {
330 testEncodes(encoding, decoded, encoded);
331 testDecodes(encoding, encoded, decoded);
332 }
333
334 private static void testEncodes(BaseEncoding encoding, String decoded, String encoded) {
335 byte[] bytes;
336 try {
337
338 bytes = decoded.getBytes("UTF-8");
339 } catch (UnsupportedEncodingException e) {
340 throw new AssertionError();
341 }
342 assertEquals(encoded, encoding.encode(bytes));
343 }
344
345 private static void testDecodes(BaseEncoding encoding, String encoded, String decoded) {
346 byte[] bytes;
347 try {
348
349 bytes = decoded.getBytes("UTF-8");
350 } catch (UnsupportedEncodingException e) {
351 throw new AssertionError();
352 }
353 assertEquals(bytes, encoding.decode(encoded));
354 }
355
356 private static void assertFailsToDecode(BaseEncoding encoding, String cannotDecode) {
357 try {
358 encoding.decode(cannotDecode);
359 fail("Expected IllegalArgumentException");
360 } catch (IllegalArgumentException expected) {
361
362 }
363 try {
364 encoding.decodeChecked(cannotDecode);
365 fail("Expected DecodingException");
366 } catch (DecodingException expected) {
367
368 }
369 }
370
371 @GwtIncompatible("Reader/Writer")
372 private static void testStreamingEncodingWithCasing(
373 BaseEncoding encoding, String decoded, String encoded) throws IOException {
374 testStreamingEncodingWithSeparators(encoding, decoded, encoded);
375 testStreamingEncodingWithSeparators(encoding.upperCase(), decoded, Ascii.toUpperCase(encoded));
376 testStreamingEncodingWithSeparators(encoding.lowerCase(), decoded, Ascii.toLowerCase(encoded));
377 }
378
379 @GwtIncompatible("Reader/Writer")
380 private static void testStreamingEncodingWithSeparators(
381 BaseEncoding encoding, String decoded, String encoded) throws IOException {
382 testStreamingEncoding(encoding, decoded, encoded);
383
384
385 for (int sepLength = 3; sepLength <= 5; sepLength++) {
386 for (String separator : ImmutableList.of(",", "\n", ";;", "")) {
387 testStreamingEncoding(encoding.withSeparator(separator, sepLength), decoded,
388 Joiner.on(separator).join(Splitter.fixedLength(sepLength).split(encoded)));
389 }
390 }
391 }
392
393 @GwtIncompatible("Reader/Writer")
394 private static void testStreamingEncoding(BaseEncoding encoding, String decoded, String encoded)
395 throws IOException {
396 testStreamingEncodes(encoding, decoded, encoded);
397 testStreamingDecodes(encoding, encoded, decoded);
398 }
399
400 @GwtIncompatible("Writer")
401 private static void testStreamingEncodes(BaseEncoding encoding, String decoded, String encoded)
402 throws IOException {
403 byte[] bytes;
404 try {
405
406 bytes = decoded.getBytes("UTF-8");
407 } catch (UnsupportedEncodingException e) {
408 throw new AssertionError();
409 }
410 StringWriter writer = new StringWriter();
411 OutputStream encodingStream = encoding.encodingStream(writer);
412 encodingStream.write(bytes);
413 encodingStream.close();
414 assertEquals(encoded, writer.toString());
415 }
416
417 @GwtIncompatible("Reader")
418 private static void testStreamingDecodes(BaseEncoding encoding, String encoded, String decoded)
419 throws IOException {
420 byte[] bytes;
421 try {
422
423 bytes = decoded.getBytes("UTF-8");
424 } catch (UnsupportedEncodingException e) {
425 throw new AssertionError();
426 }
427 InputStream decodingStream = encoding.decodingStream(new StringReader(encoded));
428 for (int i = 0; i < bytes.length; i++) {
429 assertEquals(bytes[i] & 0xFF, decodingStream.read());
430 }
431 assertEquals(-1, decodingStream.read());
432 decodingStream.close();
433 }
434
435 public void testToString() {
436 assertEquals("BaseEncoding.base64().withPadChar(=)", BaseEncoding.base64().toString());
437 assertEquals("BaseEncoding.base32Hex().omitPadding()",
438 BaseEncoding.base32Hex().omitPadding().toString());
439 assertEquals("BaseEncoding.base32().lowerCase().withPadChar($)",
440 BaseEncoding.base32().lowerCase().withPadChar('$').toString());
441 assertEquals("BaseEncoding.base16().withSeparator(\"\n\", 10)",
442 BaseEncoding.base16().withSeparator("\n", 10).toString());
443 }
444 }