mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-09 03:39:24 +00:00
f83d5bb6f0
Change-Id: I839660146760a66c5cbf25d24f81f0ba5096d9e1 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/167395 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
937 lines
20 KiB
Go
937 lines
20 KiB
Go
// Copyright 2019 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 jsonpb_test
|
|
|
|
import (
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/golang/protobuf/protoapi"
|
|
"github.com/golang/protobuf/v2/encoding/jsonpb"
|
|
"github.com/golang/protobuf/v2/internal/encoding/pack"
|
|
"github.com/golang/protobuf/v2/internal/encoding/wire"
|
|
"github.com/golang/protobuf/v2/internal/scalar"
|
|
"github.com/golang/protobuf/v2/proto"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
|
|
// This legacy package is still needed when importing legacy message.
|
|
_ "github.com/golang/protobuf/v2/internal/legacy"
|
|
|
|
"github.com/golang/protobuf/v2/encoding/testprotos/pb2"
|
|
"github.com/golang/protobuf/v2/encoding/testprotos/pb3"
|
|
)
|
|
|
|
// splitLines is a cmpopts.Option for comparing strings with line breaks.
|
|
var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
|
|
return strings.Split(s, "\n")
|
|
})
|
|
|
|
func pb2Enum(i int32) *pb2.Enum {
|
|
p := new(pb2.Enum)
|
|
*p = pb2.Enum(i)
|
|
return p
|
|
}
|
|
|
|
func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
|
|
p := new(pb2.Enums_NestedEnum)
|
|
*p = pb2.Enums_NestedEnum(i)
|
|
return p
|
|
}
|
|
|
|
func setExtension(m proto.Message, xd *protoapi.ExtensionDesc, val interface{}) {
|
|
knownFields := m.ProtoReflect().KnownFields()
|
|
extTypes := knownFields.ExtensionTypes()
|
|
extTypes.Register(xd.Type)
|
|
if val == nil {
|
|
return
|
|
}
|
|
pval := xd.Type.ValueOf(val)
|
|
knownFields.Set(wire.Number(xd.Field), pval)
|
|
}
|
|
|
|
func TestMarshal(t *testing.T) {
|
|
tests := []struct {
|
|
desc string
|
|
mo jsonpb.MarshalOptions
|
|
input proto.Message
|
|
want string
|
|
}{{
|
|
desc: "proto2 optional scalars not set",
|
|
input: &pb2.Scalars{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto3 scalars not set",
|
|
input: &pb3.Scalars{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto2 optional scalars set to zero values",
|
|
input: &pb2.Scalars{
|
|
OptBool: scalar.Bool(false),
|
|
OptInt32: scalar.Int32(0),
|
|
OptInt64: scalar.Int64(0),
|
|
OptUint32: scalar.Uint32(0),
|
|
OptUint64: scalar.Uint64(0),
|
|
OptSint32: scalar.Int32(0),
|
|
OptSint64: scalar.Int64(0),
|
|
OptFixed32: scalar.Uint32(0),
|
|
OptFixed64: scalar.Uint64(0),
|
|
OptSfixed32: scalar.Int32(0),
|
|
OptSfixed64: scalar.Int64(0),
|
|
OptFloat: scalar.Float32(0),
|
|
OptDouble: scalar.Float64(0),
|
|
OptBytes: []byte{},
|
|
OptString: scalar.String(""),
|
|
},
|
|
want: `{
|
|
"optBool": false,
|
|
"optInt32": 0,
|
|
"optInt64": "0",
|
|
"optUint32": 0,
|
|
"optUint64": "0",
|
|
"optSint32": 0,
|
|
"optSint64": "0",
|
|
"optFixed32": 0,
|
|
"optFixed64": "0",
|
|
"optSfixed32": 0,
|
|
"optSfixed64": "0",
|
|
"optFloat": 0,
|
|
"optDouble": 0,
|
|
"optBytes": "",
|
|
"optString": ""
|
|
}`,
|
|
}, {
|
|
desc: "proto2 optional scalars set to some values",
|
|
input: &pb2.Scalars{
|
|
OptBool: scalar.Bool(true),
|
|
OptInt32: scalar.Int32(0xff),
|
|
OptInt64: scalar.Int64(0xdeadbeef),
|
|
OptUint32: scalar.Uint32(47),
|
|
OptUint64: scalar.Uint64(0xdeadbeef),
|
|
OptSint32: scalar.Int32(-1001),
|
|
OptSint64: scalar.Int64(-0xffff),
|
|
OptFixed64: scalar.Uint64(64),
|
|
OptSfixed32: scalar.Int32(-32),
|
|
OptFloat: scalar.Float32(1.02),
|
|
OptDouble: scalar.Float64(1.234),
|
|
OptBytes: []byte("谷歌"),
|
|
OptString: scalar.String("谷歌"),
|
|
},
|
|
want: `{
|
|
"optBool": true,
|
|
"optInt32": 255,
|
|
"optInt64": "3735928559",
|
|
"optUint32": 47,
|
|
"optUint64": "3735928559",
|
|
"optSint32": -1001,
|
|
"optSint64": "-65535",
|
|
"optFixed64": "64",
|
|
"optSfixed32": -32,
|
|
"optFloat": 1.02,
|
|
"optDouble": 1.234,
|
|
"optBytes": "6LC35q2M",
|
|
"optString": "谷歌"
|
|
}`,
|
|
}, {
|
|
desc: "float nan",
|
|
input: &pb3.Scalars{
|
|
SFloat: float32(math.NaN()),
|
|
},
|
|
want: `{
|
|
"sFloat": "NaN"
|
|
}`,
|
|
}, {
|
|
desc: "float positive infinity",
|
|
input: &pb3.Scalars{
|
|
SFloat: float32(math.Inf(1)),
|
|
},
|
|
want: `{
|
|
"sFloat": "Infinity"
|
|
}`,
|
|
}, {
|
|
desc: "float negative infinity",
|
|
input: &pb3.Scalars{
|
|
SFloat: float32(math.Inf(-1)),
|
|
},
|
|
want: `{
|
|
"sFloat": "-Infinity"
|
|
}`,
|
|
}, {
|
|
desc: "double nan",
|
|
input: &pb3.Scalars{
|
|
SDouble: math.NaN(),
|
|
},
|
|
want: `{
|
|
"sDouble": "NaN"
|
|
}`,
|
|
}, {
|
|
desc: "double positive infinity",
|
|
input: &pb3.Scalars{
|
|
SDouble: math.Inf(1),
|
|
},
|
|
want: `{
|
|
"sDouble": "Infinity"
|
|
}`,
|
|
}, {
|
|
desc: "double negative infinity",
|
|
input: &pb3.Scalars{
|
|
SDouble: math.Inf(-1),
|
|
},
|
|
want: `{
|
|
"sDouble": "-Infinity"
|
|
}`,
|
|
}, {
|
|
desc: "proto2 enum not set",
|
|
input: &pb2.Enums{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto2 enum set to zero value",
|
|
input: &pb2.Enums{
|
|
OptEnum: pb2Enum(0),
|
|
OptNestedEnum: pb2Enums_NestedEnum(0),
|
|
},
|
|
want: `{
|
|
"optEnum": 0,
|
|
"optNestedEnum": 0
|
|
}`,
|
|
}, {
|
|
desc: "proto2 enum",
|
|
input: &pb2.Enums{
|
|
OptEnum: pb2.Enum_ONE.Enum(),
|
|
OptNestedEnum: pb2.Enums_UNO.Enum(),
|
|
},
|
|
want: `{
|
|
"optEnum": "ONE",
|
|
"optNestedEnum": "UNO"
|
|
}`,
|
|
}, {
|
|
desc: "proto2 enum set to numeric values",
|
|
input: &pb2.Enums{
|
|
OptEnum: pb2Enum(2),
|
|
OptNestedEnum: pb2Enums_NestedEnum(2),
|
|
},
|
|
want: `{
|
|
"optEnum": "TWO",
|
|
"optNestedEnum": "DOS"
|
|
}`,
|
|
}, {
|
|
desc: "proto2 enum set to unnamed numeric values",
|
|
input: &pb2.Enums{
|
|
OptEnum: pb2Enum(101),
|
|
OptNestedEnum: pb2Enums_NestedEnum(-101),
|
|
},
|
|
want: `{
|
|
"optEnum": 101,
|
|
"optNestedEnum": -101
|
|
}`,
|
|
}, {
|
|
desc: "proto3 enum not set",
|
|
input: &pb3.Enums{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto3 enum set to zero value",
|
|
input: &pb3.Enums{
|
|
SEnum: pb3.Enum_ZERO,
|
|
SNestedEnum: pb3.Enums_CERO,
|
|
},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto3 enum",
|
|
input: &pb3.Enums{
|
|
SEnum: pb3.Enum_ONE,
|
|
SNestedEnum: pb3.Enums_UNO,
|
|
},
|
|
want: `{
|
|
"sEnum": "ONE",
|
|
"sNestedEnum": "UNO"
|
|
}`,
|
|
}, {
|
|
desc: "proto3 enum set to numeric values",
|
|
input: &pb3.Enums{
|
|
SEnum: 2,
|
|
SNestedEnum: 2,
|
|
},
|
|
want: `{
|
|
"sEnum": "TWO",
|
|
"sNestedEnum": "DOS"
|
|
}`,
|
|
}, {
|
|
desc: "proto3 enum set to unnamed numeric values",
|
|
input: &pb3.Enums{
|
|
SEnum: -47,
|
|
SNestedEnum: 47,
|
|
},
|
|
want: `{
|
|
"sEnum": -47,
|
|
"sNestedEnum": 47
|
|
}`,
|
|
}, {
|
|
desc: "proto2 nested message not set",
|
|
input: &pb2.Nests{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto2 nested message set to empty",
|
|
input: &pb2.Nests{
|
|
OptNested: &pb2.Nested{},
|
|
Optgroup: &pb2.Nests_OptGroup{},
|
|
},
|
|
want: `{
|
|
"optNested": {},
|
|
"optgroup": {}
|
|
}`,
|
|
}, {
|
|
desc: "proto2 nested messages",
|
|
input: &pb2.Nests{
|
|
OptNested: &pb2.Nested{
|
|
OptString: scalar.String("nested message"),
|
|
OptNested: &pb2.Nested{
|
|
OptString: scalar.String("another nested message"),
|
|
},
|
|
},
|
|
},
|
|
want: `{
|
|
"optNested": {
|
|
"optString": "nested message",
|
|
"optNested": {
|
|
"optString": "another nested message"
|
|
}
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "proto2 groups",
|
|
input: &pb2.Nests{
|
|
Optgroup: &pb2.Nests_OptGroup{
|
|
OptString: scalar.String("inside a group"),
|
|
OptNested: &pb2.Nested{
|
|
OptString: scalar.String("nested message inside a group"),
|
|
},
|
|
Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
|
|
OptFixed32: scalar.Uint32(47),
|
|
},
|
|
},
|
|
},
|
|
want: `{
|
|
"optgroup": {
|
|
"optString": "inside a group",
|
|
"optNested": {
|
|
"optString": "nested message inside a group"
|
|
},
|
|
"optnestedgroup": {
|
|
"optFixed32": 47
|
|
}
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "proto3 nested message not set",
|
|
input: &pb3.Nests{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "proto3 nested message set to empty",
|
|
input: &pb3.Nests{
|
|
SNested: &pb3.Nested{},
|
|
},
|
|
want: `{
|
|
"sNested": {}
|
|
}`,
|
|
}, {
|
|
desc: "proto3 nested message",
|
|
input: &pb3.Nests{
|
|
SNested: &pb3.Nested{
|
|
SString: "nested message",
|
|
SNested: &pb3.Nested{
|
|
SString: "another nested message",
|
|
},
|
|
},
|
|
},
|
|
want: `{
|
|
"sNested": {
|
|
"sString": "nested message",
|
|
"sNested": {
|
|
"sString": "another nested message"
|
|
}
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "oneof not set",
|
|
input: &pb3.Oneofs{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "oneof set to empty string",
|
|
input: &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofString{},
|
|
},
|
|
want: `{
|
|
"oneofString": ""
|
|
}`,
|
|
}, {
|
|
desc: "oneof set to string",
|
|
input: &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofString{
|
|
OneofString: "hello",
|
|
},
|
|
},
|
|
want: `{
|
|
"oneofString": "hello"
|
|
}`,
|
|
}, {
|
|
desc: "oneof set to enum",
|
|
input: &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofEnum{
|
|
OneofEnum: pb3.Enum_ZERO,
|
|
},
|
|
},
|
|
want: `{
|
|
"oneofEnum": "ZERO"
|
|
}`,
|
|
}, {
|
|
desc: "oneof set to empty message",
|
|
input: &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofNested{
|
|
OneofNested: &pb3.Nested{},
|
|
},
|
|
},
|
|
want: `{
|
|
"oneofNested": {}
|
|
}`,
|
|
}, {
|
|
desc: "oneof set to message",
|
|
input: &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofNested{
|
|
OneofNested: &pb3.Nested{
|
|
SString: "nested message",
|
|
},
|
|
},
|
|
},
|
|
want: `{
|
|
"oneofNested": {
|
|
"sString": "nested message"
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "repeated fields not set",
|
|
input: &pb2.Repeats{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "repeated fields set to empty slices",
|
|
input: &pb2.Repeats{
|
|
RptBool: []bool{},
|
|
RptInt32: []int32{},
|
|
RptInt64: []int64{},
|
|
RptUint32: []uint32{},
|
|
RptUint64: []uint64{},
|
|
RptFloat: []float32{},
|
|
RptDouble: []float64{},
|
|
RptBytes: [][]byte{},
|
|
},
|
|
want: "{}",
|
|
}, {
|
|
desc: "repeated fields set to some values",
|
|
input: &pb2.Repeats{
|
|
RptBool: []bool{true, false, true, true},
|
|
RptInt32: []int32{1, 6, 0, 0},
|
|
RptInt64: []int64{-64, 47},
|
|
RptUint32: []uint32{0xff, 0xffff},
|
|
RptUint64: []uint64{0xdeadbeef},
|
|
RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
|
|
RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
|
|
RptString: []string{"hello", "世界"},
|
|
RptBytes: [][]byte{
|
|
[]byte("hello"),
|
|
[]byte("\xe4\xb8\x96\xe7\x95\x8c"),
|
|
},
|
|
},
|
|
want: `{
|
|
"rptBool": [
|
|
true,
|
|
false,
|
|
true,
|
|
true
|
|
],
|
|
"rptInt32": [
|
|
1,
|
|
6,
|
|
0,
|
|
0
|
|
],
|
|
"rptInt64": [
|
|
"-64",
|
|
"47"
|
|
],
|
|
"rptUint32": [
|
|
255,
|
|
65535
|
|
],
|
|
"rptUint64": [
|
|
"3735928559"
|
|
],
|
|
"rptFloat": [
|
|
"NaN",
|
|
"Infinity",
|
|
"-Infinity",
|
|
1.034
|
|
],
|
|
"rptDouble": [
|
|
"NaN",
|
|
"Infinity",
|
|
"-Infinity",
|
|
1.23e-308
|
|
],
|
|
"rptString": [
|
|
"hello",
|
|
"世界"
|
|
],
|
|
"rptBytes": [
|
|
"aGVsbG8=",
|
|
"5LiW55WM"
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "repeated enums",
|
|
input: &pb2.Enums{
|
|
RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
|
|
RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
|
|
},
|
|
want: `{
|
|
"rptEnum": [
|
|
"ONE",
|
|
"TWO",
|
|
"TEN",
|
|
42
|
|
],
|
|
"rptNestedEnum": [
|
|
"DOS",
|
|
47,
|
|
"DIEZ"
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "repeated messages set to empty",
|
|
input: &pb2.Nests{
|
|
RptNested: []*pb2.Nested{},
|
|
Rptgroup: []*pb2.Nests_RptGroup{},
|
|
},
|
|
want: "{}",
|
|
}, {
|
|
desc: "repeated messages",
|
|
input: &pb2.Nests{
|
|
RptNested: []*pb2.Nested{
|
|
{
|
|
OptString: scalar.String("repeat nested one"),
|
|
},
|
|
{
|
|
OptString: scalar.String("repeat nested two"),
|
|
OptNested: &pb2.Nested{
|
|
OptString: scalar.String("inside repeat nested two"),
|
|
},
|
|
},
|
|
{},
|
|
},
|
|
},
|
|
want: `{
|
|
"rptNested": [
|
|
{
|
|
"optString": "repeat nested one"
|
|
},
|
|
{
|
|
"optString": "repeat nested two",
|
|
"optNested": {
|
|
"optString": "inside repeat nested two"
|
|
}
|
|
},
|
|
{}
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "repeated messages contains nil value",
|
|
input: &pb2.Nests{
|
|
RptNested: []*pb2.Nested{nil, {}},
|
|
},
|
|
want: `{
|
|
"rptNested": [
|
|
{},
|
|
{}
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "repeated groups",
|
|
input: &pb2.Nests{
|
|
Rptgroup: []*pb2.Nests_RptGroup{
|
|
{
|
|
RptString: []string{"hello", "world"},
|
|
},
|
|
{},
|
|
nil,
|
|
},
|
|
},
|
|
want: `{
|
|
"rptgroup": [
|
|
{
|
|
"rptString": [
|
|
"hello",
|
|
"world"
|
|
]
|
|
},
|
|
{},
|
|
{}
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "map fields not set",
|
|
input: &pb3.Maps{},
|
|
want: "{}",
|
|
}, {
|
|
desc: "map fields set to empty",
|
|
input: &pb3.Maps{
|
|
Int32ToStr: map[int32]string{},
|
|
BoolToUint32: map[bool]uint32{},
|
|
Uint64ToEnum: map[uint64]pb3.Enum{},
|
|
StrToNested: map[string]*pb3.Nested{},
|
|
StrToOneofs: map[string]*pb3.Oneofs{},
|
|
},
|
|
want: "{}",
|
|
}, {
|
|
desc: "map fields 1",
|
|
input: &pb3.Maps{
|
|
BoolToUint32: map[bool]uint32{
|
|
true: 42,
|
|
false: 101,
|
|
},
|
|
},
|
|
want: `{
|
|
"boolToUint32": {
|
|
"false": 101,
|
|
"true": 42
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "map fields 2",
|
|
input: &pb3.Maps{
|
|
Int32ToStr: map[int32]string{
|
|
-101: "-101",
|
|
0xff: "0xff",
|
|
0: "zero",
|
|
},
|
|
},
|
|
want: `{
|
|
"int32ToStr": {
|
|
"-101": "-101",
|
|
"0": "zero",
|
|
"255": "0xff"
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "map fields 3",
|
|
input: &pb3.Maps{
|
|
Uint64ToEnum: map[uint64]pb3.Enum{
|
|
1: pb3.Enum_ONE,
|
|
2: pb3.Enum_TWO,
|
|
10: pb3.Enum_TEN,
|
|
47: 47,
|
|
},
|
|
},
|
|
want: `{
|
|
"uint64ToEnum": {
|
|
"1": "ONE",
|
|
"2": "TWO",
|
|
"10": "TEN",
|
|
"47": 47
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "map fields 4",
|
|
input: &pb3.Maps{
|
|
StrToNested: map[string]*pb3.Nested{
|
|
"nested": &pb3.Nested{
|
|
SString: "nested in a map",
|
|
},
|
|
},
|
|
},
|
|
want: `{
|
|
"strToNested": {
|
|
"nested": {
|
|
"sString": "nested in a map"
|
|
}
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "map fields 5",
|
|
input: &pb3.Maps{
|
|
StrToOneofs: map[string]*pb3.Oneofs{
|
|
"string": &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofString{
|
|
OneofString: "hello",
|
|
},
|
|
},
|
|
"nested": &pb3.Oneofs{
|
|
Union: &pb3.Oneofs_OneofNested{
|
|
OneofNested: &pb3.Nested{
|
|
SString: "nested oneof in map field value",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: `{
|
|
"strToOneofs": {
|
|
"nested": {
|
|
"oneofNested": {
|
|
"sString": "nested oneof in map field value"
|
|
}
|
|
},
|
|
"string": {
|
|
"oneofString": "hello"
|
|
}
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "map field contains nil value",
|
|
input: &pb3.Maps{
|
|
StrToNested: map[string]*pb3.Nested{
|
|
"nil": nil,
|
|
},
|
|
},
|
|
want: `{
|
|
"strToNested": {
|
|
"nil": {}
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "unknown fields are ignored",
|
|
input: &pb2.Scalars{
|
|
OptString: scalar.String("no unknowns"),
|
|
XXX_unrecognized: pack.Message{
|
|
pack.Tag{101, pack.BytesType}, pack.String("hello world"),
|
|
}.Marshal(),
|
|
},
|
|
want: `{
|
|
"optString": "no unknowns"
|
|
}`,
|
|
}, {
|
|
desc: "json_name",
|
|
input: &pb3.JSONNames{
|
|
SString: "json_name",
|
|
},
|
|
want: `{
|
|
"foo_bar": "json_name"
|
|
}`,
|
|
}, {
|
|
desc: "extensions of non-repeated fields",
|
|
input: func() proto.Message {
|
|
m := &pb2.Extensions{
|
|
OptString: scalar.String("non-extension field"),
|
|
OptBool: scalar.Bool(true),
|
|
OptInt32: scalar.Int32(42),
|
|
}
|
|
setExtension(m, pb2.E_OptExtBool, true)
|
|
setExtension(m, pb2.E_OptExtString, "extension field")
|
|
setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
|
|
setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
|
|
OptString: scalar.String("nested in an extension"),
|
|
OptNested: &pb2.Nested{
|
|
OptString: scalar.String("another nested in an extension"),
|
|
},
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"optString": "non-extension field",
|
|
"optBool": true,
|
|
"optInt32": 42,
|
|
"[pb2.opt_ext_bool]": true,
|
|
"[pb2.opt_ext_enum]": "TEN",
|
|
"[pb2.opt_ext_nested]": {
|
|
"optString": "nested in an extension",
|
|
"optNested": {
|
|
"optString": "another nested in an extension"
|
|
}
|
|
},
|
|
"[pb2.opt_ext_string]": "extension field"
|
|
}`,
|
|
}, {
|
|
desc: "extension message field set to nil",
|
|
input: func() proto.Message {
|
|
m := &pb2.Extensions{}
|
|
setExtension(m, pb2.E_OptExtNested, nil)
|
|
return m
|
|
}(),
|
|
want: "{}",
|
|
}, {
|
|
desc: "extensions of repeated fields",
|
|
input: func() proto.Message {
|
|
m := &pb2.Extensions{}
|
|
setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
|
|
setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
|
|
setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
|
|
&pb2.Nested{OptString: scalar.String("one")},
|
|
&pb2.Nested{OptString: scalar.String("two")},
|
|
&pb2.Nested{OptString: scalar.String("three")},
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"[pb2.rpt_ext_enum]": [
|
|
"TEN",
|
|
101,
|
|
"ONE"
|
|
],
|
|
"[pb2.rpt_ext_fixed32]": [
|
|
42,
|
|
47
|
|
],
|
|
"[pb2.rpt_ext_nested]": [
|
|
{
|
|
"optString": "one"
|
|
},
|
|
{
|
|
"optString": "two"
|
|
},
|
|
{
|
|
"optString": "three"
|
|
}
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "extensions of non-repeated fields in another message",
|
|
input: func() proto.Message {
|
|
m := &pb2.Extensions{}
|
|
setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
|
|
setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
|
|
setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
|
|
setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
|
|
OptString: scalar.String("nested in an extension"),
|
|
OptNested: &pb2.Nested{
|
|
OptString: scalar.String("another nested in an extension"),
|
|
},
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"[pb2.ExtensionsContainer.opt_ext_bool]": true,
|
|
"[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
|
|
"[pb2.ExtensionsContainer.opt_ext_nested]": {
|
|
"optString": "nested in an extension",
|
|
"optNested": {
|
|
"optString": "another nested in an extension"
|
|
}
|
|
},
|
|
"[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
|
|
}`,
|
|
}, {
|
|
desc: "extensions of repeated fields in another message",
|
|
input: func() proto.Message {
|
|
m := &pb2.Extensions{
|
|
OptString: scalar.String("non-extension field"),
|
|
OptBool: scalar.Bool(true),
|
|
OptInt32: scalar.Int32(42),
|
|
}
|
|
setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
|
|
setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
|
|
setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
|
|
&pb2.Nested{OptString: scalar.String("one")},
|
|
&pb2.Nested{OptString: scalar.String("two")},
|
|
&pb2.Nested{OptString: scalar.String("three")},
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"optString": "non-extension field",
|
|
"optBool": true,
|
|
"optInt32": 42,
|
|
"[pb2.ExtensionsContainer.rpt_ext_enum]": [
|
|
"TEN",
|
|
101,
|
|
"ONE"
|
|
],
|
|
"[pb2.ExtensionsContainer.rpt_ext_nested]": [
|
|
{
|
|
"optString": "one"
|
|
},
|
|
{
|
|
"optString": "two"
|
|
},
|
|
{
|
|
"optString": "three"
|
|
}
|
|
],
|
|
"[pb2.ExtensionsContainer.rpt_ext_string]": [
|
|
"hello",
|
|
"world"
|
|
]
|
|
}`,
|
|
}, {
|
|
desc: "MessageSet",
|
|
input: func() proto.Message {
|
|
m := &pb2.MessageSet{}
|
|
setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
|
|
OptString: scalar.String("a messageset extension"),
|
|
})
|
|
setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
|
|
OptString: scalar.String("not a messageset extension"),
|
|
})
|
|
setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
|
|
OptString: scalar.String("just a regular extension"),
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"[pb2.MessageSetExtension]": {
|
|
"optString": "a messageset extension"
|
|
},
|
|
"[pb2.MessageSetExtension.ext_nested]": {
|
|
"optString": "just a regular extension"
|
|
},
|
|
"[pb2.MessageSetExtension.not_message_set_extension]": {
|
|
"optString": "not a messageset extension"
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "not real MessageSet 1",
|
|
input: func() proto.Message {
|
|
m := &pb2.FakeMessageSet{}
|
|
setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
|
|
OptString: scalar.String("not a messageset extension"),
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"[pb2.FakeMessageSetExtension.message_set_extension]": {
|
|
"optString": "not a messageset extension"
|
|
}
|
|
}`,
|
|
}, {
|
|
desc: "not real MessageSet 2",
|
|
input: func() proto.Message {
|
|
m := &pb2.MessageSet{}
|
|
setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
|
|
OptString: scalar.String("another not a messageset extension"),
|
|
})
|
|
return m
|
|
}(),
|
|
want: `{
|
|
"[pb2.message_set_extension]": {
|
|
"optString": "another not a messageset extension"
|
|
}
|
|
}`,
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
b, err := tt.mo.Marshal(tt.input)
|
|
if err != nil {
|
|
t.Errorf("Marshal() returned error: %v\n", err)
|
|
}
|
|
got := string(b)
|
|
if got != tt.want {
|
|
t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
|
|
if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
|
|
t.Errorf("Marshal() diff -want +got\n%v\n", diff)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|