mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-06 00:55:51 +00:00
972d873b59
The protobuf documentation explicitly specifies (1<<29)-1 as the maximum field number, but the C++ implementation itself has a special-case where it allows field numbers up to MaxInt32 for MessageSet fields, but continues to apply the former limit in all non-MessageSet cases. To avoid complicated branching logic, we use the larger limit for all cases if MessageSet is supported, otherwise, we impose the documented limit. Change-Id: I710a2a21aa3beba161c3e6ca2f2ed9a266920a5a Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/175817 Reviewed-by: Damien Neil <dneil@google.com>
681 lines
23 KiB
Go
681 lines
23 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package wire
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"io"
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type (
|
|
testOps struct {
|
|
// appendOps is a sequence of append operations, each appending to
|
|
// the output of the previous append operation.
|
|
appendOps []appendOp
|
|
|
|
// wantRaw (if not nil) is the bytes that the appendOps should produce.
|
|
wantRaw []byte
|
|
|
|
// consumeOps are a sequence of consume operations, each consuming the
|
|
// remaining output after the previous consume operation.
|
|
// The first consume operation starts with the output of appendOps.
|
|
consumeOps []consumeOp
|
|
}
|
|
|
|
// appendOp represents an Append operation.
|
|
appendOp = interface{}
|
|
appendTag struct {
|
|
inNum Number
|
|
inType Type
|
|
}
|
|
appendVarint struct {
|
|
inVal uint64
|
|
}
|
|
appendFixed32 struct {
|
|
inVal uint32
|
|
}
|
|
appendFixed64 struct {
|
|
inVal uint64
|
|
}
|
|
appendBytes struct {
|
|
inVal []byte
|
|
}
|
|
appendGroup struct {
|
|
inNum Number
|
|
inVal []byte
|
|
}
|
|
appendRaw []byte
|
|
|
|
// consumeOp represents an Consume operation.
|
|
consumeOp = interface{}
|
|
consumeField struct {
|
|
wantNum Number
|
|
wantType Type
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeFieldValue struct {
|
|
inNum Number
|
|
inType Type
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeTag struct {
|
|
wantNum Number
|
|
wantType Type
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeVarint struct {
|
|
wantVal uint64
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeFixed32 struct {
|
|
wantVal uint32
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeFixed64 struct {
|
|
wantVal uint64
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeBytes struct {
|
|
wantVal []byte
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
consumeGroup struct {
|
|
inNum Number
|
|
wantVal []byte
|
|
wantCnt int
|
|
wantErr error
|
|
}
|
|
|
|
ops []interface{}
|
|
)
|
|
|
|
// dhex decodes a hex-string and returns the bytes and panics if s is invalid.
|
|
func dhex(s string) []byte {
|
|
b, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func TestTag(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeTag{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: 0, inType: Fixed32Type}},
|
|
wantRaw: dhex("05"),
|
|
consumeOps: ops{consumeTag{wantErr: errFieldNumber}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: 1, inType: Fixed32Type}},
|
|
wantRaw: dhex("0d"),
|
|
consumeOps: ops{consumeTag{wantNum: 1, wantType: Fixed32Type, wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: FirstReservedNumber, inType: BytesType}},
|
|
wantRaw: dhex("c2a309"),
|
|
consumeOps: ops{consumeTag{wantNum: FirstReservedNumber, wantType: BytesType, wantCnt: 3}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: LastReservedNumber, inType: StartGroupType}},
|
|
wantRaw: dhex("fbe109"),
|
|
consumeOps: ops{consumeTag{wantNum: LastReservedNumber, wantType: StartGroupType, wantCnt: 3}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: MaxValidNumber, inType: VarintType}},
|
|
wantRaw: dhex("f8ffffff0f"),
|
|
consumeOps: ops{consumeTag{wantNum: MaxValidNumber, wantType: VarintType, wantCnt: 5}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: ((math.MaxInt32+1)<<3 | uint64(VarintType))}},
|
|
wantRaw: dhex("8080808040"),
|
|
consumeOps: ops{consumeTag{wantErr: errFieldNumber}},
|
|
}})
|
|
}
|
|
|
|
func TestVarint(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("80"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("80808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8080808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("808080808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("80808080808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8080808080808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("808080808080808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("80808080808080808080"))},
|
|
consumeOps: ops{consumeVarint{wantErr: errOverflow}},
|
|
}, {
|
|
// Test varints at various boundaries where the length changes.
|
|
appendOps: ops{appendVarint{inVal: 0x0}},
|
|
wantRaw: dhex("00"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0, wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x1}},
|
|
wantRaw: dhex("01"),
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x7f}},
|
|
wantRaw: dhex("7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x7f, wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x7f + 1}},
|
|
wantRaw: dhex("8001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x7f + 1, wantCnt: 2}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x3fff}},
|
|
wantRaw: dhex("ff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x3fff, wantCnt: 2}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x3fff + 1}},
|
|
wantRaw: dhex("808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x3fff + 1, wantCnt: 3}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x1fffff}},
|
|
wantRaw: dhex("ffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x1fffff, wantCnt: 3}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x1fffff + 1}},
|
|
wantRaw: dhex("80808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x1fffff + 1, wantCnt: 4}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0xfffffff}},
|
|
wantRaw: dhex("ffffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0xfffffff, wantCnt: 4}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0xfffffff + 1}},
|
|
wantRaw: dhex("8080808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0xfffffff + 1, wantCnt: 5}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x7ffffffff}},
|
|
wantRaw: dhex("ffffffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff, wantCnt: 5}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x7ffffffff + 1}},
|
|
wantRaw: dhex("808080808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff + 1, wantCnt: 6}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x3ffffffffff}},
|
|
wantRaw: dhex("ffffffffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff, wantCnt: 6}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x3ffffffffff + 1}},
|
|
wantRaw: dhex("80808080808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff + 1, wantCnt: 7}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x1ffffffffffff}},
|
|
wantRaw: dhex("ffffffffffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff, wantCnt: 7}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x1ffffffffffff + 1}},
|
|
wantRaw: dhex("8080808080808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff + 1, wantCnt: 8}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0xffffffffffffff}},
|
|
wantRaw: dhex("ffffffffffffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff, wantCnt: 8}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0xffffffffffffff + 1}},
|
|
wantRaw: dhex("808080808080808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff + 1, wantCnt: 9}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x7fffffffffffffff}},
|
|
wantRaw: dhex("ffffffffffffffff7f"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff, wantCnt: 9}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: 0x7fffffffffffffff + 1}},
|
|
wantRaw: dhex("80808080808080808001"),
|
|
consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff + 1, wantCnt: 10}},
|
|
}, {
|
|
appendOps: ops{appendVarint{inVal: math.MaxUint64}},
|
|
wantRaw: dhex("ffffffffffffffffff01"),
|
|
consumeOps: ops{consumeVarint{wantVal: math.MaxUint64, wantCnt: 10}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("ffffffffffffffffff02"))},
|
|
consumeOps: ops{consumeVarint{wantErr: errOverflow}},
|
|
}, {
|
|
// Test denormalized varints; where the encoding, while valid, is
|
|
// larger than necessary.
|
|
appendOps: ops{appendRaw(dhex("01"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8100"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 2}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("818000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 3}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("81808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 4}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8180808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 5}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("818080808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 6}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("81808080808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 7}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8180808080808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 8}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("818080808080808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 9}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("81808080808080808000"))},
|
|
consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 10}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("8180808080808080808000"))},
|
|
consumeOps: ops{consumeVarint{wantErr: errOverflow}},
|
|
}})
|
|
}
|
|
|
|
func TestFixed32(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeFixed32{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("000000"))},
|
|
consumeOps: ops{consumeFixed32{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendFixed32{0}},
|
|
wantRaw: dhex("00000000"),
|
|
consumeOps: ops{consumeFixed32{wantVal: 0, wantCnt: 4}},
|
|
}, {
|
|
appendOps: ops{appendFixed32{math.MaxUint32}},
|
|
wantRaw: dhex("ffffffff"),
|
|
consumeOps: ops{consumeFixed32{wantVal: math.MaxUint32, wantCnt: 4}},
|
|
}, {
|
|
appendOps: ops{appendFixed32{0xf0e1d2c3}},
|
|
wantRaw: dhex("c3d2e1f0"),
|
|
consumeOps: ops{consumeFixed32{wantVal: 0xf0e1d2c3, wantCnt: 4}},
|
|
}})
|
|
}
|
|
|
|
func TestFixed64(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeFixed64{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("00000000000000"))},
|
|
consumeOps: ops{consumeFixed64{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendFixed64{0}},
|
|
wantRaw: dhex("0000000000000000"),
|
|
consumeOps: ops{consumeFixed64{wantVal: 0, wantCnt: 8}},
|
|
}, {
|
|
appendOps: ops{appendFixed64{math.MaxUint64}},
|
|
wantRaw: dhex("ffffffffffffffff"),
|
|
consumeOps: ops{consumeFixed64{wantVal: math.MaxUint64, wantCnt: 8}},
|
|
}, {
|
|
appendOps: ops{appendFixed64{0xf0e1d2c3b4a59687}},
|
|
wantRaw: dhex("8796a5b4c3d2e1f0"),
|
|
consumeOps: ops{consumeFixed64{wantVal: 0xf0e1d2c3b4a59687, wantCnt: 8}},
|
|
}})
|
|
}
|
|
|
|
func TestBytes(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("01"))},
|
|
consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendVarint{0}, appendRaw("")},
|
|
wantRaw: dhex("00"),
|
|
consumeOps: ops{consumeBytes{wantVal: dhex(""), wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{appendBytes{[]byte("hello")}},
|
|
wantRaw: []byte("\x05hello"),
|
|
consumeOps: ops{consumeBytes{wantVal: []byte("hello"), wantCnt: 6}},
|
|
}, {
|
|
appendOps: ops{appendBytes{[]byte(strings.Repeat("hello", 50))}},
|
|
wantRaw: []byte("\xfa\x01" + strings.Repeat("hello", 50)),
|
|
consumeOps: ops{consumeBytes{wantVal: []byte(strings.Repeat("hello", 50)), wantCnt: 252}},
|
|
}, {
|
|
appendOps: ops{appendRaw("\x85\x80\x00hello")},
|
|
consumeOps: ops{consumeBytes{wantVal: []byte("hello"), wantCnt: 8}},
|
|
}, {
|
|
appendOps: ops{appendRaw("\x85\x80\x00hell")},
|
|
consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
|
|
}})
|
|
}
|
|
|
|
func TestGroup(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeGroup{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: 0, inType: StartGroupType}},
|
|
consumeOps: ops{consumeGroup{inNum: 1, wantErr: errFieldNumber}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: 2, inType: EndGroupType}},
|
|
consumeOps: ops{consumeGroup{inNum: 1, wantErr: errEndGroup}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: 1, inType: EndGroupType}},
|
|
consumeOps: ops{consumeGroup{inNum: 1, wantCnt: 1}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 5, inType: Fixed32Type},
|
|
appendFixed32{0xf0e1d2c3},
|
|
appendTag{inNum: 5, inType: EndGroupType},
|
|
},
|
|
wantRaw: dhex("2dc3d2e1f02c"),
|
|
consumeOps: ops{consumeGroup{inNum: 5, wantVal: dhex("2dc3d2e1f0"), wantCnt: 6}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 5, inType: Fixed32Type},
|
|
appendFixed32{0xf0e1d2c3},
|
|
appendRaw(dhex("ac808000")),
|
|
},
|
|
consumeOps: ops{consumeGroup{inNum: 5, wantVal: dhex("2dc3d2e1f0"), wantCnt: 9}},
|
|
}})
|
|
}
|
|
|
|
func TestField(t *testing.T) {
|
|
runTests(t, []testOps{{
|
|
appendOps: ops{appendRaw(dhex(""))},
|
|
consumeOps: ops{consumeField{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 5000, inType: StartGroupType},
|
|
appendTag{inNum: 1, inType: VarintType},
|
|
appendVarint{123456789},
|
|
appendTag{inNum: 12, inType: Fixed32Type},
|
|
appendFixed32{123456789},
|
|
appendTag{inNum: 123, inType: Fixed64Type},
|
|
appendFixed64{123456789},
|
|
appendTag{inNum: 1234, inType: BytesType},
|
|
appendBytes{[]byte("hello")},
|
|
appendTag{inNum: 12345, inType: StartGroupType},
|
|
appendTag{inNum: 11, inType: VarintType},
|
|
appendVarint{123456789},
|
|
appendTag{inNum: 1212, inType: Fixed32Type},
|
|
appendFixed32{123456789},
|
|
appendTag{inNum: 123123, inType: Fixed64Type},
|
|
appendFixed64{123456789},
|
|
appendTag{inNum: 12341234, inType: BytesType},
|
|
appendBytes{[]byte("goodbye")},
|
|
appendTag{inNum: 12345, inType: EndGroupType},
|
|
appendTag{inNum: 5000, inType: EndGroupType},
|
|
},
|
|
wantRaw: dhex("c3b80208959aef3a6515cd5b07d90715cd5b0700000000924d0568656c6c6fcb830658959aef3ae54b15cd5b07998f3c15cd5b070000000092ff892f07676f6f64627965cc8306c4b802"),
|
|
consumeOps: ops{
|
|
consumeTag{wantNum: 5000, wantType: StartGroupType, wantCnt: 3},
|
|
consumeTag{wantNum: 1, wantType: VarintType, wantCnt: 1},
|
|
consumeVarint{wantVal: 123456789, wantCnt: 4},
|
|
consumeTag{wantNum: 12, wantType: Fixed32Type, wantCnt: 1},
|
|
consumeFixed32{wantVal: 123456789, wantCnt: 4},
|
|
consumeTag{wantNum: 123, wantType: Fixed64Type, wantCnt: 2},
|
|
consumeFixed64{wantVal: 123456789, wantCnt: 8},
|
|
consumeTag{wantNum: 1234, wantType: BytesType, wantCnt: 2},
|
|
consumeBytes{wantVal: []byte("hello"), wantCnt: 6},
|
|
consumeTag{wantNum: 12345, wantType: StartGroupType, wantCnt: 3},
|
|
consumeTag{wantNum: 11, wantType: VarintType, wantCnt: 1},
|
|
consumeVarint{wantVal: 123456789, wantCnt: 4},
|
|
consumeTag{wantNum: 1212, wantType: Fixed32Type, wantCnt: 2},
|
|
consumeFixed32{wantVal: 123456789, wantCnt: 4},
|
|
consumeTag{wantNum: 123123, wantType: Fixed64Type, wantCnt: 3},
|
|
consumeFixed64{wantVal: 123456789, wantCnt: 8},
|
|
consumeTag{wantNum: 12341234, wantType: BytesType, wantCnt: 4},
|
|
consumeBytes{wantVal: []byte("goodbye"), wantCnt: 8},
|
|
consumeTag{wantNum: 12345, wantType: EndGroupType, wantCnt: 3},
|
|
consumeTag{wantNum: 5000, wantType: EndGroupType, wantCnt: 3},
|
|
},
|
|
}, {
|
|
appendOps: ops{appendRaw(dhex("c3b80208959aef3a6515cd5b07d90715cd5b0700000000924d0568656c6c6fcb830658959aef3ae54b15cd5b07998f3c15cd5b070000000092ff892f07676f6f64627965cc8306c4b802"))},
|
|
consumeOps: ops{consumeField{wantNum: 5000, wantType: StartGroupType, wantCnt: 74}},
|
|
}, {
|
|
appendOps: ops{appendTag{inNum: 5, inType: EndGroupType}},
|
|
wantRaw: dhex("2c"),
|
|
consumeOps: ops{consumeField{wantErr: errEndGroup}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 1, inType: StartGroupType},
|
|
appendTag{inNum: 22, inType: StartGroupType},
|
|
appendTag{inNum: 333, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: EndGroupType},
|
|
appendTag{inNum: 333, inType: EndGroupType},
|
|
appendTag{inNum: 22, inType: EndGroupType},
|
|
appendTag{inNum: 1, inType: EndGroupType},
|
|
},
|
|
wantRaw: dhex("0bb301eb14e39502e49502ec14b4010c"),
|
|
consumeOps: ops{consumeField{wantNum: 1, wantType: StartGroupType, wantCnt: 16}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 1, inType: StartGroupType},
|
|
appendGroup{inNum: 1, inVal: dhex("b301eb14e39502e49502ec14b401")},
|
|
},
|
|
wantRaw: dhex("0b" + "b301eb14e39502e49502ec14b401" + "0c"),
|
|
consumeOps: ops{consumeField{wantNum: 1, wantType: StartGroupType, wantCnt: 16}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 1, inType: StartGroupType},
|
|
appendTag{inNum: 22, inType: StartGroupType},
|
|
appendTag{inNum: 333, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: StartGroupType},
|
|
appendTag{inNum: 333, inType: EndGroupType},
|
|
appendTag{inNum: 22, inType: EndGroupType},
|
|
appendTag{inNum: 1, inType: EndGroupType},
|
|
},
|
|
consumeOps: ops{consumeField{wantErr: errEndGroup}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 1, inType: StartGroupType},
|
|
appendTag{inNum: 22, inType: StartGroupType},
|
|
appendTag{inNum: 333, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: EndGroupType},
|
|
appendTag{inNum: 333, inType: EndGroupType},
|
|
appendTag{inNum: 22, inType: EndGroupType},
|
|
},
|
|
consumeOps: ops{consumeField{wantErr: io.ErrUnexpectedEOF}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 1, inType: StartGroupType},
|
|
appendTag{inNum: 22, inType: StartGroupType},
|
|
appendTag{inNum: 333, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: StartGroupType},
|
|
appendTag{inNum: 0, inType: VarintType},
|
|
appendTag{inNum: 4444, inType: EndGroupType},
|
|
appendTag{inNum: 333, inType: EndGroupType},
|
|
appendTag{inNum: 22, inType: EndGroupType},
|
|
appendTag{inNum: 1, inType: EndGroupType},
|
|
},
|
|
consumeOps: ops{consumeField{wantErr: errFieldNumber}},
|
|
}, {
|
|
appendOps: ops{
|
|
appendTag{inNum: 1, inType: StartGroupType},
|
|
appendTag{inNum: 22, inType: StartGroupType},
|
|
appendTag{inNum: 333, inType: StartGroupType},
|
|
appendTag{inNum: 4444, inType: StartGroupType},
|
|
appendTag{inNum: 1, inType: 6},
|
|
appendTag{inNum: 4444, inType: EndGroupType},
|
|
appendTag{inNum: 333, inType: EndGroupType},
|
|
appendTag{inNum: 22, inType: EndGroupType},
|
|
appendTag{inNum: 1, inType: EndGroupType},
|
|
},
|
|
consumeOps: ops{consumeField{wantErr: errReserved}},
|
|
}})
|
|
}
|
|
|
|
func runTests(t *testing.T, tests []testOps) {
|
|
for _, tt := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
var b []byte
|
|
for _, op := range tt.appendOps {
|
|
b0 := b
|
|
switch op := op.(type) {
|
|
case appendTag:
|
|
b = AppendTag(b, op.inNum, op.inType)
|
|
case appendVarint:
|
|
b = AppendVarint(b, op.inVal)
|
|
case appendFixed32:
|
|
b = AppendFixed32(b, op.inVal)
|
|
case appendFixed64:
|
|
b = AppendFixed64(b, op.inVal)
|
|
case appendBytes:
|
|
b = AppendBytes(b, op.inVal)
|
|
case appendGroup:
|
|
b = AppendGroup(b, op.inNum, op.inVal)
|
|
case appendRaw:
|
|
b = append(b, op...)
|
|
}
|
|
|
|
check := func(label string, want int) {
|
|
t.Helper()
|
|
if got := len(b) - len(b0); got != want {
|
|
t.Errorf("len(Append%v) and Size%v mismatch: got %v, want %v", label, label, got, want)
|
|
}
|
|
}
|
|
switch op := op.(type) {
|
|
case appendTag:
|
|
check("Tag", SizeTag(op.inNum))
|
|
case appendVarint:
|
|
check("Varint", SizeVarint(op.inVal))
|
|
case appendFixed32:
|
|
check("Fixed32", SizeFixed32())
|
|
case appendFixed64:
|
|
check("Fixed64", SizeFixed64())
|
|
case appendBytes:
|
|
check("Bytes", SizeBytes(len(op.inVal)))
|
|
case appendGroup:
|
|
check("Group", SizeGroup(op.inNum, len(op.inVal)))
|
|
}
|
|
}
|
|
|
|
if tt.wantRaw != nil && !bytes.Equal(b, tt.wantRaw) {
|
|
t.Errorf("raw output mismatch:\ngot %x\nwant %x", b, tt.wantRaw)
|
|
}
|
|
|
|
for _, op := range tt.consumeOps {
|
|
check := func(label string, gotCnt, wantCnt int, wantErr error) {
|
|
t.Helper()
|
|
gotErr := ParseError(gotCnt)
|
|
if gotCnt < 0 {
|
|
gotCnt = 0
|
|
}
|
|
if gotCnt != wantCnt {
|
|
t.Errorf("Consume%v(): consumed %d bytes, want %d bytes consumed", label, gotCnt, wantCnt)
|
|
}
|
|
if gotErr != wantErr {
|
|
t.Errorf("Consume%v(): got %v error, want %v error", label, gotErr, wantErr)
|
|
}
|
|
b = b[gotCnt:]
|
|
}
|
|
switch op := op.(type) {
|
|
case consumeField:
|
|
gotNum, gotType, n := ConsumeField(b)
|
|
if gotNum != op.wantNum || gotType != op.wantType {
|
|
t.Errorf("ConsumeField() = (%d, %v), want (%d, %v)", gotNum, gotType, op.wantNum, op.wantType)
|
|
}
|
|
check("Field", n, op.wantCnt, op.wantErr)
|
|
case consumeFieldValue:
|
|
n := ConsumeFieldValue(op.inNum, op.inType, b)
|
|
check("FieldValue", n, op.wantCnt, op.wantErr)
|
|
case consumeTag:
|
|
gotNum, gotType, n := ConsumeTag(b)
|
|
if gotNum != op.wantNum || gotType != op.wantType {
|
|
t.Errorf("ConsumeTag() = (%d, %v), want (%d, %v)", gotNum, gotType, op.wantNum, op.wantType)
|
|
}
|
|
check("Tag", n, op.wantCnt, op.wantErr)
|
|
case consumeVarint:
|
|
gotVal, n := ConsumeVarint(b)
|
|
if gotVal != op.wantVal {
|
|
t.Errorf("ConsumeVarint() = %d, want %d", gotVal, op.wantVal)
|
|
}
|
|
check("Varint", n, op.wantCnt, op.wantErr)
|
|
case consumeFixed32:
|
|
gotVal, n := ConsumeFixed32(b)
|
|
if gotVal != op.wantVal {
|
|
t.Errorf("ConsumeFixed32() = %d, want %d", gotVal, op.wantVal)
|
|
}
|
|
check("Fixed32", n, op.wantCnt, op.wantErr)
|
|
case consumeFixed64:
|
|
gotVal, n := ConsumeFixed64(b)
|
|
if gotVal != op.wantVal {
|
|
t.Errorf("ConsumeFixed64() = %d, want %d", gotVal, op.wantVal)
|
|
}
|
|
check("Fixed64", n, op.wantCnt, op.wantErr)
|
|
case consumeBytes:
|
|
gotVal, n := ConsumeBytes(b)
|
|
if !bytes.Equal(gotVal, op.wantVal) {
|
|
t.Errorf("ConsumeBytes() = %x, want %x", gotVal, op.wantVal)
|
|
}
|
|
check("Bytes", n, op.wantCnt, op.wantErr)
|
|
case consumeGroup:
|
|
gotVal, n := ConsumeGroup(op.inNum, b)
|
|
if !bytes.Equal(gotVal, op.wantVal) {
|
|
t.Errorf("ConsumeGroup() = %x, want %x", gotVal, op.wantVal)
|
|
}
|
|
check("Group", n, op.wantCnt, op.wantErr)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestZigZag(t *testing.T) {
|
|
tests := []struct {
|
|
dec int64
|
|
enc uint64
|
|
}{
|
|
{math.MinInt64 + 0, math.MaxUint64 - 0},
|
|
{math.MinInt64 + 1, math.MaxUint64 - 2},
|
|
{math.MinInt64 + 2, math.MaxUint64 - 4},
|
|
{-3, 5},
|
|
{-2, 3},
|
|
{-1, 1},
|
|
{0, 0},
|
|
{+1, 2},
|
|
{+2, 4},
|
|
{+3, 6},
|
|
{math.MaxInt64 - 2, math.MaxUint64 - 5},
|
|
{math.MaxInt64 - 1, math.MaxUint64 - 3},
|
|
{math.MaxInt64 - 0, math.MaxUint64 - 1},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
if enc := EncodeZigZag(tt.dec); enc != tt.enc {
|
|
t.Errorf("EncodeZigZag(%d) = %d, want %d", tt.dec, enc, tt.enc)
|
|
}
|
|
if dec := DecodeZigZag(tt.enc); dec != tt.dec {
|
|
t.Errorf("DecodeZigZag(%d) = %d, want %d", tt.enc, dec, tt.dec)
|
|
}
|
|
}
|
|
}
|