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.
21 type testpair struct {
22 decoded, encoded string
25 var pairs = []testpair{
27 {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
28 {"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
29 {"\x14\xfb\x9c\x03", "FPucAw=="},
37 {"fooba", "Zm9vYmE="},
38 {"foobar", "Zm9vYmFy"},
41 {"sure.", "c3VyZS4="},
45 {"leasure.", "bGVhc3VyZS4="},
46 {"easure.", "ZWFzdXJlLg=="},
47 {"asure.", "YXN1cmUu"},
48 {"sure.", "c3VyZS4="},
51 // Do nothing to a reference base64 string (leave in standard format)
52 func stdRef(ref string) string {
56 // Convert a reference string to URL-encoding
57 func urlRef(ref string) string {
58 ref = strings.ReplaceAll(ref, "+", "-")
59 ref = strings.ReplaceAll(ref, "/", "_")
63 // Convert a reference string to raw, unpadded format
64 func rawRef(ref string) string {
65 return strings.TrimRight(ref, "=")
68 // Both URL and unpadding conversions
69 func rawURLRef(ref string) string {
70 return rawRef(urlRef(ref))
73 // A nonstandard encoding with a funny padding character, for testing
74 var funnyEncoding = NewEncoding(encodeStd).WithPadding(rune('@'))
76 func funnyRef(ref string) string {
77 return strings.ReplaceAll(ref, "=", "@")
80 type encodingTest struct {
81 enc *Encoding // Encoding to test
82 conv func(string) string // Reference string converter
85 var encodingTests = []encodingTest{
86 {StdEncoding, stdRef},
87 {URLEncoding, urlRef},
88 {RawStdEncoding, rawRef},
89 {RawURLEncoding, rawURLRef},
90 {funnyEncoding, funnyRef},
91 {StdEncoding.Strict(), stdRef},
92 {URLEncoding.Strict(), urlRef},
93 {RawStdEncoding.Strict(), rawRef},
94 {RawURLEncoding.Strict(), rawURLRef},
95 {funnyEncoding.Strict(), funnyRef},
98 var bigtest = testpair{
99 "Twas brillig, and the slithy toves",
100 "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
103 func testEqual(t *testing.T, msg string, args ...any) bool {
105 if args[len(args)-2] != args[len(args)-1] {
106 t.Errorf(msg, args...)
112 func TestEncode(t *testing.T) {
113 for _, p := range pairs {
114 for _, tt := range encodingTests {
115 got := tt.enc.EncodeToString([]byte(p.decoded))
116 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, tt.conv(p.encoded))
117 dst := tt.enc.AppendEncode([]byte("lead"), []byte(p.decoded))
118 testEqual(t, `AppendEncode("lead", %q) = %q, want %q`, p.decoded, string(dst), "lead"+tt.conv(p.encoded))
123 func TestEncoder(t *testing.T) {
124 for _, p := range pairs {
125 bb := &strings.Builder{}
126 encoder := NewEncoder(StdEncoding, bb)
127 encoder.Write([]byte(p.decoded))
129 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
133 func TestEncoderBuffering(t *testing.T) {
134 input := []byte(bigtest.decoded)
135 for bs := 1; bs <= 12; bs++ {
136 bb := &strings.Builder{}
137 encoder := NewEncoder(StdEncoding, bb)
138 for pos := 0; pos < len(input); pos += bs {
140 if end > len(input) {
143 n, err := encoder.Write(input[pos:end])
144 testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil))
145 testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
147 err := encoder.Close()
148 testEqual(t, "Close gave error %v, want %v", err, error(nil))
149 testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
153 func TestDecode(t *testing.T) {
154 for _, p := range pairs {
155 for _, tt := range encodingTests {
156 encoded := tt.conv(p.encoded)
157 dbuf := make([]byte, tt.enc.DecodedLen(len(encoded)))
158 count, err := tt.enc.Decode(dbuf, []byte(encoded))
159 testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil))
160 testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded))
161 testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded)
163 dbuf, err = tt.enc.DecodeString(encoded)
164 testEqual(t, "DecodeString(%q) = error %v, want %v", encoded, err, error(nil))
165 testEqual(t, "DecodeString(%q) = %q, want %q", encoded, string(dbuf), p.decoded)
167 dst, err := tt.enc.AppendDecode([]byte("lead"), []byte(encoded))
168 testEqual(t, "AppendDecode(%q) = error %v, want %v", p.encoded, err, error(nil))
169 testEqual(t, `AppendDecode("lead", %q) = %q, want %q`, p.encoded, string(dst), "lead"+p.decoded)
174 func TestDecoder(t *testing.T) {
175 for _, p := range pairs {
176 decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
177 dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
178 count, err := decoder.Read(dbuf)
179 if err != nil && err != io.EOF {
180 t.Fatal("Read failed", err)
182 testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
183 testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
185 _, err = decoder.Read(dbuf)
187 testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF)
191 func TestDecoderBuffering(t *testing.T) {
192 for bs := 1; bs <= 12; bs++ {
193 decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
194 buf := make([]byte, len(bigtest.decoded)+12)
198 for total = 0; total < len(bigtest.decoded) && err == nil; {
199 n, err = decoder.Read(buf[total : total+bs])
202 if err != nil && err != io.EOF {
203 t.Errorf("Read from %q at pos %d = %d, unexpected error %v", bigtest.encoded, total, n, err)
205 testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
209 func TestDecodeCorrupt(t *testing.T) {
210 testCases := []struct {
212 offset int // -1 means no corruption.
239 for _, tc := range testCases {
240 dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
241 _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
244 t.Error("Decoder wrongly detected corruption in", tc.input)
248 switch err := err.(type) {
249 case CorruptInputError:
250 testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
252 t.Error("Decoder failed to detect corruption in", tc)
257 func TestDecodeBounds(t *testing.T) {
259 s := StdEncoding.EncodeToString(buf[:])
261 if err := recover(); err != nil {
262 t.Fatalf("Decode panicked unexpectedly: %v\n%s", err, debug.Stack())
265 n, err := StdEncoding.Decode(buf[:], []byte(s))
266 if n != len(buf) || err != nil {
267 t.Fatalf("StdEncoding.Decode = %d, %v, want %d, nil", n, err, len(buf))
271 func TestEncodedLen(t *testing.T) {
278 {RawStdEncoding, 0, 0},
279 {RawStdEncoding, 1, 2},
280 {RawStdEncoding, 2, 3},
281 {RawStdEncoding, 3, 4},
282 {RawStdEncoding, 7, 10},
288 {StdEncoding, 7, 12},
291 switch strconv.IntSize {
293 tests = append(tests, test{RawStdEncoding, (math.MaxInt-5)/8 + 1, 357913942})
294 tests = append(tests, test{RawStdEncoding, math.MaxInt/4*3 + 2, math.MaxInt})
296 tests = append(tests, test{RawStdEncoding, (math.MaxInt-5)/8 + 1, 1537228672809129302})
297 tests = append(tests, test{RawStdEncoding, math.MaxInt/4*3 + 2, math.MaxInt})
299 for _, tt := range tests {
300 if got := tt.enc.EncodedLen(tt.n); int64(got) != tt.want {
301 t.Errorf("EncodedLen(%d): got %d, want %d", tt.n, got, tt.want)
306 func TestDecodedLen(t *testing.T) {
313 {RawStdEncoding, 0, 0},
314 {RawStdEncoding, 2, 1},
315 {RawStdEncoding, 3, 2},
316 {RawStdEncoding, 4, 3},
317 {RawStdEncoding, 10, 7},
323 switch strconv.IntSize {
325 tests = append(tests, test{RawStdEncoding, math.MaxInt/6 + 1, 268435456})
326 tests = append(tests, test{RawStdEncoding, math.MaxInt, 1610612735})
328 tests = append(tests, test{RawStdEncoding, math.MaxInt/6 + 1, 1152921504606846976})
329 tests = append(tests, test{RawStdEncoding, math.MaxInt, 6917529027641081855})
331 for _, tt := range tests {
332 if got := tt.enc.DecodedLen(tt.n); int64(got) != tt.want {
333 t.Errorf("DecodedLen(%d): got %d, want %d", tt.n, got, tt.want)
338 func TestBig(t *testing.T) {
340 raw := make([]byte, n)
341 const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
342 for i := 0; i < n; i++ {
343 raw[i] = alpha[i%len(alpha)]
345 encoded := new(bytes.Buffer)
346 w := NewEncoder(StdEncoding, encoded)
347 nn, err := w.Write(raw)
348 if nn != n || err != nil {
349 t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
353 t.Fatalf("Encoder.Close() = %v want nil", err)
355 decoded, err := io.ReadAll(NewDecoder(StdEncoding, encoded))
357 t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err)
360 if !bytes.Equal(raw, decoded) {
362 for i = 0; i < len(decoded) && i < len(raw); i++ {
363 if decoded[i] != raw[i] {
367 t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
371 func TestNewLineCharacters(t *testing.T) {
372 // Each of these should decode to the string "sure", without errors.
373 const expected = "sure"
374 examples := []string{
387 for _, e := range examples {
388 buf, err := StdEncoding.DecodeString(e)
390 t.Errorf("Decode(%q) failed: %v", e, err)
393 if s := string(buf); s != expected {
394 t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
399 type nextRead struct {
400 n int // bytes to return
401 err error // error to return
404 // faultInjectReader returns data from source, rate-limited
405 // and with the errors as written to nextc.
406 type faultInjectReader struct {
408 nextc <-chan nextRead
411 func (r *faultInjectReader) Read(p []byte) (int, error) {
416 n := copy(p, r.source)
417 r.source = r.source[n:]
421 // tests that we don't ignore errors from our underlying reader
422 func TestDecoderIssue3577(t *testing.T) {
423 next := make(chan nextRead, 10)
424 wantErr := errors.New("my error")
425 next <- nextRead{5, nil}
426 next <- nextRead{10, wantErr}
427 next <- nextRead{0, wantErr}
428 d := NewDecoder(StdEncoding, &faultInjectReader{
429 source: "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", // twas brillig...
432 errc := make(chan error, 1)
434 _, err := io.ReadAll(d)
440 t.Errorf("got error %v; want %v", err, wantErr)
442 case <-time.After(5 * time.Second):
443 t.Errorf("timeout; Decoder blocked without returning an error")
447 func TestDecoderIssue4779(t *testing.T) {
448 encoded := `CP/EAT8AAAEF
449 AQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAAB
450 BAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHx
451 Y3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm
452 9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS
453 0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0
454 pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A9VSSSSUpJJJJSkkkJ+Tj
455 1kiy1jCJJDnAcCTykpKkuQ6p/jN6FgmxlNduXawwAzaGH+V6jn/R/wCt71zdn+N/qL3kVYFNYB4N
456 ji6PDVjWpKp9TSXnvTf8bFNjg3qOEa2n6VlLpj/rT/pf567DpX1i6L1hs9Py67X8mqdtg/rUWbbf
457 +gkp0kkkklKSSSSUpJJJJT//0PVUkkklKVLq3WMDpGI7KzrNjADtYNXvI/Mqr/Pd/q9W3vaxjnvM
458 NaCXE9gNSvGPrf8AWS3qmba5jjsJhoB0DAf0NDf6sevf+/lf8Hj0JJATfWT6/dV6oXU1uOLQeKKn
459 EQP+Hubtfe/+R7Mf/g7f5xcocp++Z11JMCJPgFBxOg7/AOuqDx8I/ikpkXkmSdU8mJIJA/O8EMAy
460 j+mSARB/17pKVXYWHXjsj7yIex0PadzXMO1zT5KHoNA3HT8ietoGhgjsfA+CSnvvqh/jJtqsrwOv
461 2b6NGNzXfTYexzJ+nU7/ALkf4P8Awv6P9KvTQQ4AgyDqCF85Pho3CTB7eHwXoH+LT65uZbX9X+o2
464 encodedShort := strings.ReplaceAll(encoded, "\n", "")
466 dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
467 res1, err := io.ReadAll(dec)
469 t.Errorf("ReadAll failed: %v", err)
472 dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
474 res2, err = io.ReadAll(dec)
476 t.Errorf("ReadAll failed: %v", err)
479 if !bytes.Equal(res1, res2) {
480 t.Error("Decoded results not equal")
484 func TestDecoderIssue7733(t *testing.T) {
485 s, err := StdEncoding.DecodeString("YWJjZA=====")
486 want := CorruptInputError(8)
487 if !reflect.DeepEqual(want, err) {
488 t.Errorf("Error = %v; want CorruptInputError(8)", err)
490 if string(s) != "abcd" {
491 t.Errorf("DecodeString = %q; want abcd", s)
495 func TestDecoderIssue15656(t *testing.T) {
496 _, err := StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
497 want := CorruptInputError(22)
498 if !reflect.DeepEqual(want, err) {
499 t.Errorf("Error = %v; want CorruptInputError(22)", err)
501 _, err = StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDA==")
503 t.Errorf("Error = %v; want nil", err)
505 _, err = StdEncoding.DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
507 t.Errorf("Error = %v; want nil", err)
511 func BenchmarkEncodeToString(b *testing.B) {
512 data := make([]byte, 8192)
513 b.SetBytes(int64(len(data)))
514 for i := 0; i < b.N; i++ {
515 StdEncoding.EncodeToString(data)
519 func BenchmarkDecodeString(b *testing.B) {
520 sizes := []int{2, 4, 8, 64, 8192}
521 benchFunc := func(b *testing.B, benchSize int) {
522 data := StdEncoding.EncodeToString(make([]byte, benchSize))
523 b.SetBytes(int64(len(data)))
525 for i := 0; i < b.N; i++ {
526 StdEncoding.DecodeString(data)
529 for _, size := range sizes {
530 b.Run(fmt.Sprintf("%d", size), func(b *testing.B) {
536 func BenchmarkNewEncoding(b *testing.B) {
537 b.SetBytes(int64(len(Encoding{}.decodeMap)))
538 for i := 0; i < b.N; i++ {
539 e := NewEncoding(encodeStd)
540 for _, v := range e.decodeMap {
546 func TestDecoderRaw(t *testing.T) {
548 want := []byte{0, 0, 0, 0}
551 dec1, err := RawURLEncoding.DecodeString(source)
552 if err != nil || !bytes.Equal(dec1, want) {
553 t.Errorf("RawURLEncoding.DecodeString(%q) = %x, %v, want %x, nil", source, dec1, err, want)
556 // Through reader. Used to fail.
557 r := NewDecoder(RawURLEncoding, bytes.NewReader([]byte(source)))
558 dec2, err := io.ReadAll(io.LimitReader(r, 100))
559 if err != nil || !bytes.Equal(dec2, want) {
560 t.Errorf("reading NewDecoder(RawURLEncoding, %q) = %x, %v, want %x, nil", source, dec2, err, want)
563 // Should work with padding.
564 r = NewDecoder(URLEncoding, bytes.NewReader([]byte(source+"==")))
565 dec3, err := io.ReadAll(r)
566 if err != nil || !bytes.Equal(dec3, want) {
567 t.Errorf("reading NewDecoder(URLEncoding, %q) = %x, %v, want %x, nil", source+"==", dec3, err, want)