github.com/ActiveState/go@v0.0.0-20170614201249-0b81c023a722/src/encoding/base64/base64_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package base64 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "reflect" 14 "strings" 15 "testing" 16 "time" 17 ) 18 19 type testpair struct { 20 decoded, encoded string 21 } 22 23 var pairs = []testpair{ 24 // RFC 3548 examples 25 {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"}, 26 {"\x14\xfb\x9c\x03\xd9", "FPucA9k="}, 27 {"\x14\xfb\x9c\x03", "FPucAw=="}, 28 29 // RFC 4648 examples 30 {"", ""}, 31 {"f", "Zg=="}, 32 {"fo", "Zm8="}, 33 {"foo", "Zm9v"}, 34 {"foob", "Zm9vYg=="}, 35 {"fooba", "Zm9vYmE="}, 36 {"foobar", "Zm9vYmFy"}, 37 38 // Wikipedia examples 39 {"sure.", "c3VyZS4="}, 40 {"sure", "c3VyZQ=="}, 41 {"sur", "c3Vy"}, 42 {"su", "c3U="}, 43 {"leasure.", "bGVhc3VyZS4="}, 44 {"easure.", "ZWFzdXJlLg=="}, 45 {"asure.", "YXN1cmUu"}, 46 {"sure.", "c3VyZS4="}, 47 } 48 49 // Do nothing to a reference base64 string (leave in standard format) 50 func stdRef(ref string) string { 51 return ref 52 } 53 54 // Convert a reference string to URL-encoding 55 func urlRef(ref string) string { 56 ref = strings.Replace(ref, "+", "-", -1) 57 ref = strings.Replace(ref, "/", "_", -1) 58 return ref 59 } 60 61 // Convert a reference string to raw, unpadded format 62 func rawRef(ref string) string { 63 return strings.TrimRight(ref, "=") 64 } 65 66 // Both URL and unpadding conversions 67 func rawURLRef(ref string) string { 68 return rawRef(urlRef(ref)) 69 } 70 71 // A nonstandard encoding with a funny padding character, for testing 72 var funnyEncoding = NewEncoding(encodeStd).WithPadding(rune('@')) 73 74 func funnyRef(ref string) string { 75 return strings.Replace(ref, "=", "@", -1) 76 } 77 78 type encodingTest struct { 79 enc *Encoding // Encoding to test 80 conv func(string) string // Reference string converter 81 } 82 83 var encodingTests = []encodingTest{ 84 {StdEncoding, stdRef}, 85 {URLEncoding, urlRef}, 86 {RawStdEncoding, rawRef}, 87 {RawURLEncoding, rawURLRef}, 88 {funnyEncoding, funnyRef}, 89 {StdEncoding.Strict(), stdRef}, 90 {URLEncoding.Strict(), urlRef}, 91 {RawStdEncoding.Strict(), rawRef}, 92 {RawURLEncoding.Strict(), rawURLRef}, 93 {funnyEncoding.Strict(), funnyRef}, 94 } 95 96 var bigtest = testpair{ 97 "Twas brillig, and the slithy toves", 98 "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", 99 } 100 101 func testEqual(t *testing.T, msg string, args ...interface{}) bool { 102 if args[len(args)-2] != args[len(args)-1] { 103 t.Errorf(msg, args...) 104 return false 105 } 106 return true 107 } 108 109 func TestEncode(t *testing.T) { 110 for _, p := range pairs { 111 for _, tt := range encodingTests { 112 got := tt.enc.EncodeToString([]byte(p.decoded)) 113 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, 114 got, tt.conv(p.encoded)) 115 } 116 } 117 } 118 119 func TestEncoder(t *testing.T) { 120 for _, p := range pairs { 121 bb := &bytes.Buffer{} 122 encoder := NewEncoder(StdEncoding, bb) 123 encoder.Write([]byte(p.decoded)) 124 encoder.Close() 125 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded) 126 } 127 } 128 129 func TestEncoderBuffering(t *testing.T) { 130 input := []byte(bigtest.decoded) 131 for bs := 1; bs <= 12; bs++ { 132 bb := &bytes.Buffer{} 133 encoder := NewEncoder(StdEncoding, bb) 134 for pos := 0; pos < len(input); pos += bs { 135 end := pos + bs 136 if end > len(input) { 137 end = len(input) 138 } 139 n, err := encoder.Write(input[pos:end]) 140 testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil)) 141 testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos) 142 } 143 err := encoder.Close() 144 testEqual(t, "Close gave error %v, want %v", err, error(nil)) 145 testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded) 146 } 147 } 148 149 func TestDecode(t *testing.T) { 150 for _, p := range pairs { 151 for _, tt := range encodingTests { 152 encoded := tt.conv(p.encoded) 153 dbuf := make([]byte, tt.enc.DecodedLen(len(encoded))) 154 count, end, err := tt.enc.decode(dbuf, []byte(encoded)) 155 testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil)) 156 testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded)) 157 if len(encoded) > 0 { 158 testEqual(t, "Decode(%q) = end %v, want %v", encoded, end, len(p.decoded)%3 != 0) 159 } 160 testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded) 161 162 dbuf, err = tt.enc.DecodeString(encoded) 163 testEqual(t, "DecodeString(%q) = error %v, want %v", encoded, err, error(nil)) 164 testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded) 165 } 166 } 167 } 168 169 func TestDecoder(t *testing.T) { 170 for _, p := range pairs { 171 decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded)) 172 dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded))) 173 count, err := decoder.Read(dbuf) 174 if err != nil && err != io.EOF { 175 t.Fatal("Read failed", err) 176 } 177 testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded)) 178 testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) 179 if err != io.EOF { 180 count, err = decoder.Read(dbuf) 181 } 182 testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF) 183 } 184 } 185 186 func TestDecoderBuffering(t *testing.T) { 187 for bs := 1; bs <= 12; bs++ { 188 decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded)) 189 buf := make([]byte, len(bigtest.decoded)+12) 190 var total int 191 for total = 0; total < len(bigtest.decoded); { 192 n, err := decoder.Read(buf[total : total+bs]) 193 testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, error(nil)) 194 total += n 195 } 196 testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded) 197 } 198 } 199 200 func TestDecodeCorrupt(t *testing.T) { 201 testCases := []struct { 202 input string 203 offset int // -1 means no corruption. 204 }{ 205 {"", -1}, 206 {"\n", -1}, 207 {"AAA=\n", -1}, 208 {"AAAA\n", -1}, 209 {"!!!!", 0}, 210 {"====", 0}, 211 {"x===", 1}, 212 {"=AAA", 0}, 213 {"A=AA", 1}, 214 {"AA=A", 2}, 215 {"AA==A", 4}, 216 {"AAA=AAAA", 4}, 217 {"AAAAA", 4}, 218 {"AAAAAA", 4}, 219 {"A=", 1}, 220 {"A==", 1}, 221 {"AA=", 3}, 222 {"AA==", -1}, 223 {"AAA=", -1}, 224 {"AAAA", -1}, 225 {"AAAAAA=", 7}, 226 {"YWJjZA=====", 8}, 227 {"A!\n", 1}, 228 {"A=\n", 1}, 229 } 230 for _, tc := range testCases { 231 dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input))) 232 _, err := StdEncoding.Decode(dbuf, []byte(tc.input)) 233 if tc.offset == -1 { 234 if err != nil { 235 t.Error("Decoder wrongly detected corruption in", tc.input) 236 } 237 continue 238 } 239 switch err := err.(type) { 240 case CorruptInputError: 241 testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset) 242 default: 243 t.Error("Decoder failed to detect corruption in", tc) 244 } 245 } 246 } 247 248 func TestEncodedLen(t *testing.T) { 249 for _, tt := range []struct { 250 enc *Encoding 251 n int 252 want int 253 }{ 254 {RawStdEncoding, 0, 0}, 255 {RawStdEncoding, 1, 2}, 256 {RawStdEncoding, 2, 3}, 257 {RawStdEncoding, 3, 4}, 258 {RawStdEncoding, 7, 10}, 259 {StdEncoding, 0, 0}, 260 {StdEncoding, 1, 4}, 261 {StdEncoding, 2, 4}, 262 {StdEncoding, 3, 4}, 263 {StdEncoding, 4, 8}, 264 {StdEncoding, 7, 12}, 265 } { 266 if got := tt.enc.EncodedLen(tt.n); got != tt.want { 267 t.Errorf("EncodedLen(%d): got %d, want %d", tt.n, got, tt.want) 268 } 269 } 270 } 271 272 func TestDecodedLen(t *testing.T) { 273 for _, tt := range []struct { 274 enc *Encoding 275 n int 276 want int 277 }{ 278 {RawStdEncoding, 0, 0}, 279 {RawStdEncoding, 2, 1}, 280 {RawStdEncoding, 3, 2}, 281 {RawStdEncoding, 4, 3}, 282 {RawStdEncoding, 10, 7}, 283 {StdEncoding, 0, 0}, 284 {StdEncoding, 4, 3}, 285 {StdEncoding, 8, 6}, 286 } { 287 if got := tt.enc.DecodedLen(tt.n); got != tt.want { 288 t.Errorf("DecodedLen(%d): got %d, want %d", tt.n, got, tt.want) 289 } 290 } 291 } 292 293 func TestBig(t *testing.T) { 294 n := 3*1000 + 1 295 raw := make([]byte, n) 296 const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 297 for i := 0; i < n; i++ { 298 raw[i] = alpha[i%len(alpha)] 299 } 300 encoded := new(bytes.Buffer) 301 w := NewEncoder(StdEncoding, encoded) 302 nn, err := w.Write(raw) 303 if nn != n || err != nil { 304 t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n) 305 } 306 err = w.Close() 307 if err != nil { 308 t.Fatalf("Encoder.Close() = %v want nil", err) 309 } 310 decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded)) 311 if err != nil { 312 t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err) 313 } 314 315 if !bytes.Equal(raw, decoded) { 316 var i int 317 for i = 0; i < len(decoded) && i < len(raw); i++ { 318 if decoded[i] != raw[i] { 319 break 320 } 321 } 322 t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i) 323 } 324 } 325 326 func TestNewLineCharacters(t *testing.T) { 327 // Each of these should decode to the string "sure", without errors. 328 const expected = "sure" 329 examples := []string{ 330 "c3VyZQ==", 331 "c3VyZQ==\r", 332 "c3VyZQ==\n", 333 "c3VyZQ==\r\n", 334 "c3VyZ\r\nQ==", 335 "c3V\ryZ\nQ==", 336 "c3V\nyZ\rQ==", 337 "c3VyZ\nQ==", 338 "c3VyZQ\n==", 339 "c3VyZQ=\n=", 340 "c3VyZQ=\r\n\r\n=", 341 } 342 for _, e := range examples { 343 buf, err := StdEncoding.DecodeString(e) 344 if err != nil { 345 t.Errorf("Decode(%q) failed: %v", e, err) 346 continue 347 } 348 if s := string(buf); s != expected { 349 t.Errorf("Decode(%q) = %q, want %q", e, s, expected) 350 } 351 } 352 } 353 354 type nextRead struct { 355 n int // bytes to return 356 err error // error to return 357 } 358 359 // faultInjectReader returns data from source, rate-limited 360 // and with the errors as written to nextc. 361 type faultInjectReader struct { 362 source string 363 nextc <-chan nextRead 364 } 365 366 func (r *faultInjectReader) Read(p []byte) (int, error) { 367 nr := <-r.nextc 368 if len(p) > nr.n { 369 p = p[:nr.n] 370 } 371 n := copy(p, r.source) 372 r.source = r.source[n:] 373 return n, nr.err 374 } 375 376 // tests that we don't ignore errors from our underlying reader 377 func TestDecoderIssue3577(t *testing.T) { 378 next := make(chan nextRead, 10) 379 wantErr := errors.New("my error") 380 next <- nextRead{5, nil} 381 next <- nextRead{10, wantErr} 382 next <- nextRead{0, wantErr} 383 d := NewDecoder(StdEncoding, &faultInjectReader{ 384 source: "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", // twas brillig... 385 nextc: next, 386 }) 387 errc := make(chan error) 388 go func() { 389 _, err := ioutil.ReadAll(d) 390 errc <- err 391 }() 392 select { 393 case err := <-errc: 394 if err != wantErr { 395 t.Errorf("got error %v; want %v", err, wantErr) 396 } 397 case <-time.After(5 * time.Second): 398 t.Errorf("timeout; Decoder blocked without returning an error") 399 } 400 } 401 402 func TestDecoderIssue4779(t *testing.T) { 403 encoded := `CP/EAT8AAAEF 404 AQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAAB 405 BAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHx 406 Y3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm 407 9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS 408 0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0 409 pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A9VSSSSUpJJJJSkkkJ+Tj 410 1kiy1jCJJDnAcCTykpKkuQ6p/jN6FgmxlNduXawwAzaGH+V6jn/R/wCt71zdn+N/qL3kVYFNYB4N 411 ji6PDVjWpKp9TSXnvTf8bFNjg3qOEa2n6VlLpj/rT/pf567DpX1i6L1hs9Py67X8mqdtg/rUWbbf 412 +gkp0kkkklKSSSSUpJJJJT//0PVUkkklKVLq3WMDpGI7KzrNjADtYNXvI/Mqr/Pd/q9W3vaxjnvM 413 NaCXE9gNSvGPrf8AWS3qmba5jjsJhoB0DAf0NDf6sevf+/lf8Hj0JJATfWT6/dV6oXU1uOLQeKKn 414 EQP+Hubtfe/+R7Mf/g7f5xcocp++Z11JMCJPgFBxOg7/AOuqDx8I/ikpkXkmSdU8mJIJA/O8EMAy 415 j+mSARB/17pKVXYWHXjsj7yIex0PadzXMO1zT5KHoNA3HT8ietoGhgjsfA+CSnvvqh/jJtqsrwOv 416 2b6NGNzXfTYexzJ+nU7/ALkf4P8Awv6P9KvTQQ4AgyDqCF85Pho3CTB7eHwXoH+LT65uZbX9X+o2 417 bqbPb06551Y4 418 ` 419 encodedShort := strings.Replace(encoded, "\n", "", -1) 420 421 dec := NewDecoder(StdEncoding, strings.NewReader(encoded)) 422 res1, err := ioutil.ReadAll(dec) 423 if err != nil { 424 t.Errorf("ReadAll failed: %v", err) 425 } 426 427 dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort)) 428 var res2 []byte 429 res2, err = ioutil.ReadAll(dec) 430 if err != nil { 431 t.Errorf("ReadAll failed: %v", err) 432 } 433 434 if !bytes.Equal(res1, res2) { 435 t.Error("Decoded results not equal") 436 } 437 } 438 439 func TestDecoderIssue7733(t *testing.T) { 440 s, err := StdEncoding.DecodeString("YWJjZA=====") 441 want := CorruptInputError(8) 442 if !reflect.DeepEqual(want, err) { 443 t.Errorf("Error = %v; want CorruptInputError(8)", err) 444 } 445 if string(s) != "abcd" { 446 t.Errorf("DecodeString = %q; want abcd", s) 447 } 448 } 449 450 func TestDecoderIssue15656(t *testing.T) { 451 _, err := StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDB==") 452 want := CorruptInputError(22) 453 if !reflect.DeepEqual(want, err) { 454 t.Errorf("Error = %v; want CorruptInputError(22)", err) 455 } 456 _, err = StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDA==") 457 if err != nil { 458 t.Errorf("Error = %v; want nil", err) 459 } 460 _, err = StdEncoding.DecodeString("WvLTlMrX9NpYDQlEIFlnDB==") 461 if err != nil { 462 t.Errorf("Error = %v; want nil", err) 463 } 464 } 465 466 func BenchmarkEncodeToString(b *testing.B) { 467 data := make([]byte, 8192) 468 b.SetBytes(int64(len(data))) 469 for i := 0; i < b.N; i++ { 470 StdEncoding.EncodeToString(data) 471 } 472 } 473 474 func BenchmarkDecodeString(b *testing.B) { 475 sizes := []int{2, 4, 8, 64, 8192} 476 benchFunc := func(b *testing.B, benchSize int) { 477 data := StdEncoding.EncodeToString(make([]byte, benchSize)) 478 b.SetBytes(int64(len(data))) 479 b.ResetTimer() 480 for i := 0; i < b.N; i++ { 481 StdEncoding.DecodeString(data) 482 } 483 } 484 for _, size := range sizes { 485 b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { 486 benchFunc(b, size) 487 }) 488 } 489 } 490 491 func TestDecoderRaw(t *testing.T) { 492 source := "AAAAAA" 493 want := []byte{0, 0, 0, 0} 494 495 // Direct. 496 dec1, err := RawURLEncoding.DecodeString(source) 497 if err != nil || !bytes.Equal(dec1, want) { 498 t.Errorf("RawURLEncoding.DecodeString(%q) = %x, %v, want %x, nil", source, dec1, err, want) 499 } 500 501 // Through reader. Used to fail. 502 r := NewDecoder(RawURLEncoding, bytes.NewReader([]byte(source))) 503 dec2, err := ioutil.ReadAll(io.LimitReader(r, 100)) 504 if err != nil || !bytes.Equal(dec2, want) { 505 t.Errorf("reading NewDecoder(RawURLEncoding, %q) = %x, %v, want %x, nil", source, dec2, err, want) 506 } 507 508 // Should work with padding. 509 r = NewDecoder(URLEncoding, bytes.NewReader([]byte(source+"=="))) 510 dec3, err := ioutil.ReadAll(r) 511 if err != nil || !bytes.Equal(dec3, want) { 512 t.Errorf("reading NewDecoder(URLEncoding, %q) = %x, %v, want %x, nil", source+"==", dec3, err, want) 513 } 514 }