github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/proto/protowire/decode_test.go (about)

     1  package protowire
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"math"
    10  	"reflect"
    11  	"strconv"
    12  	"testing"
    13  )
    14  
    15  type (
    16  	testOps struct {
    17  		// appendOps is a sequence of append operations, each appending to
    18  		// the output of the previous append operation.
    19  		appendOps []appendOp
    20  
    21  		// wantRaw (if not nil) is the bytes that the appendOps should produce.
    22  		wantRaw []byte
    23  
    24  		// consumeOps are a sequence of consume operations, each consuming the
    25  		// remaining output after the previous consume operation.
    26  		// The first consume operation starts with the output of appendOps.
    27  		consumeOps []consumeOp
    28  	}
    29  
    30  	appendOp = interface{}
    31  
    32  	appendVarint struct {
    33  		InVal uint64
    34  	}
    35  	appendFixed32 struct {
    36  		InVal uint32
    37  	}
    38  	appendFixed64 struct {
    39  		InVal uint64
    40  	}
    41  	encodeBool struct {
    42  		InVal bool
    43  	}
    44  	encodeByte struct {
    45  		InVal byte
    46  	}
    47  	encodeEnum struct {
    48  		InVal int32
    49  	}
    50  	encodeInt32 struct {
    51  		InVal int32
    52  	}
    53  	encodeSint32 struct {
    54  		InVal int32
    55  	}
    56  	encodeUint32 struct {
    57  		InVal uint32
    58  	}
    59  	encodeInt64 struct {
    60  		InVal int64
    61  	}
    62  	encodeSint64 struct {
    63  		InVal int64
    64  	}
    65  	encodeUint64 struct {
    66  		InVal uint64
    67  	}
    68  	encodeFixed32 struct {
    69  		InVal uint32
    70  	}
    71  	encodeSFixed32 struct {
    72  		InVal int32
    73  	}
    74  	encodeFloat32 struct {
    75  		InVal float32
    76  	}
    77  	encodeFixed64 struct {
    78  		InVal uint64
    79  	}
    80  	encodeSFixed64 struct {
    81  		InVal int64
    82  	}
    83  	encodeDouble struct {
    84  		InVal float64
    85  	}
    86  	encodeString struct {
    87  		InVal string
    88  	}
    89  	encodeBytes struct {
    90  		intVal []byte
    91  	}
    92  
    93  	appendRaw []byte
    94  
    95  	consumeOp     = interface{}
    96  	consumeVarint struct {
    97  		wantVal uint64
    98  		wantCnt int
    99  		wantErr error
   100  	}
   101  	consumeFixed32 struct {
   102  		wantVal uint32
   103  		wantCnt int
   104  		wantErr error
   105  	}
   106  	consumeFixed64 struct {
   107  		wantVal uint64
   108  		wantCnt int
   109  		wantErr error
   110  	}
   111  	consumeBytes struct {
   112  		wantVal []byte
   113  		wantCnt int
   114  		wantErr error
   115  	}
   116  	decodeBool struct {
   117  		wantVal bool
   118  		wantCnt int
   119  		wantErr error
   120  	}
   121  	decodeByte struct {
   122  		wantVal byte
   123  		wantCnt int
   124  		wantErr error
   125  	}
   126  	decodeEnum struct {
   127  		wantVal int
   128  		wantCnt int
   129  		wantErr error
   130  	}
   131  	decodeInt32 struct {
   132  		wantVal int32
   133  		wantCnt int
   134  		wantErr error
   135  	}
   136  	decodeSint32 struct {
   137  		wantVal int32
   138  		wantCnt int
   139  		wantErr error
   140  	}
   141  	decodeUint32 struct {
   142  		wantVal uint32
   143  		wantCnt int
   144  		wantErr error
   145  	}
   146  	decodeInt64 struct {
   147  		wantVal int64
   148  		wantCnt int
   149  		wantErr error
   150  	}
   151  	decodeSint64 struct {
   152  		wantVal int64
   153  		wantCnt int
   154  		wantErr error
   155  	}
   156  	decodeUint64 struct {
   157  		wantVal uint64
   158  		wantCnt int
   159  		wantErr error
   160  	}
   161  	decodeFixed32 struct {
   162  		wantVal uint32
   163  		wantCnt int
   164  		wantErr error
   165  	}
   166  	decodeSfixed32 struct {
   167  		wantVal int32
   168  		wantCnt int
   169  		wantErr error
   170  	}
   171  	decodeFloat32 struct {
   172  		wantVal float32
   173  		wantCnt int
   174  		wantErr error
   175  	}
   176  	decodeFixed64 struct {
   177  		wantVal uint64
   178  		wantCnt int
   179  		wantErr error
   180  	}
   181  	decodeSfixed64 struct {
   182  		wantVal int64
   183  		wantCnt int
   184  		wantErr error
   185  	}
   186  	decodeDouble struct {
   187  		wantVal float64
   188  		wantCnt int
   189  		wantErr error
   190  	}
   191  	decodeString struct {
   192  		wantVal string
   193  		wantCnt int
   194  		wantErr error
   195  	}
   196  	decodeBytes struct {
   197  		wantVal []byte
   198  		wantCnt int
   199  		wantErr error
   200  	}
   201  	ops []interface{}
   202  )
   203  
   204  // dhex decodes a hex-string and returns the bytes and panics if s is invalid.
   205  func dhex(s string) []byte {
   206  	b, err := hex.DecodeString(s)
   207  	if err != nil {
   208  		panic(err)
   209  	}
   210  	return b
   211  }
   212  
   213  var (
   214  	errFieldNumber = errors.New("invalid field number")
   215  	errOverflow    = errors.New("variable length integer overflow")
   216  	errReserved    = errors.New("cannot parse reserved wire type")
   217  	errEndGroup    = errors.New("mismatching end group marker")
   218  	errParse       = errors.New("parse error")
   219  )
   220  
   221  // ParseError converts an error code into an error value.
   222  // This returns nil if n is a non-negative number.
   223  func ParseError(n int) error {
   224  	if n >= 0 {
   225  		return nil
   226  	}
   227  	switch n {
   228  	case errCodeTruncated:
   229  		return io.ErrUnexpectedEOF
   230  	case errCodeFieldNumber:
   231  		return errFieldNumber
   232  	case errCodeOverflow:
   233  		return errOverflow
   234  	case errCodeReserved:
   235  		return errReserved
   236  	case errCodeEndGroup:
   237  		return errEndGroup
   238  	default:
   239  		return errParse
   240  	}
   241  }
   242  
   243  var OpType2Name = map[interface{}]string{
   244  	reflect.TypeOf(appendVarint{}):   "Varint_en",
   245  	reflect.TypeOf(appendFixed32{}):  "Fixed32_en",
   246  	reflect.TypeOf(appendFixed64{}):  "Fixed64_en",
   247  	reflect.TypeOf(encodeBool{}):     "Bool_en",
   248  	reflect.TypeOf(encodeByte{}):     "Byte_en",
   249  	reflect.TypeOf(encodeEnum{}):     "Enum_en",
   250  	reflect.TypeOf(encodeInt32{}):    "Int32_en",
   251  	reflect.TypeOf(encodeSint32{}):   "Sint32_en",
   252  	reflect.TypeOf(encodeUint32{}):   "Uint32_en",
   253  	reflect.TypeOf(encodeInt64{}):    "Int64_en",
   254  	reflect.TypeOf(encodeSint64{}):   "Sint64_en",
   255  	reflect.TypeOf(encodeUint64{}):   "Uint64_en",
   256  	reflect.TypeOf(encodeSFixed32{}): "Sfixed32_en",
   257  	reflect.TypeOf(encodeFixed32{}):  "EncodeFixed32_en",
   258  	reflect.TypeOf(encodeSFixed64{}): "Sfixed64_en",
   259  	reflect.TypeOf(encodeFixed64{}):  "EncodeFixed64_en",
   260  	reflect.TypeOf(encodeDouble{}):   "Double_en",
   261  	reflect.TypeOf(encodeString{}):   "String_en",
   262  	reflect.TypeOf(encodeBytes{}):    "Bytes_en",
   263  }
   264  
   265  func TestVarint(t *testing.T) {
   266  	runTests(t, []testOps{
   267  		{
   268  			// Test varints at various boundaries where the length changes.
   269  			appendOps:  ops{appendVarint{InVal: 0x0}},
   270  			wantRaw:    dhex("00"),
   271  			consumeOps: ops{consumeVarint{wantVal: 0, wantCnt: 1}},
   272  		}, {
   273  			appendOps:  ops{appendVarint{InVal: 0x1}},
   274  			wantRaw:    dhex("01"),
   275  			consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
   276  		}, {
   277  			appendOps:  ops{appendVarint{InVal: 0x7f}},
   278  			wantRaw:    dhex("7f"),
   279  			consumeOps: ops{consumeVarint{wantVal: 0x7f, wantCnt: 1}},
   280  		}, {
   281  			appendOps:  ops{appendVarint{InVal: 0x7f + 1}},
   282  			wantRaw:    dhex("8001"),
   283  			consumeOps: ops{consumeVarint{wantVal: 0x7f + 1, wantCnt: 2}},
   284  		}, {
   285  			appendOps:  ops{appendVarint{InVal: 0x3fff}},
   286  			wantRaw:    dhex("ff7f"),
   287  			consumeOps: ops{consumeVarint{wantVal: 0x3fff, wantCnt: 2}},
   288  		}, {
   289  			appendOps:  ops{appendVarint{InVal: 0x3fff + 1}},
   290  			wantRaw:    dhex("808001"),
   291  			consumeOps: ops{consumeVarint{wantVal: 0x3fff + 1, wantCnt: 3}},
   292  		}, {
   293  			appendOps:  ops{appendVarint{InVal: 0x1fffff}},
   294  			wantRaw:    dhex("ffff7f"),
   295  			consumeOps: ops{consumeVarint{wantVal: 0x1fffff, wantCnt: 3}},
   296  		}, {
   297  			appendOps:  ops{appendVarint{InVal: 0x1fffff + 1}},
   298  			wantRaw:    dhex("80808001"),
   299  			consumeOps: ops{consumeVarint{wantVal: 0x1fffff + 1, wantCnt: 4}},
   300  		}, {
   301  			appendOps:  ops{appendVarint{InVal: 0xfffffff}},
   302  			wantRaw:    dhex("ffffff7f"),
   303  			consumeOps: ops{consumeVarint{wantVal: 0xfffffff, wantCnt: 4}},
   304  		}, {
   305  			appendOps:  ops{appendVarint{InVal: 0xfffffff + 1}},
   306  			wantRaw:    dhex("8080808001"),
   307  			consumeOps: ops{consumeVarint{wantVal: 0xfffffff + 1, wantCnt: 5}},
   308  		}, {
   309  			appendOps:  ops{appendVarint{InVal: 0x7ffffffff}},
   310  			wantRaw:    dhex("ffffffff7f"),
   311  			consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff, wantCnt: 5}},
   312  		}, {
   313  			appendOps:  ops{appendVarint{InVal: 0x7ffffffff + 1}},
   314  			wantRaw:    dhex("808080808001"),
   315  			consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff + 1, wantCnt: 6}},
   316  		}, {
   317  			appendOps:  ops{appendVarint{InVal: 0x3ffffffffff}},
   318  			wantRaw:    dhex("ffffffffff7f"),
   319  			consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff, wantCnt: 6}},
   320  		}, {
   321  			appendOps:  ops{appendVarint{InVal: 0x3ffffffffff + 1}},
   322  			wantRaw:    dhex("80808080808001"),
   323  			consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff + 1, wantCnt: 7}},
   324  		}, {
   325  			appendOps:  ops{appendVarint{InVal: 0x1ffffffffffff}},
   326  			wantRaw:    dhex("ffffffffffff7f"),
   327  			consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff, wantCnt: 7}},
   328  		}, {
   329  			appendOps:  ops{appendVarint{InVal: 0x1ffffffffffff + 1}},
   330  			wantRaw:    dhex("8080808080808001"),
   331  			consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff + 1, wantCnt: 8}},
   332  		}, {
   333  			appendOps:  ops{appendVarint{InVal: 0xffffffffffffff}},
   334  			wantRaw:    dhex("ffffffffffffff7f"),
   335  			consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff, wantCnt: 8}},
   336  		}, {
   337  			appendOps:  ops{appendVarint{InVal: 0xffffffffffffff + 1}},
   338  			wantRaw:    dhex("808080808080808001"),
   339  			consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff + 1, wantCnt: 9}},
   340  		}, {
   341  			appendOps:  ops{appendVarint{InVal: 0x7fffffffffffffff}},
   342  			wantRaw:    dhex("ffffffffffffffff7f"),
   343  			consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff, wantCnt: 9}},
   344  		}, {
   345  			appendOps:  ops{appendVarint{InVal: 0x7fffffffffffffff + 1}},
   346  			wantRaw:    dhex("80808080808080808001"),
   347  			consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff + 1, wantCnt: 10}},
   348  		}, {
   349  			appendOps:  ops{appendVarint{InVal: math.MaxUint64}},
   350  			wantRaw:    dhex("ffffffffffffffffff01"),
   351  			consumeOps: ops{consumeVarint{wantVal: math.MaxUint64, wantCnt: 10}},
   352  		},
   353  	})
   354  }
   355  
   356  func TestFixed32(t *testing.T) {
   357  	runTests(t, []testOps{{
   358  		appendOps:  ops{appendFixed32{0}},
   359  		wantRaw:    dhex("00000000"),
   360  		consumeOps: ops{consumeFixed32{wantVal: 0, wantCnt: 4}},
   361  	}, {
   362  		appendOps:  ops{appendFixed32{math.MaxUint32}},
   363  		wantRaw:    dhex("ffffffff"),
   364  		consumeOps: ops{consumeFixed32{wantVal: math.MaxUint32, wantCnt: 4}},
   365  	}, {
   366  		appendOps:  ops{appendFixed32{0xf0e1d2c3}},
   367  		wantRaw:    dhex("c3d2e1f0"),
   368  		consumeOps: ops{consumeFixed32{wantVal: 0xf0e1d2c3, wantCnt: 4}},
   369  	}})
   370  }
   371  
   372  func TestFixed64(t *testing.T) {
   373  	runTests(t, []testOps{{
   374  		appendOps:  ops{appendFixed64{0}},
   375  		wantRaw:    dhex("0000000000000000"),
   376  		consumeOps: ops{consumeFixed64{wantVal: 0, wantCnt: 8}},
   377  	}, {
   378  		appendOps:  ops{appendFixed64{math.MaxUint64}},
   379  		wantRaw:    dhex("ffffffffffffffff"),
   380  		consumeOps: ops{consumeFixed64{wantVal: math.MaxUint64, wantCnt: 8}},
   381  	}, {
   382  		appendOps:  ops{appendFixed64{0xf0e1d2c3b4a59687}},
   383  		wantRaw:    dhex("8796a5b4c3d2e1f0"),
   384  		consumeOps: ops{consumeFixed64{wantVal: 0xf0e1d2c3b4a59687, wantCnt: 8}},
   385  	}})
   386  }
   387  
   388  func TestBool(t *testing.T) {
   389  	runTests(t, []testOps{{
   390  		appendOps:  ops{encodeBool{true}},
   391  		wantRaw:    dhex("01"),
   392  		consumeOps: ops{decodeBool{wantVal: true, wantCnt: 1}},
   393  	}, {
   394  		appendOps:  ops{encodeBool{false}},
   395  		wantRaw:    dhex("00"),
   396  		consumeOps: ops{decodeBool{wantVal: false, wantCnt: 1}},
   397  	}})
   398  }
   399  
   400  func TestByte(t *testing.T) {
   401  	runTests(t, []testOps{{
   402  		appendOps:  ops{encodeByte{0x12}},
   403  		wantRaw:    []byte{0x12},
   404  		consumeOps: ops{decodeByte{wantVal: 0x12, wantCnt: 1}},
   405  	}, {
   406  		appendOps:  ops{encodeByte{0xff}},
   407  		wantRaw:    []byte{0xff},
   408  		consumeOps: ops{decodeByte{wantVal: 0xff, wantCnt: 1}},
   409  	}})
   410  }
   411  
   412  func TestInt32(t *testing.T) {
   413  	runTests(t, []testOps{
   414  		{
   415  			appendOps:  ops{encodeInt32{26984}},
   416  			wantRaw:    dhex("e8d201"),
   417  			consumeOps: ops{decodeInt32{wantVal: 26984, wantCnt: 3}},
   418  		},
   419  		{
   420  			appendOps:  ops{encodeInt32{123}},
   421  			wantRaw:    []byte{0x7b},
   422  			consumeOps: ops{decodeInt32{wantVal: 123, wantCnt: 1}},
   423  		},
   424  		{
   425  			appendOps:  ops{encodeInt32{2147483647}},
   426  			wantRaw:    dhex("ffffffff07"),
   427  			consumeOps: ops{decodeInt32{wantVal: 2147483647, wantCnt: 5}},
   428  		},
   429  	})
   430  }
   431  
   432  func TestSint32(t *testing.T) {
   433  	runTests(t, []testOps{
   434  		{
   435  			appendOps:  ops{encodeSint32{26984}},
   436  			wantRaw:    dhex("d0a503"),
   437  			consumeOps: ops{decodeSint32{wantVal: 26984, wantCnt: 3}},
   438  		},
   439  		{
   440  			appendOps:  ops{encodeSint32{-1}},
   441  			wantRaw:    []byte{0x1},
   442  			consumeOps: ops{decodeSint32{wantVal: -1, wantCnt: 1}},
   443  		},
   444  		{
   445  			appendOps:  ops{encodeSint32{-200}},
   446  			wantRaw:    dhex("8f03"),
   447  			consumeOps: ops{decodeSint32{wantVal: -200, wantCnt: 2}},
   448  		},
   449  	})
   450  }
   451  
   452  func TestUint32(t *testing.T) {
   453  	runTests(t, []testOps{
   454  		{
   455  			appendOps:  ops{encodeUint32{26984}},
   456  			wantRaw:    dhex("e8d201"),
   457  			consumeOps: ops{decodeUint32{wantVal: 26984, wantCnt: 3}},
   458  		},
   459  		{
   460  			appendOps:  ops{encodeUint32{10000}},
   461  			wantRaw:    dhex("904e"),
   462  			consumeOps: ops{decodeUint32{wantVal: 10000, wantCnt: 2}},
   463  		},
   464  		{
   465  			appendOps:  ops{encodeUint32{200}},
   466  			wantRaw:    dhex("c801"),
   467  			consumeOps: ops{decodeUint32{wantVal: 200, wantCnt: 2}},
   468  		},
   469  	})
   470  }
   471  
   472  func TestInt64(t *testing.T) {
   473  	runTests(t, []testOps{
   474  		{
   475  			appendOps:  ops{encodeInt64{26984}},
   476  			wantRaw:    dhex("e8d201"),
   477  			consumeOps: ops{decodeInt64{wantVal: 26984, wantCnt: 3}},
   478  		},
   479  		{
   480  			appendOps:  ops{encodeInt64{123}},
   481  			wantRaw:    []byte{0x7b},
   482  			consumeOps: ops{decodeInt64{wantVal: 123, wantCnt: 1}},
   483  		},
   484  		{
   485  			appendOps:  ops{encodeInt64{2147483647}},
   486  			wantRaw:    dhex("ffffffff07"),
   487  			consumeOps: ops{decodeInt64{wantVal: 2147483647, wantCnt: 5}},
   488  		},
   489  	})
   490  }
   491  
   492  func TestSint64(t *testing.T) {
   493  	runTests(t, []testOps{
   494  		{
   495  			appendOps:  ops{encodeSint64{26984}},
   496  			wantRaw:    dhex("d0a503"),
   497  			consumeOps: ops{decodeSint64{wantVal: 26984, wantCnt: 3}},
   498  		},
   499  		{
   500  			appendOps:  ops{encodeSint64{-1}},
   501  			wantRaw:    []byte{0x1},
   502  			consumeOps: ops{decodeSint64{wantVal: -1, wantCnt: 1}},
   503  		},
   504  		{
   505  			appendOps:  ops{encodeSint64{-200}},
   506  			wantRaw:    dhex("8f03"),
   507  			consumeOps: ops{decodeSint64{wantVal: -200, wantCnt: 2}},
   508  		},
   509  	})
   510  }
   511  
   512  func TestUint64(t *testing.T) {
   513  	runTests(t, []testOps{
   514  		{
   515  			appendOps:  ops{encodeUint64{26984}},
   516  			wantRaw:    dhex("e8d201"),
   517  			consumeOps: ops{decodeUint64{wantVal: 26984, wantCnt: 3}},
   518  		},
   519  		{
   520  			appendOps:  ops{encodeUint64{10000}},
   521  			wantRaw:    dhex("904e"),
   522  			consumeOps: ops{decodeUint64{wantVal: 10000, wantCnt: 2}},
   523  		},
   524  		{
   525  			appendOps:  ops{encodeUint64{200}},
   526  			wantRaw:    dhex("c801"),
   527  			consumeOps: ops{decodeUint64{wantVal: 200, wantCnt: 2}},
   528  		},
   529  	})
   530  }
   531  
   532  func TestSfixed32(t *testing.T) {
   533  	runTests(t, []testOps{{
   534  		appendOps:  ops{encodeSFixed32{0}},
   535  		wantRaw:    dhex("00000000"),
   536  		consumeOps: ops{decodeSfixed32{wantVal: 0, wantCnt: 4}},
   537  	}, {
   538  		appendOps:  ops{encodeSFixed32{math.MaxInt32}},
   539  		wantRaw:    dhex("ffffff7f"),
   540  		consumeOps: ops{decodeSfixed32{wantVal: math.MaxInt32, wantCnt: 4}},
   541  	}, {
   542  		appendOps:  ops{encodeSFixed32{1}},
   543  		wantRaw:    dhex("01000000"),
   544  		consumeOps: ops{decodeSfixed32{wantVal: 1, wantCnt: 4}},
   545  	}})
   546  }
   547  
   548  func TestFloat32(t *testing.T) {
   549  	runTests(t, []testOps{
   550  		{
   551  			appendOps:  ops{encodeFloat32{0.32}},
   552  			wantRaw:    dhex("0ad7a33e"),
   553  			consumeOps: ops{decodeFloat32{wantVal: 0.32, wantCnt: 4}},
   554  		},
   555  		{
   556  			appendOps:  ops{encodeFloat32{1298.222}},
   557  			wantRaw:    dhex("1b47a244"),
   558  			consumeOps: ops{decodeFloat32{wantVal: 1298.222, wantCnt: 4}},
   559  		},
   560  		{
   561  			appendOps:  ops{encodeFloat32{9898989.11}},
   562  			wantRaw:    dhex("ed0b174b"),
   563  			consumeOps: ops{decodeFloat32{wantVal: 9898989.11, wantCnt: 4}},
   564  		},
   565  	})
   566  }
   567  
   568  func TestSfixed64(t *testing.T) {
   569  	runTests(t, []testOps{
   570  		{
   571  			appendOps:  ops{encodeSFixed64{0}},
   572  			wantRaw:    dhex("0000000000000000"),
   573  			consumeOps: ops{decodeSfixed64{wantVal: 0, wantCnt: 8}},
   574  		},
   575  		{
   576  			appendOps:  ops{appendFixed64{math.MaxUint64}},
   577  			wantRaw:    dhex("ffffffffffffffff"),
   578  			consumeOps: ops{consumeFixed64{wantVal: math.MaxUint64, wantCnt: 8}},
   579  		}, {
   580  			appendOps:  ops{appendFixed64{0xf0e1d2c3b4a59687}},
   581  			wantRaw:    dhex("8796a5b4c3d2e1f0"),
   582  			consumeOps: ops{consumeFixed64{wantVal: 0xf0e1d2c3b4a59687, wantCnt: 8}},
   583  		},
   584  	})
   585  }
   586  
   587  func TestDouble(t *testing.T) {
   588  	runTests(t, []testOps{
   589  		{
   590  			appendOps:  ops{encodeDouble{0.32}},
   591  			wantRaw:    dhex("7b14ae47e17ad43f"),
   592  			consumeOps: ops{decodeDouble{wantVal: 0.32, wantCnt: 8}},
   593  		},
   594  		{
   595  			appendOps:  ops{encodeDouble{1298.222}},
   596  			wantRaw:    dhex("d9cef753e3489440"),
   597  			consumeOps: ops{decodeDouble{wantVal: 1298.222, wantCnt: 8}},
   598  		},
   599  		{
   600  			appendOps:  ops{encodeDouble{9898989.11}},
   601  			wantRaw:    dhex("b81e85a37de16241"),
   602  			consumeOps: ops{decodeDouble{wantVal: 9898989.11, wantCnt: 8}},
   603  		},
   604  	})
   605  }
   606  
   607  func TestString(t *testing.T) {
   608  	runTests(t, []testOps{
   609  		{
   610  			appendOps:  ops{encodeString{"aabbcc"}},
   611  			wantRaw:    dhex("06616162626363"),
   612  			consumeOps: ops{decodeString{wantVal: "aabbcc", wantCnt: 7}},
   613  		},
   614  		{
   615  			appendOps:  ops{encodeString{"dau9bkn;jasdf"}},
   616  			wantRaw:    dhex("0d64617539626b6e3b6a61736466"),
   617  			consumeOps: ops{decodeString{wantVal: "dau9bkn;jasdf", wantCnt: 14}},
   618  		},
   619  	})
   620  }
   621  
   622  func TestBytes(t *testing.T) {
   623  	runTests(t, []testOps{
   624  		{
   625  			appendOps:  ops{encodeBytes{[]byte{0x61, 0x61, 0x62, 0x62, 0x63, 0x63}}},
   626  			wantRaw:    dhex("06616162626363"),
   627  			consumeOps: ops{decodeBytes{wantVal: []byte{0x61, 0x61, 0x62, 0x62, 0x63, 0x63}, wantCnt: 7}},
   628  		},
   629  		{
   630  			appendOps:  ops{encodeBytes{[]byte{0x64, 0x61, 0x75, 0x39, 0x62, 0x6b, 0x6e, 0x3b, 0x6a, 0x61, 0x73, 0x64, 0x66}}},
   631  			wantRaw:    dhex("0d64617539626b6e3b6a61736466"),
   632  			consumeOps: ops{decodeBytes{wantVal: []byte{0x64, 0x61, 0x75, 0x39, 0x62, 0x6b, 0x6e, 0x3b, 0x6a, 0x61, 0x73, 0x64, 0x66}, wantCnt: 14}},
   633  		},
   634  	})
   635  }
   636  
   637  func runTests(t *testing.T, tests []testOps) {
   638  	for _, tt := range tests {
   639  		t.Run("", func(t *testing.T) {
   640  			var b []byte
   641  			for _, op := range tt.appendOps {
   642  				b0 := b
   643  				switch op := op.(type) {
   644  				case appendVarint:
   645  					b = AppendVarint(b, op.InVal)
   646  				case appendFixed32:
   647  					b = AppendFixed32(b, op.InVal)
   648  				case appendFixed64:
   649  					b = AppendFixed64(b, op.InVal)
   650  				case encodeBool:
   651  					b = BinaryEncoder{}.EncodeBool(b, op.InVal)
   652  				case encodeByte:
   653  					b = BinaryEncoder{}.EncodeByte(b, op.InVal)
   654  				case encodeEnum:
   655  					b = BinaryEncoder{}.EncodeEnum(b, op.InVal)
   656  				case encodeInt32:
   657  					b = BinaryEncoder{}.EncodeInt32(b, op.InVal)
   658  				case encodeSint32:
   659  					b = BinaryEncoder{}.EncodeSint32(b, op.InVal)
   660  				case encodeUint32:
   661  					b = BinaryEncoder{}.EncodeUint32(b, op.InVal)
   662  				case encodeInt64:
   663  					b = BinaryEncoder{}.EncodeInt64(b, op.InVal)
   664  				case encodeSint64:
   665  					b = BinaryEncoder{}.EncodeSint64(b, op.InVal)
   666  				case encodeUint64:
   667  					b = BinaryEncoder{}.EncodeUint64(b, op.InVal)
   668  				case encodeSFixed32:
   669  					b = BinaryEncoder{}.EncodeSfixed32(b, op.InVal)
   670  				case encodeFixed32:
   671  					b = BinaryEncoder{}.EncodeFixed32(b, op.InVal)
   672  				case encodeSFixed64:
   673  					b = BinaryEncoder{}.EncodeSfixed64(b, op.InVal)
   674  				case encodeFixed64:
   675  					b = BinaryEncoder{}.EncodeFixed64(b, op.InVal)
   676  				case encodeFloat32:
   677  					b = BinaryEncoder{}.EncodeFloat32(b, op.InVal)
   678  				case encodeDouble:
   679  					b = BinaryEncoder{}.EncodeDouble(b, op.InVal)
   680  				case encodeString:
   681  					b = BinaryEncoder{}.EncodeString(b, op.InVal)
   682  				case encodeBytes:
   683  					b = BinaryEncoder{}.EncodeBytes(b, op.intVal)
   684  				case appendRaw:
   685  					b = append(b, op...)
   686  				}
   687  
   688  				check := func(label string, want int) {
   689  					t.Helper()
   690  					if got := len(b) - len(b0); got != want {
   691  						t.Errorf("len(Append%v) and Size%v mismatch: got %v, want %v", label, label, got, want)
   692  					}
   693  				}
   694  
   695  				switch op := op.(type) {
   696  				case appendVarint, encodeEnum, encodeInt32, encodeUint32, encodeInt64, encodeUint64:
   697  					data_str := fmt.Sprint(reflect.ValueOf(op).Field(0).Interface())
   698  					data_conv, _ := strconv.ParseUint(data_str, 10, 64)
   699  					check(OpType2Name[op], SizeVarint(data_conv))
   700  				case appendFixed32, encodeFixed32, encodeSFixed32, encodeFloat32:
   701  					check(OpType2Name[op], SizeFixed32())
   702  				case appendFixed64, encodeFixed64, encodeSFixed64:
   703  					check(OpType2Name[op], SizeFixed64())
   704  				case encodeBool, encodeByte:
   705  					check(OpType2Name[op], 1)
   706  				case encodeSint32, encodeSint64:
   707  					data_str := fmt.Sprint(reflect.ValueOf(op).Field(0).Interface())
   708  					data_conv, _ := strconv.ParseInt(data_str, 10, 64)
   709  					check(OpType2Name[op], SizeVarint(EncodeZigZag(data_conv)))
   710  				}
   711  			}
   712  
   713  			if tt.wantRaw != nil && !bytes.Equal(b, tt.wantRaw) {
   714  				t.Errorf("raw output mismatch:\ngot  %x\nwant %x", b, tt.wantRaw)
   715  			}
   716  
   717  			for _, op := range tt.consumeOps {
   718  				check := func(label string, gotCnt, wantCnt int, wantErr error) {
   719  					t.Helper()
   720  					gotErr := ParseError(gotCnt)
   721  					if gotCnt < 0 {
   722  						gotCnt = 0
   723  					}
   724  					if gotCnt != wantCnt {
   725  						t.Errorf("Consume%v(): consumed %d bytes, want %d bytes consumed", label, gotCnt, wantCnt)
   726  					}
   727  					if gotErr != wantErr {
   728  						t.Errorf("Consume%v(): got %v error, want %v error", label, gotErr, wantErr)
   729  					}
   730  					b = b[gotCnt:]
   731  				}
   732  				switch op := op.(type) {
   733  				case consumeVarint:
   734  					gotVal, n := ConsumeVarint(b)
   735  					if gotVal != op.wantVal {
   736  						t.Errorf("ConsumeVarint() = %d, want %d", gotVal, op.wantVal)
   737  					}
   738  					check("Varint_de", n, op.wantCnt, op.wantErr)
   739  				case consumeFixed32:
   740  					gotVal, n := ConsumeFixed32(b)
   741  					if gotVal != op.wantVal {
   742  						t.Errorf("ConsumeFixed32() = %d, want %d", gotVal, op.wantVal)
   743  					}
   744  					check("Fixed32_de", n, op.wantCnt, op.wantErr)
   745  				case consumeFixed64:
   746  					gotVal, n := ConsumeFixed64(b)
   747  					if gotVal != op.wantVal {
   748  						t.Errorf("ConsumeFixed64() = %d, want %d", gotVal, op.wantVal)
   749  					}
   750  					check("Fixed64_de", n, op.wantCnt, op.wantErr)
   751  				case consumeBytes:
   752  					gotVal, _, n := ConsumeBytes(b)
   753  					if !bytes.Equal(gotVal, op.wantVal) {
   754  						t.Errorf("ConsumeBytes() = %x, want %x", gotVal, op.wantVal)
   755  					}
   756  					check("Bytes_de", n, op.wantCnt, op.wantErr)
   757  				case decodeBool:
   758  					gotVal, n := BinaryDecoder{}.DecodeBool(b)
   759  					if gotVal != op.wantVal {
   760  						t.Errorf("DecodeBool() = %t, want %t", gotVal, op.wantVal)
   761  					}
   762  					check("Bool_de", n, op.wantCnt, op.wantErr)
   763  				case decodeByte:
   764  					gotVal := BinaryDecoder{}.DecodeByte(b)
   765  					if gotVal != op.wantVal {
   766  						t.Errorf("DecodeByte() = %d, want %d", gotVal, op.wantVal)
   767  					}
   768  					check("Byte_de", 1, op.wantCnt, op.wantErr)
   769  				case decodeInt32:
   770  					gotVal, n := BinaryDecoder{}.DecodeInt32(b)
   771  					if gotVal != op.wantVal {
   772  						t.Errorf("DecodeInt32() = %d, want %d", gotVal, op.wantVal)
   773  					}
   774  					check("Int32_de", n, op.wantCnt, op.wantErr)
   775  				case decodeSint32:
   776  					gotVal, n := BinaryDecoder{}.DecodeSint32(b)
   777  					if gotVal != op.wantVal {
   778  						t.Errorf("DecodeSint32() = %d, want %d", gotVal, op.wantVal)
   779  					}
   780  					check("Sint32_de", n, op.wantCnt, op.wantErr)
   781  				case decodeUint32:
   782  					gotVal, n := BinaryDecoder{}.DecodeUint32(b)
   783  					if gotVal != op.wantVal {
   784  						t.Errorf("DecodeUint32() = %d, want %d", gotVal, op.wantVal)
   785  					}
   786  					check("Uint32_de", n, op.wantCnt, op.wantErr)
   787  				case decodeInt64:
   788  					gotVal, n := BinaryDecoder{}.DecodeInt64(b)
   789  					if gotVal != op.wantVal {
   790  						t.Errorf("DecodeInt64() = %d, want %d", gotVal, op.wantVal)
   791  					}
   792  					check("Int64_de", n, op.wantCnt, op.wantErr)
   793  				case decodeSint64:
   794  					gotVal, n := BinaryDecoder{}.DecodeSint64(b)
   795  					if gotVal != op.wantVal {
   796  						t.Errorf("DecodeSint64() = %d, want %d", gotVal, op.wantVal)
   797  					}
   798  					check("Sint64_de", n, op.wantCnt, op.wantErr)
   799  				case decodeUint64:
   800  					gotVal, n := BinaryDecoder{}.DecodeUint64(b)
   801  					if gotVal != op.wantVal {
   802  						t.Errorf("DecodeUint64() = %d, want %d", gotVal, op.wantVal)
   803  					}
   804  					check("Uint64_de", n, op.wantCnt, op.wantErr)
   805  				case decodeFixed32:
   806  					gotVal, n := BinaryDecoder{}.DecodeFixed32(b)
   807  					if gotVal != op.wantVal {
   808  						t.Errorf("DecodeFixed32() = %d, want %d", gotVal, op.wantVal)
   809  					}
   810  					check("DecodeFixed32_de", n, op.wantCnt, op.wantErr)
   811  				case decodeSfixed32:
   812  					gotVal, n := BinaryDecoder{}.DecodeSfixed32(b)
   813  					if gotVal != op.wantVal {
   814  						t.Errorf("DecodeSfixed32() = %d, want %d", gotVal, op.wantVal)
   815  					}
   816  					check("DecodeSfixed32_de", n, op.wantCnt, op.wantErr)
   817  				case decodeFloat32:
   818  					gotVal, n := BinaryDecoder{}.DecodeFloat32(b)
   819  					if gotVal != op.wantVal {
   820  						t.Errorf("DecodeFloat32() = %f, want %f", gotVal, op.wantVal)
   821  					}
   822  					check("Float32_de", n, op.wantCnt, op.wantErr)
   823  				case decodeFixed64:
   824  					gotVal, n := BinaryDecoder{}.DecodeFixed64(b)
   825  					if gotVal != op.wantVal {
   826  						t.Errorf("DecodeFixed64() = %d, want %d", gotVal, op.wantVal)
   827  					}
   828  					check("DecodeFixed64_de", n, op.wantCnt, op.wantErr)
   829  				case decodeSfixed64:
   830  					gotVal, n := BinaryDecoder{}.DecodeSfixed64(b)
   831  					if gotVal != op.wantVal {
   832  						t.Errorf("DecodeSfixed64() = %d, want %d", gotVal, op.wantVal)
   833  					}
   834  					check("DecodeSfixed64_de", n, op.wantCnt, op.wantErr)
   835  				case decodeDouble:
   836  					gotVal, n := BinaryDecoder{}.DecodeDouble(b)
   837  					if gotVal != op.wantVal {
   838  						t.Errorf("DecodeDouble() = %f, want %f", gotVal, op.wantVal)
   839  					}
   840  					check("Double_de", n, op.wantCnt, op.wantErr)
   841  				case decodeString:
   842  					gotVal, _, n := BinaryDecoder{}.DecodeString(b)
   843  					if gotVal != op.wantVal {
   844  						t.Errorf("DecodeString() = %s, want %s", gotVal, op.wantVal)
   845  					}
   846  					check("String_de", n, op.wantCnt, op.wantErr)
   847  				case decodeBytes:
   848  					gotVal, _, n := BinaryDecoder{}.DecodeBytes(b)
   849  					if !bytes.Equal(gotVal, op.wantVal) {
   850  						t.Errorf("DecodeBytes() = %x, want %x", gotVal, op.wantVal)
   851  					}
   852  					check("DecodeBytes_de", n, op.wantCnt, op.wantErr)
   853  				}
   854  			}
   855  		})
   856  	}
   857  }
   858  
   859  
   860  func TestZigZag(t *testing.T) {
   861  	tests := []struct {
   862  		dec int64
   863  		enc uint64
   864  	}{
   865  		{math.MinInt64 + 0, math.MaxUint64 - 0},
   866  		{math.MinInt64 + 1, math.MaxUint64 - 2},
   867  		{math.MinInt64 + 2, math.MaxUint64 - 4},
   868  		{-3, 5},
   869  		{-2, 3},
   870  		{-1, 1},
   871  		{0, 0},
   872  		{+1, 2},
   873  		{+2, 4},
   874  		{+3, 6},
   875  		{math.MaxInt64 - 2, math.MaxUint64 - 5},
   876  		{math.MaxInt64 - 1, math.MaxUint64 - 3},
   877  		{math.MaxInt64 - 0, math.MaxUint64 - 1},
   878  	}
   879  
   880  	for _, tt := range tests {
   881  		if enc := EncodeZigZag(tt.dec); enc != tt.enc {
   882  			t.Errorf("EncodeZigZag(%d) = %d, want %d", tt.dec, enc, tt.enc)
   883  		}
   884  		if dec := DecodeZigZag(tt.enc); dec != tt.dec {
   885  			t.Errorf("DecodeZigZag(%d) = %d, want %d", tt.enc, dec, tt.dec)
   886  		}
   887  	}
   888  }