Source file src/encoding/base64/base64_test.go

     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  	"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  	// RFC 3548 examples
    27  	{"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
    28  	{"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
    29  	{"\x14\xfb\x9c\x03", "FPucAw=="},
    30  
    31  	// RFC 4648 examples
    32  	{"", ""},
    33  	{"f", "Zg=="},
    34  	{"fo", "Zm8="},
    35  	{"foo", "Zm9v"},
    36  	{"foob", "Zm9vYg=="},
    37  	{"fooba", "Zm9vYmE="},
    38  	{"foobar", "Zm9vYmFy"},
    39  
    40  	// Wikipedia examples
    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  // Do nothing to a reference base64 string (leave in standard format)
    52  func stdRef(ref string) string {
    53  	return ref
    54  }
    55  
    56  // Convert a reference string to URL-encoding
    57  func urlRef(ref string) string {
    58  	ref = strings.ReplaceAll(ref, "+", "-")
    59  	ref = strings.ReplaceAll(ref, "/", "_")
    60  	return ref
    61  }
    62  
    63  // Convert a reference string to raw, unpadded format
    64  func rawRef(ref string) string {
    65  	return strings.TrimRight(ref, "=")
    66  }
    67  
    68  // Both URL and unpadding conversions
    69  func rawURLRef(ref string) string {
    70  	return rawRef(urlRef(ref))
    71  }
    72  
    73  const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    74  
    75  // A nonstandard encoding with a funny padding character, for testing
    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           // Encoding to test
    84  	conv func(string) string // Reference string converter
    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 // -1 means no corruption.
   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  	// check overflow
   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  	// check overflow
   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  	// Each of these should decode to the string "sure", without errors.
   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   // bytes to return
   410  	err error // error to return
   411  }
   412  
   413  // faultInjectReader returns data from source, rate-limited
   414  // and with the errors as written to nextc.
   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  // tests that we don't ignore errors from our underlying reader
   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==", // twas brillig...
   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  	// Direct.
   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  	// Through reader. Used to fail.
   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  	// Should work with padding.
   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