...

Source file src/google.golang.org/protobuf/encoding/protowire/wire_test.go

Documentation: google.golang.org/protobuf/encoding/protowire

     1  // Copyright 2018 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 protowire
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  	"io"
    11  	"math"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  type (
    17  	testOps struct {
    18  		// appendOps is a sequence of append operations, each appending to
    19  		// the output of the previous append operation.
    20  		appendOps []appendOp
    21  
    22  		// wantRaw (if not nil) is the bytes that the appendOps should produce.
    23  		wantRaw []byte
    24  
    25  		// consumeOps are a sequence of consume operations, each consuming the
    26  		// remaining output after the previous consume operation.
    27  		// The first consume operation starts with the output of appendOps.
    28  		consumeOps []consumeOp
    29  	}
    30  
    31  	// appendOp represents an Append operation.
    32  	appendOp  = interface{}
    33  	appendTag struct {
    34  		inNum  Number
    35  		inType Type
    36  	}
    37  	appendVarint struct {
    38  		inVal uint64
    39  	}
    40  	appendFixed32 struct {
    41  		inVal uint32
    42  	}
    43  	appendFixed64 struct {
    44  		inVal uint64
    45  	}
    46  	appendBytes struct {
    47  		inVal []byte
    48  	}
    49  	appendGroup struct {
    50  		inNum Number
    51  		inVal []byte
    52  	}
    53  	appendRaw []byte
    54  
    55  	// consumeOp represents an Consume operation.
    56  	consumeOp    = interface{}
    57  	consumeField struct {
    58  		wantNum  Number
    59  		wantType Type
    60  		wantCnt  int
    61  		wantErr  error
    62  	}
    63  	consumeFieldValue struct {
    64  		inNum   Number
    65  		inType  Type
    66  		wantCnt int
    67  		wantErr error
    68  	}
    69  	consumeTag struct {
    70  		wantNum  Number
    71  		wantType Type
    72  		wantCnt  int
    73  		wantErr  error
    74  	}
    75  	consumeVarint struct {
    76  		wantVal uint64
    77  		wantCnt int
    78  		wantErr error
    79  	}
    80  	consumeFixed32 struct {
    81  		wantVal uint32
    82  		wantCnt int
    83  		wantErr error
    84  	}
    85  	consumeFixed64 struct {
    86  		wantVal uint64
    87  		wantCnt int
    88  		wantErr error
    89  	}
    90  	consumeBytes struct {
    91  		wantVal []byte
    92  		wantCnt int
    93  		wantErr error
    94  	}
    95  	consumeGroup struct {
    96  		inNum   Number
    97  		wantVal []byte
    98  		wantCnt int
    99  		wantErr error
   100  	}
   101  
   102  	ops []interface{}
   103  )
   104  
   105  // dhex decodes a hex-string and returns the bytes and panics if s is invalid.
   106  func dhex(s string) []byte {
   107  	b, err := hex.DecodeString(s)
   108  	if err != nil {
   109  		panic(err)
   110  	}
   111  	return b
   112  }
   113  
   114  func TestTag(t *testing.T) {
   115  	runTests(t, []testOps{{
   116  		appendOps:  ops{appendRaw(dhex(""))},
   117  		consumeOps: ops{consumeTag{wantErr: io.ErrUnexpectedEOF}},
   118  	}, {
   119  		appendOps:  ops{appendTag{inNum: 0, inType: Fixed32Type}},
   120  		wantRaw:    dhex("05"),
   121  		consumeOps: ops{consumeTag{wantErr: errFieldNumber}},
   122  	}, {
   123  		appendOps:  ops{appendTag{inNum: 1, inType: Fixed32Type}},
   124  		wantRaw:    dhex("0d"),
   125  		consumeOps: ops{consumeTag{wantNum: 1, wantType: Fixed32Type, wantCnt: 1}},
   126  	}, {
   127  		appendOps:  ops{appendTag{inNum: FirstReservedNumber, inType: BytesType}},
   128  		wantRaw:    dhex("c2a309"),
   129  		consumeOps: ops{consumeTag{wantNum: FirstReservedNumber, wantType: BytesType, wantCnt: 3}},
   130  	}, {
   131  		appendOps:  ops{appendTag{inNum: LastReservedNumber, inType: StartGroupType}},
   132  		wantRaw:    dhex("fbe109"),
   133  		consumeOps: ops{consumeTag{wantNum: LastReservedNumber, wantType: StartGroupType, wantCnt: 3}},
   134  	}, {
   135  		appendOps:  ops{appendTag{inNum: MaxValidNumber, inType: VarintType}},
   136  		wantRaw:    dhex("f8ffffff0f"),
   137  		consumeOps: ops{consumeTag{wantNum: MaxValidNumber, wantType: VarintType, wantCnt: 5}},
   138  	}, {
   139  		appendOps:  ops{appendVarint{inVal: ((math.MaxInt32+1)<<3 | uint64(VarintType))}},
   140  		wantRaw:    dhex("8080808040"),
   141  		consumeOps: ops{consumeTag{wantErr: errFieldNumber}},
   142  	}})
   143  }
   144  
   145  func TestVarint(t *testing.T) {
   146  	runTests(t, []testOps{{
   147  		appendOps:  ops{appendRaw(dhex(""))},
   148  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   149  	}, {
   150  		appendOps:  ops{appendRaw(dhex("80"))},
   151  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   152  	}, {
   153  		appendOps:  ops{appendRaw(dhex("8080"))},
   154  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   155  	}, {
   156  		appendOps:  ops{appendRaw(dhex("808080"))},
   157  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   158  	}, {
   159  		appendOps:  ops{appendRaw(dhex("80808080"))},
   160  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   161  	}, {
   162  		appendOps:  ops{appendRaw(dhex("8080808080"))},
   163  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   164  	}, {
   165  		appendOps:  ops{appendRaw(dhex("808080808080"))},
   166  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   167  	}, {
   168  		appendOps:  ops{appendRaw(dhex("80808080808080"))},
   169  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   170  	}, {
   171  		appendOps:  ops{appendRaw(dhex("8080808080808080"))},
   172  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   173  	}, {
   174  		appendOps:  ops{appendRaw(dhex("808080808080808080"))},
   175  		consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
   176  	}, {
   177  		appendOps:  ops{appendRaw(dhex("80808080808080808080"))},
   178  		consumeOps: ops{consumeVarint{wantErr: errOverflow}},
   179  	}, {
   180  		// Test varints at various boundaries where the length changes.
   181  		appendOps:  ops{appendVarint{inVal: 0x0}},
   182  		wantRaw:    dhex("00"),
   183  		consumeOps: ops{consumeVarint{wantVal: 0, wantCnt: 1}},
   184  	}, {
   185  		appendOps:  ops{appendVarint{inVal: 0x1}},
   186  		wantRaw:    dhex("01"),
   187  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
   188  	}, {
   189  		appendOps:  ops{appendVarint{inVal: 0x7f}},
   190  		wantRaw:    dhex("7f"),
   191  		consumeOps: ops{consumeVarint{wantVal: 0x7f, wantCnt: 1}},
   192  	}, {
   193  		appendOps:  ops{appendVarint{inVal: 0x7f + 1}},
   194  		wantRaw:    dhex("8001"),
   195  		consumeOps: ops{consumeVarint{wantVal: 0x7f + 1, wantCnt: 2}},
   196  	}, {
   197  		appendOps:  ops{appendVarint{inVal: 0x3fff}},
   198  		wantRaw:    dhex("ff7f"),
   199  		consumeOps: ops{consumeVarint{wantVal: 0x3fff, wantCnt: 2}},
   200  	}, {
   201  		appendOps:  ops{appendVarint{inVal: 0x3fff + 1}},
   202  		wantRaw:    dhex("808001"),
   203  		consumeOps: ops{consumeVarint{wantVal: 0x3fff + 1, wantCnt: 3}},
   204  	}, {
   205  		appendOps:  ops{appendVarint{inVal: 0x1fffff}},
   206  		wantRaw:    dhex("ffff7f"),
   207  		consumeOps: ops{consumeVarint{wantVal: 0x1fffff, wantCnt: 3}},
   208  	}, {
   209  		appendOps:  ops{appendVarint{inVal: 0x1fffff + 1}},
   210  		wantRaw:    dhex("80808001"),
   211  		consumeOps: ops{consumeVarint{wantVal: 0x1fffff + 1, wantCnt: 4}},
   212  	}, {
   213  		appendOps:  ops{appendVarint{inVal: 0xfffffff}},
   214  		wantRaw:    dhex("ffffff7f"),
   215  		consumeOps: ops{consumeVarint{wantVal: 0xfffffff, wantCnt: 4}},
   216  	}, {
   217  		appendOps:  ops{appendVarint{inVal: 0xfffffff + 1}},
   218  		wantRaw:    dhex("8080808001"),
   219  		consumeOps: ops{consumeVarint{wantVal: 0xfffffff + 1, wantCnt: 5}},
   220  	}, {
   221  		appendOps:  ops{appendVarint{inVal: 0x7ffffffff}},
   222  		wantRaw:    dhex("ffffffff7f"),
   223  		consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff, wantCnt: 5}},
   224  	}, {
   225  		appendOps:  ops{appendVarint{inVal: 0x7ffffffff + 1}},
   226  		wantRaw:    dhex("808080808001"),
   227  		consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff + 1, wantCnt: 6}},
   228  	}, {
   229  		appendOps:  ops{appendVarint{inVal: 0x3ffffffffff}},
   230  		wantRaw:    dhex("ffffffffff7f"),
   231  		consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff, wantCnt: 6}},
   232  	}, {
   233  		appendOps:  ops{appendVarint{inVal: 0x3ffffffffff + 1}},
   234  		wantRaw:    dhex("80808080808001"),
   235  		consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff + 1, wantCnt: 7}},
   236  	}, {
   237  		appendOps:  ops{appendVarint{inVal: 0x1ffffffffffff}},
   238  		wantRaw:    dhex("ffffffffffff7f"),
   239  		consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff, wantCnt: 7}},
   240  	}, {
   241  		appendOps:  ops{appendVarint{inVal: 0x1ffffffffffff + 1}},
   242  		wantRaw:    dhex("8080808080808001"),
   243  		consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff + 1, wantCnt: 8}},
   244  	}, {
   245  		appendOps:  ops{appendVarint{inVal: 0xffffffffffffff}},
   246  		wantRaw:    dhex("ffffffffffffff7f"),
   247  		consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff, wantCnt: 8}},
   248  	}, {
   249  		appendOps:  ops{appendVarint{inVal: 0xffffffffffffff + 1}},
   250  		wantRaw:    dhex("808080808080808001"),
   251  		consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff + 1, wantCnt: 9}},
   252  	}, {
   253  		appendOps:  ops{appendVarint{inVal: 0x7fffffffffffffff}},
   254  		wantRaw:    dhex("ffffffffffffffff7f"),
   255  		consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff, wantCnt: 9}},
   256  	}, {
   257  		appendOps:  ops{appendVarint{inVal: 0x7fffffffffffffff + 1}},
   258  		wantRaw:    dhex("80808080808080808001"),
   259  		consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff + 1, wantCnt: 10}},
   260  	}, {
   261  		appendOps:  ops{appendVarint{inVal: math.MaxUint64}},
   262  		wantRaw:    dhex("ffffffffffffffffff01"),
   263  		consumeOps: ops{consumeVarint{wantVal: math.MaxUint64, wantCnt: 10}},
   264  	}, {
   265  		appendOps:  ops{appendRaw(dhex("ffffffffffffffffff02"))},
   266  		consumeOps: ops{consumeVarint{wantErr: errOverflow}},
   267  	}, {
   268  		// Test denormalized varints; where the encoding, while valid, is
   269  		// larger than necessary.
   270  		appendOps:  ops{appendRaw(dhex("01"))},
   271  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
   272  	}, {
   273  		appendOps:  ops{appendRaw(dhex("8100"))},
   274  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 2}},
   275  	}, {
   276  		appendOps:  ops{appendRaw(dhex("818000"))},
   277  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 3}},
   278  	}, {
   279  		appendOps:  ops{appendRaw(dhex("81808000"))},
   280  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 4}},
   281  	}, {
   282  		appendOps:  ops{appendRaw(dhex("8180808000"))},
   283  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 5}},
   284  	}, {
   285  		appendOps:  ops{appendRaw(dhex("818080808000"))},
   286  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 6}},
   287  	}, {
   288  		appendOps:  ops{appendRaw(dhex("81808080808000"))},
   289  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 7}},
   290  	}, {
   291  		appendOps:  ops{appendRaw(dhex("8180808080808000"))},
   292  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 8}},
   293  	}, {
   294  		appendOps:  ops{appendRaw(dhex("818080808080808000"))},
   295  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 9}},
   296  	}, {
   297  		appendOps:  ops{appendRaw(dhex("81808080808080808000"))},
   298  		consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 10}},
   299  	}, {
   300  		appendOps:  ops{appendRaw(dhex("8180808080808080808000"))},
   301  		consumeOps: ops{consumeVarint{wantErr: errOverflow}},
   302  	}})
   303  }
   304  
   305  func TestFixed32(t *testing.T) {
   306  	runTests(t, []testOps{{
   307  		appendOps:  ops{appendRaw(dhex(""))},
   308  		consumeOps: ops{consumeFixed32{wantErr: io.ErrUnexpectedEOF}},
   309  	}, {
   310  		appendOps:  ops{appendRaw(dhex("000000"))},
   311  		consumeOps: ops{consumeFixed32{wantErr: io.ErrUnexpectedEOF}},
   312  	}, {
   313  		appendOps:  ops{appendFixed32{0}},
   314  		wantRaw:    dhex("00000000"),
   315  		consumeOps: ops{consumeFixed32{wantVal: 0, wantCnt: 4}},
   316  	}, {
   317  		appendOps:  ops{appendFixed32{math.MaxUint32}},
   318  		wantRaw:    dhex("ffffffff"),
   319  		consumeOps: ops{consumeFixed32{wantVal: math.MaxUint32, wantCnt: 4}},
   320  	}, {
   321  		appendOps:  ops{appendFixed32{0xf0e1d2c3}},
   322  		wantRaw:    dhex("c3d2e1f0"),
   323  		consumeOps: ops{consumeFixed32{wantVal: 0xf0e1d2c3, wantCnt: 4}},
   324  	}})
   325  }
   326  
   327  func TestFixed64(t *testing.T) {
   328  	runTests(t, []testOps{{
   329  		appendOps:  ops{appendRaw(dhex(""))},
   330  		consumeOps: ops{consumeFixed64{wantErr: io.ErrUnexpectedEOF}},
   331  	}, {
   332  		appendOps:  ops{appendRaw(dhex("00000000000000"))},
   333  		consumeOps: ops{consumeFixed64{wantErr: io.ErrUnexpectedEOF}},
   334  	}, {
   335  		appendOps:  ops{appendFixed64{0}},
   336  		wantRaw:    dhex("0000000000000000"),
   337  		consumeOps: ops{consumeFixed64{wantVal: 0, wantCnt: 8}},
   338  	}, {
   339  		appendOps:  ops{appendFixed64{math.MaxUint64}},
   340  		wantRaw:    dhex("ffffffffffffffff"),
   341  		consumeOps: ops{consumeFixed64{wantVal: math.MaxUint64, wantCnt: 8}},
   342  	}, {
   343  		appendOps:  ops{appendFixed64{0xf0e1d2c3b4a59687}},
   344  		wantRaw:    dhex("8796a5b4c3d2e1f0"),
   345  		consumeOps: ops{consumeFixed64{wantVal: 0xf0e1d2c3b4a59687, wantCnt: 8}},
   346  	}})
   347  }
   348  
   349  func TestBytes(t *testing.T) {
   350  	runTests(t, []testOps{{
   351  		appendOps:  ops{appendRaw(dhex(""))},
   352  		consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
   353  	}, {
   354  		appendOps:  ops{appendRaw(dhex("01"))},
   355  		consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
   356  	}, {
   357  		appendOps:  ops{appendVarint{0}, appendRaw("")},
   358  		wantRaw:    dhex("00"),
   359  		consumeOps: ops{consumeBytes{wantVal: dhex(""), wantCnt: 1}},
   360  	}, {
   361  		appendOps:  ops{appendBytes{[]byte("hello")}},
   362  		wantRaw:    []byte("\x05hello"),
   363  		consumeOps: ops{consumeBytes{wantVal: []byte("hello"), wantCnt: 6}},
   364  	}, {
   365  		appendOps:  ops{appendBytes{[]byte(strings.Repeat("hello", 50))}},
   366  		wantRaw:    []byte("\xfa\x01" + strings.Repeat("hello", 50)),
   367  		consumeOps: ops{consumeBytes{wantVal: []byte(strings.Repeat("hello", 50)), wantCnt: 252}},
   368  	}, {
   369  		appendOps:  ops{appendRaw("\x85\x80\x00hello")},
   370  		consumeOps: ops{consumeBytes{wantVal: []byte("hello"), wantCnt: 8}},
   371  	}, {
   372  		appendOps:  ops{appendRaw("\x85\x80\x00hell")},
   373  		consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
   374  	}})
   375  }
   376  
   377  func TestGroup(t *testing.T) {
   378  	runTests(t, []testOps{{
   379  		appendOps:  ops{appendRaw(dhex(""))},
   380  		consumeOps: ops{consumeGroup{wantErr: io.ErrUnexpectedEOF}},
   381  	}, {
   382  		appendOps:  ops{appendTag{inNum: 0, inType: StartGroupType}},
   383  		consumeOps: ops{consumeGroup{inNum: 1, wantErr: errFieldNumber}},
   384  	}, {
   385  		appendOps:  ops{appendTag{inNum: 2, inType: EndGroupType}},
   386  		consumeOps: ops{consumeGroup{inNum: 1, wantErr: errEndGroup}},
   387  	}, {
   388  		appendOps:  ops{appendTag{inNum: 1, inType: EndGroupType}},
   389  		consumeOps: ops{consumeGroup{inNum: 1, wantCnt: 1}},
   390  	}, {
   391  		appendOps: ops{
   392  			appendTag{inNum: 5, inType: Fixed32Type},
   393  			appendFixed32{0xf0e1d2c3},
   394  			appendTag{inNum: 5, inType: EndGroupType},
   395  		},
   396  		wantRaw:    dhex("2dc3d2e1f02c"),
   397  		consumeOps: ops{consumeGroup{inNum: 5, wantVal: dhex("2dc3d2e1f0"), wantCnt: 6}},
   398  	}, {
   399  		appendOps: ops{
   400  			appendTag{inNum: 5, inType: Fixed32Type},
   401  			appendFixed32{0xf0e1d2c3},
   402  			appendRaw(dhex("ac808000")),
   403  		},
   404  		consumeOps: ops{consumeGroup{inNum: 5, wantVal: dhex("2dc3d2e1f0"), wantCnt: 9}},
   405  	}})
   406  }
   407  
   408  func TestField(t *testing.T) {
   409  	runTests(t, []testOps{{
   410  		appendOps:  ops{appendRaw(dhex(""))},
   411  		consumeOps: ops{consumeField{wantErr: io.ErrUnexpectedEOF}},
   412  	}, {
   413  		appendOps: ops{
   414  			appendTag{inNum: 5000, inType: StartGroupType},
   415  			appendTag{inNum: 1, inType: VarintType},
   416  			appendVarint{123456789},
   417  			appendTag{inNum: 12, inType: Fixed32Type},
   418  			appendFixed32{123456789},
   419  			appendTag{inNum: 123, inType: Fixed64Type},
   420  			appendFixed64{123456789},
   421  			appendTag{inNum: 1234, inType: BytesType},
   422  			appendBytes{[]byte("hello")},
   423  			appendTag{inNum: 12345, inType: StartGroupType},
   424  			appendTag{inNum: 11, inType: VarintType},
   425  			appendVarint{123456789},
   426  			appendTag{inNum: 1212, inType: Fixed32Type},
   427  			appendFixed32{123456789},
   428  			appendTag{inNum: 123123, inType: Fixed64Type},
   429  			appendFixed64{123456789},
   430  			appendTag{inNum: 12341234, inType: BytesType},
   431  			appendBytes{[]byte("goodbye")},
   432  			appendTag{inNum: 12345, inType: EndGroupType},
   433  			appendTag{inNum: 5000, inType: EndGroupType},
   434  		},
   435  		wantRaw: dhex("c3b80208959aef3a6515cd5b07d90715cd5b0700000000924d0568656c6c6fcb830658959aef3ae54b15cd5b07998f3c15cd5b070000000092ff892f07676f6f64627965cc8306c4b802"),
   436  		consumeOps: ops{
   437  			consumeTag{wantNum: 5000, wantType: StartGroupType, wantCnt: 3},
   438  			consumeTag{wantNum: 1, wantType: VarintType, wantCnt: 1},
   439  			consumeVarint{wantVal: 123456789, wantCnt: 4},
   440  			consumeTag{wantNum: 12, wantType: Fixed32Type, wantCnt: 1},
   441  			consumeFixed32{wantVal: 123456789, wantCnt: 4},
   442  			consumeTag{wantNum: 123, wantType: Fixed64Type, wantCnt: 2},
   443  			consumeFixed64{wantVal: 123456789, wantCnt: 8},
   444  			consumeTag{wantNum: 1234, wantType: BytesType, wantCnt: 2},
   445  			consumeBytes{wantVal: []byte("hello"), wantCnt: 6},
   446  			consumeTag{wantNum: 12345, wantType: StartGroupType, wantCnt: 3},
   447  			consumeTag{wantNum: 11, wantType: VarintType, wantCnt: 1},
   448  			consumeVarint{wantVal: 123456789, wantCnt: 4},
   449  			consumeTag{wantNum: 1212, wantType: Fixed32Type, wantCnt: 2},
   450  			consumeFixed32{wantVal: 123456789, wantCnt: 4},
   451  			consumeTag{wantNum: 123123, wantType: Fixed64Type, wantCnt: 3},
   452  			consumeFixed64{wantVal: 123456789, wantCnt: 8},
   453  			consumeTag{wantNum: 12341234, wantType: BytesType, wantCnt: 4},
   454  			consumeBytes{wantVal: []byte("goodbye"), wantCnt: 8},
   455  			consumeTag{wantNum: 12345, wantType: EndGroupType, wantCnt: 3},
   456  			consumeTag{wantNum: 5000, wantType: EndGroupType, wantCnt: 3},
   457  		},
   458  	}, {
   459  		appendOps:  ops{appendRaw(dhex("c3b80208959aef3a6515cd5b07d90715cd5b0700000000924d0568656c6c6fcb830658959aef3ae54b15cd5b07998f3c15cd5b070000000092ff892f07676f6f64627965cc8306c4b802"))},
   460  		consumeOps: ops{consumeField{wantNum: 5000, wantType: StartGroupType, wantCnt: 74}},
   461  	}, {
   462  		appendOps:  ops{appendTag{inNum: 5, inType: EndGroupType}},
   463  		wantRaw:    dhex("2c"),
   464  		consumeOps: ops{consumeField{wantErr: errEndGroup}},
   465  	}, {
   466  		appendOps: ops{
   467  			appendTag{inNum: 1, inType: StartGroupType},
   468  			appendTag{inNum: 22, inType: StartGroupType},
   469  			appendTag{inNum: 333, inType: StartGroupType},
   470  			appendTag{inNum: 4444, inType: StartGroupType},
   471  			appendTag{inNum: 4444, inType: EndGroupType},
   472  			appendTag{inNum: 333, inType: EndGroupType},
   473  			appendTag{inNum: 22, inType: EndGroupType},
   474  			appendTag{inNum: 1, inType: EndGroupType},
   475  		},
   476  		wantRaw:    dhex("0bb301eb14e39502e49502ec14b4010c"),
   477  		consumeOps: ops{consumeField{wantNum: 1, wantType: StartGroupType, wantCnt: 16}},
   478  	}, {
   479  		appendOps: ops{
   480  			appendTag{inNum: 1, inType: StartGroupType},
   481  			appendGroup{inNum: 1, inVal: dhex("b301eb14e39502e49502ec14b401")},
   482  		},
   483  		wantRaw:    dhex("0b" + "b301eb14e39502e49502ec14b401" + "0c"),
   484  		consumeOps: ops{consumeField{wantNum: 1, wantType: StartGroupType, wantCnt: 16}},
   485  	}, {
   486  		appendOps: ops{
   487  			appendTag{inNum: 1, inType: StartGroupType},
   488  			appendTag{inNum: 22, inType: StartGroupType},
   489  			appendTag{inNum: 333, inType: StartGroupType},
   490  			appendTag{inNum: 4444, inType: StartGroupType},
   491  			appendTag{inNum: 333, inType: EndGroupType},
   492  			appendTag{inNum: 22, inType: EndGroupType},
   493  			appendTag{inNum: 1, inType: EndGroupType},
   494  		},
   495  		consumeOps: ops{consumeField{wantErr: errEndGroup}},
   496  	}, {
   497  		appendOps: ops{
   498  			appendTag{inNum: 1, inType: StartGroupType},
   499  			appendTag{inNum: 22, inType: StartGroupType},
   500  			appendTag{inNum: 333, inType: StartGroupType},
   501  			appendTag{inNum: 4444, inType: StartGroupType},
   502  			appendTag{inNum: 4444, inType: EndGroupType},
   503  			appendTag{inNum: 333, inType: EndGroupType},
   504  			appendTag{inNum: 22, inType: EndGroupType},
   505  		},
   506  		consumeOps: ops{consumeField{wantErr: io.ErrUnexpectedEOF}},
   507  	}, {
   508  		appendOps: ops{
   509  			appendTag{inNum: 1, inType: StartGroupType},
   510  			appendTag{inNum: 22, inType: StartGroupType},
   511  			appendTag{inNum: 333, inType: StartGroupType},
   512  			appendTag{inNum: 4444, inType: StartGroupType},
   513  			appendTag{inNum: 0, inType: VarintType},
   514  			appendTag{inNum: 4444, inType: EndGroupType},
   515  			appendTag{inNum: 333, inType: EndGroupType},
   516  			appendTag{inNum: 22, inType: EndGroupType},
   517  			appendTag{inNum: 1, inType: EndGroupType},
   518  		},
   519  		consumeOps: ops{consumeField{wantErr: errFieldNumber}},
   520  	}, {
   521  		appendOps: ops{
   522  			appendTag{inNum: 1, inType: StartGroupType},
   523  			appendTag{inNum: 22, inType: StartGroupType},
   524  			appendTag{inNum: 333, inType: StartGroupType},
   525  			appendTag{inNum: 4444, inType: StartGroupType},
   526  			appendTag{inNum: 1, inType: 6},
   527  			appendTag{inNum: 4444, inType: EndGroupType},
   528  			appendTag{inNum: 333, inType: EndGroupType},
   529  			appendTag{inNum: 22, inType: EndGroupType},
   530  			appendTag{inNum: 1, inType: EndGroupType},
   531  		},
   532  		consumeOps: ops{consumeField{wantErr: errReserved}},
   533  	}})
   534  }
   535  
   536  func runTests(t *testing.T, tests []testOps) {
   537  	for _, tt := range tests {
   538  		t.Run("", func(t *testing.T) {
   539  			var b []byte
   540  			for _, op := range tt.appendOps {
   541  				b0 := b
   542  				switch op := op.(type) {
   543  				case appendTag:
   544  					b = AppendTag(b, op.inNum, op.inType)
   545  				case appendVarint:
   546  					b = AppendVarint(b, op.inVal)
   547  				case appendFixed32:
   548  					b = AppendFixed32(b, op.inVal)
   549  				case appendFixed64:
   550  					b = AppendFixed64(b, op.inVal)
   551  				case appendBytes:
   552  					b = AppendBytes(b, op.inVal)
   553  				case appendGroup:
   554  					b = AppendGroup(b, op.inNum, op.inVal)
   555  				case appendRaw:
   556  					b = append(b, op...)
   557  				}
   558  
   559  				check := func(label string, want int) {
   560  					t.Helper()
   561  					if got := len(b) - len(b0); got != want {
   562  						t.Errorf("len(Append%v) and Size%v mismatch: got %v, want %v", label, label, got, want)
   563  					}
   564  				}
   565  				switch op := op.(type) {
   566  				case appendTag:
   567  					check("Tag", SizeTag(op.inNum))
   568  				case appendVarint:
   569  					check("Varint", SizeVarint(op.inVal))
   570  				case appendFixed32:
   571  					check("Fixed32", SizeFixed32())
   572  				case appendFixed64:
   573  					check("Fixed64", SizeFixed64())
   574  				case appendBytes:
   575  					check("Bytes", SizeBytes(len(op.inVal)))
   576  				case appendGroup:
   577  					check("Group", SizeGroup(op.inNum, len(op.inVal)))
   578  				}
   579  			}
   580  
   581  			if tt.wantRaw != nil && !bytes.Equal(b, tt.wantRaw) {
   582  				t.Errorf("raw output mismatch:\ngot  %x\nwant %x", b, tt.wantRaw)
   583  			}
   584  
   585  			for _, op := range tt.consumeOps {
   586  				check := func(label string, gotCnt, wantCnt int, wantErr error) {
   587  					t.Helper()
   588  					gotErr := ParseError(gotCnt)
   589  					if gotCnt < 0 {
   590  						gotCnt = 0
   591  					}
   592  					if gotCnt != wantCnt {
   593  						t.Errorf("Consume%v(): consumed %d bytes, want %d bytes consumed", label, gotCnt, wantCnt)
   594  					}
   595  					if gotErr != wantErr {
   596  						t.Errorf("Consume%v(): got %v error, want %v error", label, gotErr, wantErr)
   597  					}
   598  					b = b[gotCnt:]
   599  				}
   600  				switch op := op.(type) {
   601  				case consumeField:
   602  					gotNum, gotType, n := ConsumeField(b)
   603  					if gotNum != op.wantNum || gotType != op.wantType {
   604  						t.Errorf("ConsumeField() = (%d, %v), want (%d, %v)", gotNum, gotType, op.wantNum, op.wantType)
   605  					}
   606  					check("Field", n, op.wantCnt, op.wantErr)
   607  				case consumeFieldValue:
   608  					n := ConsumeFieldValue(op.inNum, op.inType, b)
   609  					check("FieldValue", n, op.wantCnt, op.wantErr)
   610  				case consumeTag:
   611  					gotNum, gotType, n := ConsumeTag(b)
   612  					if gotNum != op.wantNum || gotType != op.wantType {
   613  						t.Errorf("ConsumeTag() = (%d, %v), want (%d, %v)", gotNum, gotType, op.wantNum, op.wantType)
   614  					}
   615  					check("Tag", n, op.wantCnt, op.wantErr)
   616  				case consumeVarint:
   617  					gotVal, n := ConsumeVarint(b)
   618  					if gotVal != op.wantVal {
   619  						t.Errorf("ConsumeVarint() = %d, want %d", gotVal, op.wantVal)
   620  					}
   621  					check("Varint", n, op.wantCnt, op.wantErr)
   622  				case consumeFixed32:
   623  					gotVal, n := ConsumeFixed32(b)
   624  					if gotVal != op.wantVal {
   625  						t.Errorf("ConsumeFixed32() = %d, want %d", gotVal, op.wantVal)
   626  					}
   627  					check("Fixed32", n, op.wantCnt, op.wantErr)
   628  				case consumeFixed64:
   629  					gotVal, n := ConsumeFixed64(b)
   630  					if gotVal != op.wantVal {
   631  						t.Errorf("ConsumeFixed64() = %d, want %d", gotVal, op.wantVal)
   632  					}
   633  					check("Fixed64", n, op.wantCnt, op.wantErr)
   634  				case consumeBytes:
   635  					gotVal, n := ConsumeBytes(b)
   636  					if !bytes.Equal(gotVal, op.wantVal) {
   637  						t.Errorf("ConsumeBytes() = %x, want %x", gotVal, op.wantVal)
   638  					}
   639  					check("Bytes", n, op.wantCnt, op.wantErr)
   640  				case consumeGroup:
   641  					gotVal, n := ConsumeGroup(op.inNum, b)
   642  					if !bytes.Equal(gotVal, op.wantVal) {
   643  						t.Errorf("ConsumeGroup() = %x, want %x", gotVal, op.wantVal)
   644  					}
   645  					check("Group", n, op.wantCnt, op.wantErr)
   646  				}
   647  			}
   648  		})
   649  	}
   650  }
   651  
   652  func TestZigZag(t *testing.T) {
   653  	tests := []struct {
   654  		dec int64
   655  		enc uint64
   656  	}{
   657  		{math.MinInt64 + 0, math.MaxUint64 - 0},
   658  		{math.MinInt64 + 1, math.MaxUint64 - 2},
   659  		{math.MinInt64 + 2, math.MaxUint64 - 4},
   660  		{-3, 5},
   661  		{-2, 3},
   662  		{-1, 1},
   663  		{0, 0},
   664  		{+1, 2},
   665  		{+2, 4},
   666  		{+3, 6},
   667  		{math.MaxInt64 - 2, math.MaxUint64 - 5},
   668  		{math.MaxInt64 - 1, math.MaxUint64 - 3},
   669  		{math.MaxInt64 - 0, math.MaxUint64 - 1},
   670  	}
   671  
   672  	for _, tt := range tests {
   673  		if enc := EncodeZigZag(tt.dec); enc != tt.enc {
   674  			t.Errorf("EncodeZigZag(%d) = %d, want %d", tt.dec, enc, tt.enc)
   675  		}
   676  		if dec := DecodeZigZag(tt.enc); dec != tt.dec {
   677  			t.Errorf("DecodeZigZag(%d) = %d, want %d", tt.enc, dec, tt.dec)
   678  		}
   679  	}
   680  }
   681  

View as plain text