1 /* 2 * Copyright (C) 2012 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.io; 16 17 import static com.google.common.base.Charsets.UTF_8; 18 import static com.google.common.io.BaseEncoding.base16; 19 import static com.google.common.io.BaseEncoding.base32; 20 import static com.google.common.io.BaseEncoding.base32Hex; 21 import static com.google.common.io.BaseEncoding.base64; 22 import static com.google.common.io.BaseEncoding.base64Url; 23 import static com.google.common.truth.Truth.assertThat; 24 25 import com.google.common.annotations.GwtCompatible; 26 import com.google.common.annotations.GwtIncompatible; 27 import com.google.common.base.Ascii; 28 import com.google.common.base.Joiner; 29 import com.google.common.base.Splitter; 30 import com.google.common.collect.ImmutableList; 31 import com.google.common.io.BaseEncoding.DecodingException; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.OutputStream; 35 import java.io.Reader; 36 import java.io.StringReader; 37 import java.io.StringWriter; 38 import junit.framework.TestCase; 39 import org.checkerframework.checker.nullness.qual.Nullable; 40 41 /** 42 * Tests for {@code BaseEncoding}. 43 * 44 * @author Louis Wasserman 45 */ 46 @GwtCompatible(emulated = true) 47 public class BaseEncodingTest extends TestCase { 48 testSeparatorsExplicitly()49 public void testSeparatorsExplicitly() { 50 testEncodes(base64().withSeparator("\n", 3), "foobar", "Zm9\nvYm\nFy"); 51 testEncodes(base64().withSeparator("$", 4), "foobar", "Zm9v$YmFy"); 52 testEncodes(base32().withSeparator("*", 4), "foobar", "MZXW*6YTB*OI==*===="); 53 } 54 testSeparatorSameAsPadChar()55 public void testSeparatorSameAsPadChar() { 56 try { 57 base64().withSeparator("=", 3); 58 fail("Expected IllegalArgumentException"); 59 } catch (IllegalArgumentException expected) { 60 } 61 62 try { 63 base64().withPadChar('#').withSeparator("!#!", 3); 64 fail("Expected IllegalArgumentException"); 65 } catch (IllegalArgumentException expected) { 66 } 67 } 68 testAtMostOneSeparator()69 public void testAtMostOneSeparator() { 70 BaseEncoding separated = base64().withSeparator("\n", 3); 71 try { 72 separated.withSeparator("$", 4); 73 fail("Expected UnsupportedOperationException"); 74 } catch (UnsupportedOperationException expected) { 75 } 76 } 77 testBase64()78 public void testBase64() { 79 // The following test vectors are specified in RFC 4648 itself 80 testEncodingWithSeparators(base64(), "", ""); 81 testEncodingWithSeparators(base64(), "f", "Zg=="); 82 testEncodingWithSeparators(base64(), "fo", "Zm8="); 83 testEncodingWithSeparators(base64(), "foo", "Zm9v"); 84 testEncodingWithSeparators(base64(), "foob", "Zm9vYg=="); 85 testEncodingWithSeparators(base64(), "fooba", "Zm9vYmE="); 86 testEncodingWithSeparators(base64(), "foobar", "Zm9vYmFy"); 87 } 88 89 @GwtIncompatible // Reader/Writer testBase64Streaming()90 public void testBase64Streaming() throws IOException { 91 // The following test vectors are specified in RFC 4648 itself 92 testStreamingEncodingWithSeparators(base64(), "", ""); 93 testStreamingEncodingWithSeparators(base64(), "f", "Zg=="); 94 testStreamingEncodingWithSeparators(base64(), "fo", "Zm8="); 95 testStreamingEncodingWithSeparators(base64(), "foo", "Zm9v"); 96 testStreamingEncodingWithSeparators(base64(), "foob", "Zm9vYg=="); 97 testStreamingEncodingWithSeparators(base64(), "fooba", "Zm9vYmE="); 98 testStreamingEncodingWithSeparators(base64(), "foobar", "Zm9vYmFy"); 99 } 100 testBase64LenientPadding()101 public void testBase64LenientPadding() { 102 testDecodes(base64(), "Zg", "f"); 103 testDecodes(base64(), "Zg=", "f"); 104 testDecodes(base64(), "Zg==", "f"); // proper padding length 105 testDecodes(base64(), "Zg===", "f"); 106 testDecodes(base64(), "Zg====", "f"); 107 } 108 testBase64InvalidDecodings()109 public void testBase64InvalidDecodings() { 110 // These contain bytes not in the decodabet. 111 assertFailsToDecode(base64(), "A\u007f", "Unrecognized character: 0x7f"); 112 assertFailsToDecode(base64(), "Wf2!", "Unrecognized character: !"); 113 // This sentence just isn't base64() encoded. 114 assertFailsToDecode(base64(), "let's not talk of love or chains!"); 115 // A 4n+1 length string is never legal base64(). 116 assertFailsToDecode(base64(), "12345", "Invalid input length 5"); 117 // These have a combination of invalid length, unrecognized characters and wrong padding. 118 assertFailsToDecode(base64(), "AB=C", "Unrecognized character: ="); 119 assertFailsToDecode(base64(), "A=BCD", "Invalid input length 5"); 120 assertFailsToDecode(base64(), "?", "Invalid input length 1"); 121 } 122 testBase64CannotUpperCase()123 public void testBase64CannotUpperCase() { 124 try { 125 base64().upperCase(); 126 fail(); 127 } catch (IllegalStateException expected) { 128 // success 129 } 130 } 131 testBase64CannotLowerCase()132 public void testBase64CannotLowerCase() { 133 try { 134 base64().lowerCase(); 135 fail(); 136 } catch (IllegalStateException expected) { 137 // success 138 } 139 } 140 testBase64AlternatePadding()141 public void testBase64AlternatePadding() { 142 BaseEncoding enc = base64().withPadChar('~'); 143 testEncodingWithSeparators(enc, "", ""); 144 testEncodingWithSeparators(enc, "f", "Zg~~"); 145 testEncodingWithSeparators(enc, "fo", "Zm8~"); 146 testEncodingWithSeparators(enc, "foo", "Zm9v"); 147 testEncodingWithSeparators(enc, "foob", "Zm9vYg~~"); 148 testEncodingWithSeparators(enc, "fooba", "Zm9vYmE~"); 149 testEncodingWithSeparators(enc, "foobar", "Zm9vYmFy"); 150 } 151 152 @GwtIncompatible // Reader/Writer testBase64StreamingAlternatePadding()153 public void testBase64StreamingAlternatePadding() throws IOException { 154 BaseEncoding enc = base64().withPadChar('~'); 155 testStreamingEncodingWithSeparators(enc, "", ""); 156 testStreamingEncodingWithSeparators(enc, "f", "Zg~~"); 157 testStreamingEncodingWithSeparators(enc, "fo", "Zm8~"); 158 testStreamingEncodingWithSeparators(enc, "foo", "Zm9v"); 159 testStreamingEncodingWithSeparators(enc, "foob", "Zm9vYg~~"); 160 testStreamingEncodingWithSeparators(enc, "fooba", "Zm9vYmE~"); 161 testStreamingEncodingWithSeparators(enc, "foobar", "Zm9vYmFy"); 162 } 163 testBase64OmitPadding()164 public void testBase64OmitPadding() { 165 BaseEncoding enc = base64().omitPadding(); 166 testEncodingWithSeparators(enc, "", ""); 167 testEncodingWithSeparators(enc, "f", "Zg"); 168 testEncodingWithSeparators(enc, "fo", "Zm8"); 169 testEncodingWithSeparators(enc, "foo", "Zm9v"); 170 testEncodingWithSeparators(enc, "foob", "Zm9vYg"); 171 testEncodingWithSeparators(enc, "fooba", "Zm9vYmE"); 172 testEncodingWithSeparators(enc, "foobar", "Zm9vYmFy"); 173 } 174 175 @GwtIncompatible // Reader/Writer testBase64StreamingOmitPadding()176 public void testBase64StreamingOmitPadding() throws IOException { 177 BaseEncoding enc = base64().omitPadding(); 178 testStreamingEncodingWithSeparators(enc, "", ""); 179 testStreamingEncodingWithSeparators(enc, "f", "Zg"); 180 testStreamingEncodingWithSeparators(enc, "fo", "Zm8"); 181 testStreamingEncodingWithSeparators(enc, "foo", "Zm9v"); 182 testStreamingEncodingWithSeparators(enc, "foob", "Zm9vYg"); 183 testStreamingEncodingWithSeparators(enc, "fooba", "Zm9vYmE"); 184 testStreamingEncodingWithSeparators(enc, "foobar", "Zm9vYmFy"); 185 } 186 testBase64Offset()187 public void testBase64Offset() { 188 testEncodesWithOffset(base64(), "foobar", 0, 6, "Zm9vYmFy"); 189 testEncodesWithOffset(base64(), "foobar", 1, 5, "b29iYXI="); 190 testEncodesWithOffset(base64(), "foobar", 2, 3, "b2Jh"); 191 testEncodesWithOffset(base64(), "foobar", 3, 1, "Yg=="); 192 testEncodesWithOffset(base64(), "foobar", 4, 0, ""); 193 } 194 testBase64Url()195 public void testBase64Url() { 196 testDecodesByBytes(base64Url(), "_zzz", new byte[] {-1, 60, -13}); 197 testDecodesByBytes(base64Url(), "-zzz", new byte[] {-5, 60, -13}); 198 } 199 testBase64UrlInvalidDecodings()200 public void testBase64UrlInvalidDecodings() { 201 assertFailsToDecode(base64Url(), "+zzz", "Unrecognized character: +"); 202 assertFailsToDecode(base64Url(), "/zzz", "Unrecognized character: /"); 203 } 204 testBase32()205 public void testBase32() { 206 // The following test vectors are specified in RFC 4648 itself 207 testEncodingWithCasing(base32(), "", ""); 208 testEncodingWithCasing(base32(), "f", "MY======"); 209 testEncodingWithCasing(base32(), "fo", "MZXQ===="); 210 testEncodingWithCasing(base32(), "foo", "MZXW6==="); 211 testEncodingWithCasing(base32(), "foob", "MZXW6YQ="); 212 testEncodingWithCasing(base32(), "fooba", "MZXW6YTB"); 213 testEncodingWithCasing(base32(), "foobar", "MZXW6YTBOI======"); 214 } 215 216 @GwtIncompatible // Reader/Writer testBase32Streaming()217 public void testBase32Streaming() throws IOException { 218 // The following test vectors are specified in RFC 4648 itself 219 testStreamingEncodingWithCasing(base32(), "", ""); 220 testStreamingEncodingWithCasing(base32(), "f", "MY======"); 221 testStreamingEncodingWithCasing(base32(), "fo", "MZXQ===="); 222 testStreamingEncodingWithCasing(base32(), "foo", "MZXW6==="); 223 testStreamingEncodingWithCasing(base32(), "foob", "MZXW6YQ="); 224 testStreamingEncodingWithCasing(base32(), "fooba", "MZXW6YTB"); 225 testStreamingEncodingWithCasing(base32(), "foobar", "MZXW6YTBOI======"); 226 } 227 testBase32LenientPadding()228 public void testBase32LenientPadding() { 229 testDecodes(base32(), "MZXW6", "foo"); 230 testDecodes(base32(), "MZXW6=", "foo"); 231 testDecodes(base32(), "MZXW6==", "foo"); 232 testDecodes(base32(), "MZXW6===", "foo"); // proper padding length 233 testDecodes(base32(), "MZXW6====", "foo"); 234 testDecodes(base32(), "MZXW6=====", "foo"); 235 } 236 testBase32AlternatePadding()237 public void testBase32AlternatePadding() { 238 BaseEncoding enc = base32().withPadChar('~'); 239 testEncodingWithCasing(enc, "", ""); 240 testEncodingWithCasing(enc, "f", "MY~~~~~~"); 241 testEncodingWithCasing(enc, "fo", "MZXQ~~~~"); 242 testEncodingWithCasing(enc, "foo", "MZXW6~~~"); 243 testEncodingWithCasing(enc, "foob", "MZXW6YQ~"); 244 testEncodingWithCasing(enc, "fooba", "MZXW6YTB"); 245 testEncodingWithCasing(enc, "foobar", "MZXW6YTBOI~~~~~~"); 246 } 247 testBase32InvalidDecodings()248 public void testBase32InvalidDecodings() { 249 // These contain bytes not in the decodabet. 250 assertFailsToDecode(base32(), "A ", "Unrecognized character: 0x20"); 251 assertFailsToDecode(base32(), "Wf2!", "Unrecognized character: f"); 252 // This sentence just isn't base32() encoded. 253 assertFailsToDecode(base32(), "let's not talk of love or chains!"); 254 // An 8n+{1,3,6} length string is never legal base32. 255 assertFailsToDecode(base32(), "A", "Invalid input length 1"); 256 assertFailsToDecode(base32(), "ABC"); 257 assertFailsToDecode(base32(), "ABCDEF"); 258 // These have a combination of invalid length, unrecognized characters and wrong padding. 259 assertFailsToDecode(base32(), "AB=C", "Unrecognized character: ="); 260 assertFailsToDecode(base32(), "A=BCDE", "Invalid input length 6"); 261 assertFailsToDecode(base32(), "?", "Invalid input length 1"); 262 } 263 testBase32UpperCaseIsNoOp()264 public void testBase32UpperCaseIsNoOp() { 265 assertSame(base32(), base32().upperCase()); 266 } 267 testBase32Offset()268 public void testBase32Offset() { 269 testEncodesWithOffset(base32(), "foobar", 0, 6, "MZXW6YTBOI======"); 270 testEncodesWithOffset(base32(), "foobar", 1, 5, "N5XWEYLS"); 271 testEncodesWithOffset(base32(), "foobar", 2, 3, "N5RGC==="); 272 testEncodesWithOffset(base32(), "foobar", 3, 1, "MI======"); 273 testEncodesWithOffset(base32(), "foobar", 4, 0, ""); 274 } 275 testBase32Hex()276 public void testBase32Hex() { 277 // The following test vectors are specified in RFC 4648 itself 278 testEncodingWithCasing(base32Hex(), "", ""); 279 testEncodingWithCasing(base32Hex(), "f", "CO======"); 280 testEncodingWithCasing(base32Hex(), "fo", "CPNG===="); 281 testEncodingWithCasing(base32Hex(), "foo", "CPNMU==="); 282 testEncodingWithCasing(base32Hex(), "foob", "CPNMUOG="); 283 testEncodingWithCasing(base32Hex(), "fooba", "CPNMUOJ1"); 284 testEncodingWithCasing(base32Hex(), "foobar", "CPNMUOJ1E8======"); 285 } 286 287 @GwtIncompatible // Reader/Writer testBase32HexStreaming()288 public void testBase32HexStreaming() throws IOException { 289 // The following test vectors are specified in RFC 4648 itself 290 testStreamingEncodingWithCasing(base32Hex(), "", ""); 291 testStreamingEncodingWithCasing(base32Hex(), "f", "CO======"); 292 testStreamingEncodingWithCasing(base32Hex(), "fo", "CPNG===="); 293 testStreamingEncodingWithCasing(base32Hex(), "foo", "CPNMU==="); 294 testStreamingEncodingWithCasing(base32Hex(), "foob", "CPNMUOG="); 295 testStreamingEncodingWithCasing(base32Hex(), "fooba", "CPNMUOJ1"); 296 testStreamingEncodingWithCasing(base32Hex(), "foobar", "CPNMUOJ1E8======"); 297 } 298 testBase32HexLenientPadding()299 public void testBase32HexLenientPadding() { 300 testDecodes(base32Hex(), "CPNMU", "foo"); 301 testDecodes(base32Hex(), "CPNMU=", "foo"); 302 testDecodes(base32Hex(), "CPNMU==", "foo"); 303 testDecodes(base32Hex(), "CPNMU===", "foo"); // proper padding length 304 testDecodes(base32Hex(), "CPNMU====", "foo"); 305 testDecodes(base32Hex(), "CPNMU=====", "foo"); 306 } 307 testBase32HexInvalidDecodings()308 public void testBase32HexInvalidDecodings() { 309 // These contain bytes not in the decodabet. 310 assertFailsToDecode(base32Hex(), "A\u007f", "Unrecognized character: 0x7f"); 311 assertFailsToDecode(base32Hex(), "Wf2!", "Unrecognized character: W"); 312 // This sentence just isn't base32 encoded. 313 assertFailsToDecode(base32Hex(), "let's not talk of love or chains!"); 314 // An 8n+{1,3,6} length string is never legal base32. 315 assertFailsToDecode(base32Hex(), "A"); 316 assertFailsToDecode(base32Hex(), "ABC"); 317 assertFailsToDecode(base32Hex(), "ABCDEF"); 318 } 319 testBase32HexUpperCaseIsNoOp()320 public void testBase32HexUpperCaseIsNoOp() { 321 assertSame(base32Hex(), base32Hex().upperCase()); 322 } 323 testBase16()324 public void testBase16() { 325 testEncodingWithCasing(base16(), "", ""); 326 testEncodingWithCasing(base16(), "f", "66"); 327 testEncodingWithCasing(base16(), "fo", "666F"); 328 testEncodingWithCasing(base16(), "foo", "666F6F"); 329 testEncodingWithCasing(base16(), "foob", "666F6F62"); 330 testEncodingWithCasing(base16(), "fooba", "666F6F6261"); 331 testEncodingWithCasing(base16(), "foobar", "666F6F626172"); 332 } 333 testBase16UpperCaseIsNoOp()334 public void testBase16UpperCaseIsNoOp() { 335 assertSame(base16(), base16().upperCase()); 336 } 337 testBase16InvalidDecodings()338 public void testBase16InvalidDecodings() { 339 // These contain bytes not in the decodabet. 340 assertFailsToDecode(base16(), "\n\n", "Unrecognized character: 0xa"); 341 assertFailsToDecode(base16(), "EFGH", "Unrecognized character: G"); 342 // Valid base16 strings always have an even length. 343 assertFailsToDecode(base16(), "A", "Invalid input length 1"); 344 assertFailsToDecode(base16(), "ABC"); 345 // These have a combination of invalid length and unrecognized characters. 346 assertFailsToDecode(base16(), "?", "Invalid input length 1"); 347 } 348 testBase16Offset()349 public void testBase16Offset() { 350 testEncodesWithOffset(base16(), "foobar", 0, 6, "666F6F626172"); 351 testEncodesWithOffset(base16(), "foobar", 1, 5, "6F6F626172"); 352 testEncodesWithOffset(base16(), "foobar", 2, 3, "6F6261"); 353 testEncodesWithOffset(base16(), "foobar", 3, 1, "62"); 354 testEncodesWithOffset(base16(), "foobar", 4, 0, ""); 355 } 356 testEncodingWithCasing( BaseEncoding encoding, String decoded, String encoded)357 private static void testEncodingWithCasing( 358 BaseEncoding encoding, String decoded, String encoded) { 359 testEncodingWithSeparators(encoding, decoded, encoded); 360 testEncodingWithSeparators(encoding.upperCase(), decoded, Ascii.toUpperCase(encoded)); 361 testEncodingWithSeparators(encoding.lowerCase(), decoded, Ascii.toLowerCase(encoded)); 362 } 363 testEncodingWithSeparators( BaseEncoding encoding, String decoded, String encoded)364 private static void testEncodingWithSeparators( 365 BaseEncoding encoding, String decoded, String encoded) { 366 testEncoding(encoding, decoded, encoded); 367 368 // test separators work 369 for (int sepLength = 3; sepLength <= 5; sepLength++) { 370 for (String separator : ImmutableList.of(",", "\n", ";;", "")) { 371 testEncoding( 372 encoding.withSeparator(separator, sepLength), 373 decoded, 374 Joiner.on(separator).join(Splitter.fixedLength(sepLength).split(encoded))); 375 } 376 } 377 } 378 testEncoding(BaseEncoding encoding, String decoded, String encoded)379 private static void testEncoding(BaseEncoding encoding, String decoded, String encoded) { 380 testEncodes(encoding, decoded, encoded); 381 testDecodes(encoding, encoded, decoded); 382 } 383 testEncodes(BaseEncoding encoding, String decoded, String encoded)384 private static void testEncodes(BaseEncoding encoding, String decoded, String encoded) { 385 assertThat(encoding.encode(decoded.getBytes(UTF_8))).isEqualTo(encoded); 386 } 387 testEncodesWithOffset( BaseEncoding encoding, String decoded, int offset, int len, String encoded)388 private static void testEncodesWithOffset( 389 BaseEncoding encoding, String decoded, int offset, int len, String encoded) { 390 assertThat(encoding.encode(decoded.getBytes(UTF_8), offset, len)).isEqualTo(encoded); 391 } 392 testDecodes(BaseEncoding encoding, String encoded, String decoded)393 private static void testDecodes(BaseEncoding encoding, String encoded, String decoded) { 394 assertTrue(encoding.canDecode(encoded)); 395 assertThat(encoding.decode(encoded)).isEqualTo(decoded.getBytes(UTF_8)); 396 } 397 testDecodesByBytes(BaseEncoding encoding, String encoded, byte[] decoded)398 private static void testDecodesByBytes(BaseEncoding encoding, String encoded, byte[] decoded) { 399 assertTrue(encoding.canDecode(encoded)); 400 assertThat(encoding.decode(encoded)).isEqualTo(decoded); 401 } 402 assertFailsToDecode(BaseEncoding encoding, String cannotDecode)403 private static void assertFailsToDecode(BaseEncoding encoding, String cannotDecode) { 404 assertFailsToDecode(encoding, cannotDecode, null); 405 } 406 assertFailsToDecode( BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage)407 private static void assertFailsToDecode( 408 BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage) { 409 // We use this somewhat weird pattern with an enum for each assertion we want to make as a way 410 // of dealing with the fact that one of the assertions is @GwtIncompatible but we don't want to 411 // have to have duplicate @GwtIncompatible test methods just to make that assertion. 412 for (AssertFailsToDecodeStrategy strategy : AssertFailsToDecodeStrategy.values()) { 413 strategy.assertFailsToDecode(encoding, cannotDecode, expectedMessage); 414 } 415 } 416 417 enum AssertFailsToDecodeStrategy { 418 @GwtIncompatible // decodingStream(Reader) 419 DECODING_STREAM { 420 @Override assertFailsToDecode( BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage)421 void assertFailsToDecode( 422 BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage) { 423 // Regression test for case where DecodingException was swallowed by default implementation 424 // of 425 // InputStream.read(byte[], int, int) 426 // See https://github.com/google/guava/issues/3542 427 Reader reader = new StringReader(cannotDecode); 428 InputStream decodingStream = encoding.decodingStream(reader); 429 try { 430 ByteStreams.exhaust(decodingStream); 431 fail("Expected DecodingException"); 432 } catch (DecodingException expected) { 433 // Don't assert on the expectedMessage; the messages for exceptions thrown from the 434 // decoding stream may differ from the messages for the decode methods. 435 } catch (IOException e) { 436 fail("Expected DecodingException but got: " + e); 437 } 438 } 439 }, 440 CAN_DECODE { 441 @Override assertFailsToDecode( BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage)442 void assertFailsToDecode( 443 BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage) { 444 assertFalse(encoding.canDecode(cannotDecode)); 445 } 446 }, 447 DECODE { 448 @Override assertFailsToDecode( BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage)449 void assertFailsToDecode( 450 BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage) { 451 try { 452 encoding.decode(cannotDecode); 453 fail("Expected IllegalArgumentException"); 454 } catch (IllegalArgumentException expected) { 455 if (expectedMessage != null) { 456 assertThat(expected).hasCauseThat().hasMessageThat().isEqualTo(expectedMessage); 457 } 458 } 459 } 460 }, 461 DECODE_CHECKED { 462 @Override assertFailsToDecode( BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage)463 void assertFailsToDecode( 464 BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage) { 465 try { 466 encoding.decodeChecked(cannotDecode); 467 fail("Expected DecodingException"); 468 } catch (DecodingException expected) { 469 if (expectedMessage != null) { 470 assertThat(expected).hasMessageThat().isEqualTo(expectedMessage); 471 } 472 } 473 } 474 }; 475 assertFailsToDecode( BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage)476 abstract void assertFailsToDecode( 477 BaseEncoding encoding, String cannotDecode, @Nullable String expectedMessage); 478 } 479 480 @GwtIncompatible // Reader/Writer testStreamingEncodingWithCasing( BaseEncoding encoding, String decoded, String encoded)481 private static void testStreamingEncodingWithCasing( 482 BaseEncoding encoding, String decoded, String encoded) throws IOException { 483 testStreamingEncodingWithSeparators(encoding, decoded, encoded); 484 testStreamingEncodingWithSeparators(encoding.upperCase(), decoded, Ascii.toUpperCase(encoded)); 485 testStreamingEncodingWithSeparators(encoding.lowerCase(), decoded, Ascii.toLowerCase(encoded)); 486 } 487 488 @GwtIncompatible // Reader/Writer testStreamingEncodingWithSeparators( BaseEncoding encoding, String decoded, String encoded)489 private static void testStreamingEncodingWithSeparators( 490 BaseEncoding encoding, String decoded, String encoded) throws IOException { 491 testStreamingEncoding(encoding, decoded, encoded); 492 493 // test separators work 494 for (int sepLength = 3; sepLength <= 5; sepLength++) { 495 for (String separator : ImmutableList.of(",", "\n", ";;", "")) { 496 testStreamingEncoding( 497 encoding.withSeparator(separator, sepLength), 498 decoded, 499 Joiner.on(separator).join(Splitter.fixedLength(sepLength).split(encoded))); 500 } 501 } 502 } 503 504 @GwtIncompatible // Reader/Writer testStreamingEncoding(BaseEncoding encoding, String decoded, String encoded)505 private static void testStreamingEncoding(BaseEncoding encoding, String decoded, String encoded) 506 throws IOException { 507 testStreamingEncodes(encoding, decoded, encoded); 508 testStreamingDecodes(encoding, encoded, decoded); 509 } 510 511 @GwtIncompatible // Writer testStreamingEncodes(BaseEncoding encoding, String decoded, String encoded)512 private static void testStreamingEncodes(BaseEncoding encoding, String decoded, String encoded) 513 throws IOException { 514 StringWriter writer = new StringWriter(); 515 OutputStream encodingStream = encoding.encodingStream(writer); 516 encodingStream.write(decoded.getBytes(UTF_8)); 517 encodingStream.close(); 518 assertThat(writer.toString()).isEqualTo(encoded); 519 } 520 521 @GwtIncompatible // Reader testStreamingDecodes(BaseEncoding encoding, String encoded, String decoded)522 private static void testStreamingDecodes(BaseEncoding encoding, String encoded, String decoded) 523 throws IOException { 524 byte[] bytes = decoded.getBytes(UTF_8); 525 InputStream decodingStream = encoding.decodingStream(new StringReader(encoded)); 526 for (int i = 0; i < bytes.length; i++) { 527 assertThat(decodingStream.read()).isEqualTo(bytes[i] & 0xFF); 528 } 529 assertThat(decodingStream.read()).isEqualTo(-1); 530 decodingStream.close(); 531 } 532 testToString()533 public void testToString() { 534 assertEquals("BaseEncoding.base64().withPadChar('=')", base64().toString()); 535 assertEquals("BaseEncoding.base32Hex().omitPadding()", base32Hex().omitPadding().toString()); 536 assertEquals( 537 "BaseEncoding.base32().lowerCase().withPadChar('$')", 538 base32().lowerCase().withPadChar('$').toString()); 539 assertEquals( 540 "BaseEncoding.base16().withSeparator(\"\n\", 10)", 541 base16().withSeparator("\n", 10).toString()); 542 } 543 } 544