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