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