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.
19 type testpair
struct {
20 decoded
, encoded
string
23 var pairs
= []testpair
{
25 {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
26 {"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
27 {"\x14\xfb\x9c\x03", "FPucAw=="},
35 {"fooba", "Zm9vYmE="},
36 {"foobar", "Zm9vYmFy"},
39 {"sure.", "c3VyZS4="},
43 {"leasure.", "bGVhc3VyZS4="},
44 {"easure.", "ZWFzdXJlLg=="},
45 {"asure.", "YXN1cmUu"},
46 {"sure.", "c3VyZS4="},
49 // Do nothing to a reference base64 string (leave in standard format)
50 func stdRef(ref
string) string {
54 // Convert a reference string to URL-encoding
55 func urlRef(ref
string) string {
56 ref
= strings
.ReplaceAll(ref
, "+", "-")
57 ref
= strings
.ReplaceAll(ref
, "/", "_")
61 // Convert a reference string to raw, unpadded format
62 func rawRef(ref
string) string {
63 return strings
.TrimRight(ref
, "=")
66 // Both URL and unpadding conversions
67 func rawURLRef(ref
string) string {
68 return rawRef(urlRef(ref
))
71 // A nonstandard encoding with a funny padding character, for testing
72 var funnyEncoding
= NewEncoding(encodeStd
).WithPadding(rune('@'))
74 func funnyRef(ref
string) string {
75 return strings
.ReplaceAll(ref
, "=", "@")
78 type encodingTest
struct {
79 enc
*Encoding
// Encoding to test
80 conv
func(string) string // Reference string converter
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
},
96 var bigtest
= testpair
{
97 "Twas brillig, and the slithy toves",
98 "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
101 func testEqual(t
*testing
.T
, msg
string, args
...any
) bool {
103 if args
[len(args
)-2] != args
[len(args
)-1] {
104 t
.Errorf(msg
, args
...)
110 func TestEncode(t
*testing
.T
) {
111 for _
, p
:= range pairs
{
112 for _
, tt
:= range encodingTests
{
113 got
:= tt
.enc
.EncodeToString([]byte(p
.decoded
))
114 testEqual(t
, "Encode(%q) = %q, want %q", p
.decoded
,
115 got
, tt
.conv(p
.encoded
))
120 func TestEncoder(t
*testing
.T
) {
121 for _
, p
:= range pairs
{
122 bb
:= &bytes
.Buffer
{}
123 encoder
:= NewEncoder(StdEncoding
, bb
)
124 encoder
.Write([]byte(p
.decoded
))
126 testEqual(t
, "Encode(%q) = %q, want %q", p
.decoded
, bb
.String(), p
.encoded
)
130 func TestEncoderBuffering(t
*testing
.T
) {
131 input
:= []byte(bigtest
.decoded
)
132 for bs
:= 1; bs
<= 12; bs
++ {
133 bb
:= &bytes
.Buffer
{}
134 encoder
:= NewEncoder(StdEncoding
, bb
)
135 for pos
:= 0; pos
< len(input
); pos
+= bs
{
137 if end
> len(input
) {
140 n
, err
:= encoder
.Write(input
[pos
:end
])
141 testEqual(t
, "Write(%q) gave error %v, want %v", input
[pos
:end
], err
, error(nil))
142 testEqual(t
, "Write(%q) gave length %v, want %v", input
[pos
:end
], n
, end
-pos
)
144 err
:= encoder
.Close()
145 testEqual(t
, "Close gave error %v, want %v", err
, error(nil))
146 testEqual(t
, "Encoding/%d of %q = %q, want %q", bs
, bigtest
.decoded
, bb
.String(), bigtest
.encoded
)
150 func TestDecode(t
*testing
.T
) {
151 for _
, p
:= range pairs
{
152 for _
, tt
:= range encodingTests
{
153 encoded
:= tt
.conv(p
.encoded
)
154 dbuf
:= make([]byte, tt
.enc
.DecodedLen(len(encoded
)))
155 count
, err
:= tt
.enc
.Decode(dbuf
, []byte(encoded
))
156 testEqual(t
, "Decode(%q) = error %v, want %v", encoded
, err
, error(nil))
157 testEqual(t
, "Decode(%q) = length %v, want %v", encoded
, count
, len(p
.decoded
))
158 testEqual(t
, "Decode(%q) = %q, want %q", encoded
, string(dbuf
[0:count
]), p
.decoded
)
160 dbuf
, err
= tt
.enc
.DecodeString(encoded
)
161 testEqual(t
, "DecodeString(%q) = error %v, want %v", encoded
, err
, error(nil))
162 testEqual(t
, "DecodeString(%q) = %q, want %q", encoded
, string(dbuf
), p
.decoded
)
167 func TestDecoder(t
*testing
.T
) {
168 for _
, p
:= range pairs
{
169 decoder
:= NewDecoder(StdEncoding
, strings
.NewReader(p
.encoded
))
170 dbuf
:= make([]byte, StdEncoding
.DecodedLen(len(p
.encoded
)))
171 count
, err
:= decoder
.Read(dbuf
)
172 if err
!= nil && err
!= io
.EOF
{
173 t
.Fatal("Read failed", err
)
175 testEqual(t
, "Read from %q = length %v, want %v", p
.encoded
, count
, len(p
.decoded
))
176 testEqual(t
, "Decoding of %q = %q, want %q", p
.encoded
, string(dbuf
[0:count
]), p
.decoded
)
178 _
, err
= decoder
.Read(dbuf
)
180 testEqual(t
, "Read from %q = %v, want %v", p
.encoded
, err
, io
.EOF
)
184 func TestDecoderBuffering(t
*testing
.T
) {
185 for bs
:= 1; bs
<= 12; bs
++ {
186 decoder
:= NewDecoder(StdEncoding
, strings
.NewReader(bigtest
.encoded
))
187 buf
:= make([]byte, len(bigtest
.decoded
)+12)
191 for total
= 0; total
< len(bigtest
.decoded
) && err
== nil; {
192 n
, err
= decoder
.Read(buf
[total
: total
+bs
])
195 if err
!= nil && err
!= io
.EOF
{
196 t
.Errorf("Read from %q at pos %d = %d, unexpected error %v", bigtest
.encoded
, total
, n
, err
)
198 testEqual(t
, "Decoding/%d of %q = %q, want %q", bs
, bigtest
.encoded
, string(buf
[0:total
]), bigtest
.decoded
)
202 func TestDecodeCorrupt(t
*testing
.T
) {
203 testCases
:= []struct {
205 offset
int // -1 means no corruption.
232 for _
, tc
:= range testCases
{
233 dbuf
:= make([]byte, StdEncoding
.DecodedLen(len(tc
.input
)))
234 _
, err
:= StdEncoding
.Decode(dbuf
, []byte(tc
.input
))
237 t
.Error("Decoder wrongly detected corruption in", tc
.input
)
241 switch err
:= err
.(type) {
242 case CorruptInputError
:
243 testEqual(t
, "Corruption in %q at offset %v, want %v", tc
.input
, int(err
), tc
.offset
)
245 t
.Error("Decoder failed to detect corruption in", tc
)
250 func TestDecodeBounds(t
*testing
.T
) {
252 s
:= StdEncoding
.EncodeToString(buf
[:])
254 if err
:= recover(); err
!= nil {
255 t
.Fatalf("Decode panicked unexpectedly: %v\n%s", err
, debug
.Stack())
258 n
, err
:= StdEncoding
.Decode(buf
[:], []byte(s
))
259 if n
!= len(buf
) || err
!= nil {
260 t
.Fatalf("StdEncoding.Decode = %d, %v, want %d, nil", n
, err
, len(buf
))
264 func TestEncodedLen(t
*testing
.T
) {
265 for _
, tt
:= range []struct {
270 {RawStdEncoding
, 0, 0},
271 {RawStdEncoding
, 1, 2},
272 {RawStdEncoding
, 2, 3},
273 {RawStdEncoding
, 3, 4},
274 {RawStdEncoding
, 7, 10},
280 {StdEncoding
, 7, 12},
282 if got
:= tt
.enc
.EncodedLen(tt
.n
); got
!= tt
.want
{
283 t
.Errorf("EncodedLen(%d): got %d, want %d", tt
.n
, got
, tt
.want
)
288 func TestDecodedLen(t
*testing
.T
) {
289 for _
, tt
:= range []struct {
294 {RawStdEncoding
, 0, 0},
295 {RawStdEncoding
, 2, 1},
296 {RawStdEncoding
, 3, 2},
297 {RawStdEncoding
, 4, 3},
298 {RawStdEncoding
, 10, 7},
303 if got
:= tt
.enc
.DecodedLen(tt
.n
); got
!= tt
.want
{
304 t
.Errorf("DecodedLen(%d): got %d, want %d", tt
.n
, got
, tt
.want
)
309 func TestBig(t
*testing
.T
) {
311 raw
:= make([]byte, n
)
312 const alpha
= "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
313 for i
:= 0; i
< n
; i
++ {
314 raw
[i
] = alpha
[i%len
(alpha
)]
316 encoded
:= new(bytes
.Buffer
)
317 w
:= NewEncoder(StdEncoding
, encoded
)
318 nn
, err
:= w
.Write(raw
)
319 if nn
!= n || err
!= nil {
320 t
.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn
, err
, n
)
324 t
.Fatalf("Encoder.Close() = %v want nil", err
)
326 decoded
, err
:= io
.ReadAll(NewDecoder(StdEncoding
, encoded
))
328 t
.Fatalf("io.ReadAll(NewDecoder(...)): %v", err
)
331 if !bytes
.Equal(raw
, decoded
) {
333 for i
= 0; i
< len(decoded
) && i
< len(raw
); i
++ {
334 if decoded
[i
] != raw
[i
] {
338 t
.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n
, i
)
342 func TestNewLineCharacters(t
*testing
.T
) {
343 // Each of these should decode to the string "sure", without errors.
344 const expected
= "sure"
345 examples
:= []string{
358 for _
, e
:= range examples
{
359 buf
, err
:= StdEncoding
.DecodeString(e
)
361 t
.Errorf("Decode(%q) failed: %v", e
, err
)
364 if s
:= string(buf
); s
!= expected
{
365 t
.Errorf("Decode(%q) = %q, want %q", e
, s
, expected
)
370 type nextRead
struct {
371 n
int // bytes to return
372 err error
// error to return
375 // faultInjectReader returns data from source, rate-limited
376 // and with the errors as written to nextc.
377 type faultInjectReader
struct {
379 nextc
<-chan nextRead
382 func (r
*faultInjectReader
) Read(p
[]byte) (int, error
) {
387 n
:= copy(p
, r
.source
)
388 r
.source
= r
.source
[n
:]
392 // tests that we don't ignore errors from our underlying reader
393 func TestDecoderIssue3577(t
*testing
.T
) {
394 next
:= make(chan nextRead
, 10)
395 wantErr
:= errors
.New("my error")
396 next
<- nextRead
{5, nil}
397 next
<- nextRead
{10, wantErr
}
398 next
<- nextRead
{0, wantErr
}
399 d
:= NewDecoder(StdEncoding
, &faultInjectReader
{
400 source
: "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", // twas brillig...
403 errc
:= make(chan error
, 1)
405 _
, err
:= io
.ReadAll(d
)
411 t
.Errorf("got error %v; want %v", err
, wantErr
)
413 case <-time
.After(5 * time
.Second
):
414 t
.Errorf("timeout; Decoder blocked without returning an error")
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
435 encodedShort
:= strings
.ReplaceAll(encoded
, "\n", "")
437 dec
:= NewDecoder(StdEncoding
, strings
.NewReader(encoded
))
438 res1
, err
:= io
.ReadAll(dec
)
440 t
.Errorf("ReadAll failed: %v", err
)
443 dec
= NewDecoder(StdEncoding
, strings
.NewReader(encodedShort
))
445 res2
, err
= io
.ReadAll(dec
)
447 t
.Errorf("ReadAll failed: %v", err
)
450 if !bytes
.Equal(res1
, res2
) {
451 t
.Error("Decoded results not equal")
455 func TestDecoderIssue7733(t
*testing
.T
) {
456 s
, err
:= StdEncoding
.DecodeString("YWJjZA=====")
457 want
:= CorruptInputError(8)
458 if !reflect
.DeepEqual(want
, err
) {
459 t
.Errorf("Error = %v; want CorruptInputError(8)", err
)
461 if string(s
) != "abcd" {
462 t
.Errorf("DecodeString = %q; want abcd", s
)
466 func TestDecoderIssue15656(t
*testing
.T
) {
467 _
, err
:= StdEncoding
.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
468 want
:= CorruptInputError(22)
469 if !reflect
.DeepEqual(want
, err
) {
470 t
.Errorf("Error = %v; want CorruptInputError(22)", err
)
472 _
, err
= StdEncoding
.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDA==")
474 t
.Errorf("Error = %v; want nil", err
)
476 _
, err
= StdEncoding
.DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
478 t
.Errorf("Error = %v; want nil", err
)
482 func BenchmarkEncodeToString(b
*testing
.B
) {
483 data
:= make([]byte, 8192)
484 b
.SetBytes(int64(len(data
)))
485 for i
:= 0; i
< b
.N
; i
++ {
486 StdEncoding
.EncodeToString(data
)
490 func BenchmarkDecodeString(b
*testing
.B
) {
491 sizes
:= []int{2, 4, 8, 64, 8192}
492 benchFunc
:= func(b
*testing
.B
, benchSize
int) {
493 data
:= StdEncoding
.EncodeToString(make([]byte, benchSize
))
494 b
.SetBytes(int64(len(data
)))
496 for i
:= 0; i
< b
.N
; i
++ {
497 StdEncoding
.DecodeString(data
)
500 for _
, size
:= range sizes
{
501 b
.Run(fmt
.Sprintf("%d", size
), func(b
*testing
.B
) {
507 func TestDecoderRaw(t
*testing
.T
) {
509 want
:= []byte{0, 0, 0, 0}
512 dec1
, err
:= RawURLEncoding
.DecodeString(source
)
513 if err
!= nil ||
!bytes
.Equal(dec1
, want
) {
514 t
.Errorf("RawURLEncoding.DecodeString(%q) = %x, %v, want %x, nil", source
, dec1
, err
, want
)
517 // Through reader. Used to fail.
518 r
:= NewDecoder(RawURLEncoding
, bytes
.NewReader([]byte(source
)))
519 dec2
, err
:= io
.ReadAll(io
.LimitReader(r
, 100))
520 if err
!= nil ||
!bytes
.Equal(dec2
, want
) {
521 t
.Errorf("reading NewDecoder(RawURLEncoding, %q) = %x, %v, want %x, nil", source
, dec2
, err
, want
)
524 // Should work with padding.
525 r
= NewDecoder(URLEncoding
, bytes
.NewReader([]byte(source
+"==")))
526 dec3
, err
:= io
.ReadAll(r
)
527 if err
!= nil ||
!bytes
.Equal(dec3
, want
) {
528 t
.Errorf("reading NewDecoder(URLEncoding, %q) = %x, %v, want %x, nil", source
+"==", dec3
, err
, want
)