diff options
Diffstat (limited to 'encoding/protojson/encode_test.go')
-rw-r--r-- | encoding/protojson/encode_test.go | 2312 |
1 files changed, 0 insertions, 2312 deletions
diff --git a/encoding/protojson/encode_test.go b/encoding/protojson/encode_test.go deleted file mode 100644 index f1a05fe1..00000000 --- a/encoding/protojson/encode_test.go +++ /dev/null @@ -1,2312 +0,0 @@ -// 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 protojson_test - -import ( - "bytes" - "math" - "testing" - - "github.com/google/go-cmp/cmp" - - "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/internal/detrand" - "google.golang.org/protobuf/internal/flags" - "google.golang.org/protobuf/proto" - preg "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/testing/protopack" - - pb2 "google.golang.org/protobuf/internal/testprotos/textpb2" - pb3 "google.golang.org/protobuf/internal/testprotos/textpb3" - "google.golang.org/protobuf/types/known/anypb" - "google.golang.org/protobuf/types/known/durationpb" - "google.golang.org/protobuf/types/known/emptypb" - "google.golang.org/protobuf/types/known/fieldmaskpb" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" - "google.golang.org/protobuf/types/known/wrapperspb" -) - -// Disable detrand to enable direct comparisons on outputs. -func init() { detrand.Disable() } - -func TestMarshal(t *testing.T) { - tests := []struct { - desc string - mo protojson.MarshalOptions - input proto.Message - want string - wantErr bool // TODO: Verify error message substring. - skip bool - }{{ - desc: "proto2 optional scalars not set", - input: &pb2.Scalars{}, - want: "{}", - }, { - desc: "proto3 scalars not set", - input: &pb3.Scalars{}, - want: "{}", - }, { - desc: "proto3 optional not set", - input: &pb3.Proto3Optional{}, - want: "{}", - }, { - desc: "proto2 optional scalars set to zero values", - input: &pb2.Scalars{ - OptBool: proto.Bool(false), - OptInt32: proto.Int32(0), - OptInt64: proto.Int64(0), - OptUint32: proto.Uint32(0), - OptUint64: proto.Uint64(0), - OptSint32: proto.Int32(0), - OptSint64: proto.Int64(0), - OptFixed32: proto.Uint32(0), - OptFixed64: proto.Uint64(0), - OptSfixed32: proto.Int32(0), - OptSfixed64: proto.Int64(0), - OptFloat: proto.Float32(0), - OptDouble: proto.Float64(0), - OptBytes: []byte{}, - OptString: proto.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: "proto3 optional set to zero values", - input: &pb3.Proto3Optional{ - OptBool: proto.Bool(false), - OptInt32: proto.Int32(0), - OptInt64: proto.Int64(0), - OptUint32: proto.Uint32(0), - OptUint64: proto.Uint64(0), - OptFloat: proto.Float32(0), - OptDouble: proto.Float64(0), - OptString: proto.String(""), - OptBytes: []byte{}, - OptEnum: pb3.Enum_ZERO.Enum(), - OptMessage: &pb3.Nested{}, - }, - want: `{ - "optBool": false, - "optInt32": 0, - "optInt64": "0", - "optUint32": 0, - "optUint64": "0", - "optFloat": 0, - "optDouble": 0, - "optString": "", - "optBytes": "", - "optEnum": "ZERO", - "optMessage": {} -}`, - }, { - desc: "proto2 optional scalars set to some values", - input: &pb2.Scalars{ - OptBool: proto.Bool(true), - OptInt32: proto.Int32(0xff), - OptInt64: proto.Int64(0xdeadbeef), - OptUint32: proto.Uint32(47), - OptUint64: proto.Uint64(0xdeadbeef), - OptSint32: proto.Int32(-1001), - OptSint64: proto.Int64(-0xffff), - OptFixed64: proto.Uint64(64), - OptSfixed32: proto.Int32(-32), - OptFloat: proto.Float32(1.02), - OptDouble: proto.Float64(1.234), - OptBytes: []byte("谷歌"), - OptString: proto.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: "string", - input: &pb3.Scalars{ - SString: "谷歌", - }, - want: `{ - "sString": "谷歌" -}`, - }, { - desc: "string with invalid UTF8", - input: &pb3.Scalars{ - SString: "abc\xff", - }, - wantErr: true, - }, { - 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: pb2.Enum(0).Enum(), - OptNestedEnum: pb2.Enums_NestedEnum(0).Enum(), - }, - 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: pb2.Enum(2).Enum(), - OptNestedEnum: pb2.Enums_NestedEnum(2).Enum(), - }, - want: `{ - "optEnum": "TWO", - "optNestedEnum": "DOS" -}`, - }, { - desc: "proto2 enum set to unnamed numeric values", - input: &pb2.Enums{ - OptEnum: pb2.Enum(101).Enum(), - OptNestedEnum: pb2.Enums_NestedEnum(-101).Enum(), - }, - 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: proto.String("nested message"), - OptNested: &pb2.Nested{ - OptString: proto.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: proto.String("inside a group"), - OptNested: &pb2.Nested{ - OptString: proto.String("nested message inside a group"), - }, - Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{ - OptFixed32: proto.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: proto.String("repeat nested one"), - }, - { - OptString: proto.String("repeat nested two"), - OptNested: &pb2.Nested{ - OptString: proto.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: "required fields not set", - input: &pb2.Requireds{}, - want: `{}`, - wantErr: true, - }, { - desc: "required fields partially set", - input: &pb2.Requireds{ - ReqBool: proto.Bool(false), - ReqSfixed64: proto.Int64(0), - ReqDouble: proto.Float64(1.23), - ReqString: proto.String("hello"), - ReqEnum: pb2.Enum_ONE.Enum(), - }, - want: `{ - "reqBool": false, - "reqSfixed64": "0", - "reqDouble": 1.23, - "reqString": "hello", - "reqEnum": "ONE" -}`, - wantErr: true, - }, { - desc: "required fields not set with AllowPartial", - mo: protojson.MarshalOptions{AllowPartial: true}, - input: &pb2.Requireds{ - ReqBool: proto.Bool(false), - ReqSfixed64: proto.Int64(0), - ReqDouble: proto.Float64(1.23), - ReqString: proto.String("hello"), - ReqEnum: pb2.Enum_ONE.Enum(), - }, - want: `{ - "reqBool": false, - "reqSfixed64": "0", - "reqDouble": 1.23, - "reqString": "hello", - "reqEnum": "ONE" -}`, - }, { - desc: "required fields all set", - input: &pb2.Requireds{ - ReqBool: proto.Bool(false), - ReqSfixed64: proto.Int64(0), - ReqDouble: proto.Float64(1.23), - ReqString: proto.String("hello"), - ReqEnum: pb2.Enum_ONE.Enum(), - ReqNested: &pb2.Nested{}, - }, - want: `{ - "reqBool": false, - "reqSfixed64": "0", - "reqDouble": 1.23, - "reqString": "hello", - "reqEnum": "ONE", - "reqNested": {} -}`, - }, { - desc: "indirect required field", - input: &pb2.IndirectRequired{ - OptNested: &pb2.NestedWithRequired{}, - }, - want: `{ - "optNested": {} -}`, - wantErr: true, - }, { - desc: "indirect required field with AllowPartial", - mo: protojson.MarshalOptions{AllowPartial: true}, - input: &pb2.IndirectRequired{ - OptNested: &pb2.NestedWithRequired{}, - }, - want: `{ - "optNested": {} -}`, - }, { - desc: "indirect required field in empty repeated", - input: &pb2.IndirectRequired{ - RptNested: []*pb2.NestedWithRequired{}, - }, - want: `{}`, - }, { - desc: "indirect required field in repeated", - input: &pb2.IndirectRequired{ - RptNested: []*pb2.NestedWithRequired{ - &pb2.NestedWithRequired{}, - }, - }, - want: `{ - "rptNested": [ - {} - ] -}`, - wantErr: true, - }, { - desc: "indirect required field in repeated with AllowPartial", - mo: protojson.MarshalOptions{AllowPartial: true}, - input: &pb2.IndirectRequired{ - RptNested: []*pb2.NestedWithRequired{ - &pb2.NestedWithRequired{}, - }, - }, - want: `{ - "rptNested": [ - {} - ] -}`, - }, { - desc: "indirect required field in empty map", - input: &pb2.IndirectRequired{ - StrToNested: map[string]*pb2.NestedWithRequired{}, - }, - want: "{}", - }, { - desc: "indirect required field in map", - input: &pb2.IndirectRequired{ - StrToNested: map[string]*pb2.NestedWithRequired{ - "fail": &pb2.NestedWithRequired{}, - }, - }, - want: `{ - "strToNested": { - "fail": {} - } -}`, - wantErr: true, - }, { - desc: "indirect required field in map with AllowPartial", - mo: protojson.MarshalOptions{AllowPartial: true}, - input: &pb2.IndirectRequired{ - StrToNested: map[string]*pb2.NestedWithRequired{ - "fail": &pb2.NestedWithRequired{}, - }, - }, - want: `{ - "strToNested": { - "fail": {} - } -}`, - }, { - desc: "indirect required field in oneof", - input: &pb2.IndirectRequired{ - Union: &pb2.IndirectRequired_OneofNested{ - OneofNested: &pb2.NestedWithRequired{}, - }, - }, - want: `{ - "oneofNested": {} -}`, - wantErr: true, - }, { - desc: "indirect required field in oneof with AllowPartial", - mo: protojson.MarshalOptions{AllowPartial: true}, - input: &pb2.IndirectRequired{ - Union: &pb2.IndirectRequired_OneofNested{ - OneofNested: &pb2.NestedWithRequired{}, - }, - }, - want: `{ - "oneofNested": {} -}`, - }, { - desc: "unknown fields are ignored", - input: func() proto.Message { - m := &pb2.Scalars{ - OptString: proto.String("no unknowns"), - } - m.ProtoReflect().SetUnknown(protopack.Message{ - protopack.Tag{101, protopack.BytesType}, protopack.String("hello world"), - }.Marshal()) - return m - }(), - 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: proto.String("non-extension field"), - OptBool: proto.Bool(true), - OptInt32: proto.Int32(42), - } - proto.SetExtension(m, pb2.E_OptExtBool, true) - proto.SetExtension(m, pb2.E_OptExtString, "extension field") - proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN) - proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{ - OptString: proto.String("nested in an extension"), - OptNested: &pb2.Nested{ - OptString: proto.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: "extensions of repeated fields", - input: func() proto.Message { - m := &pb2.Extensions{} - proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE}) - proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47}) - proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{ - &pb2.Nested{OptString: proto.String("one")}, - &pb2.Nested{OptString: proto.String("two")}, - &pb2.Nested{OptString: proto.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{} - proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true) - proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field") - proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN) - proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{ - OptString: proto.String("nested in an extension"), - OptNested: &pb2.Nested{ - OptString: proto.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: proto.String("non-extension field"), - OptBool: proto.Bool(true), - OptInt32: proto.Int32(42), - } - proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE}) - proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"}) - proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{ - &pb2.Nested{OptString: proto.String("one")}, - &pb2.Nested{OptString: proto.String("two")}, - &pb2.Nested{OptString: proto.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{} - proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{ - OptString: proto.String("a messageset extension"), - }) - proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{ - OptString: proto.String("not a messageset extension"), - }) - proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{ - OptString: proto.String("just a regular extension"), - }) - return m - }(), - want: `{ - "[pb2.MessageSetExtension.ext_nested]": { - "optString": "just a regular extension" - }, - "[pb2.MessageSetExtension]": { - "optString": "a messageset extension" - }, - "[pb2.MessageSetExtension.not_message_set_extension]": { - "optString": "not a messageset extension" - } -}`, - skip: !flags.ProtoLegacy, - }, { - desc: "not real MessageSet 1", - input: func() proto.Message { - m := &pb2.FakeMessageSet{} - proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{ - OptString: proto.String("not a messageset extension"), - }) - return m - }(), - want: `{ - "[pb2.FakeMessageSetExtension.message_set_extension]": { - "optString": "not a messageset extension" - } -}`, - skip: !flags.ProtoLegacy, - }, { - desc: "not real MessageSet 2", - input: func() proto.Message { - m := &pb2.MessageSet{} - proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{ - OptString: proto.String("another not a messageset extension"), - }) - return m - }(), - want: `{ - "[pb2.message_set_extension]": { - "optString": "another not a messageset extension" - } -}`, - skip: !flags.ProtoLegacy, - }, { - desc: "BoolValue empty", - input: &wrapperspb.BoolValue{}, - want: `false`, - }, { - desc: "BoolValue", - input: &wrapperspb.BoolValue{Value: true}, - want: `true`, - }, { - desc: "Int32Value empty", - input: &wrapperspb.Int32Value{}, - want: `0`, - }, { - desc: "Int32Value", - input: &wrapperspb.Int32Value{Value: 42}, - want: `42`, - }, { - desc: "Int64Value", - input: &wrapperspb.Int64Value{Value: 42}, - want: `"42"`, - }, { - desc: "UInt32Value", - input: &wrapperspb.UInt32Value{Value: 42}, - want: `42`, - }, { - desc: "UInt64Value", - input: &wrapperspb.UInt64Value{Value: 42}, - want: `"42"`, - }, { - desc: "FloatValue", - input: &wrapperspb.FloatValue{Value: 1.02}, - want: `1.02`, - }, { - desc: "FloatValue Infinity", - input: &wrapperspb.FloatValue{Value: float32(math.Inf(-1))}, - want: `"-Infinity"`, - }, { - desc: "DoubleValue", - input: &wrapperspb.DoubleValue{Value: 1.02}, - want: `1.02`, - }, { - desc: "DoubleValue NaN", - input: &wrapperspb.DoubleValue{Value: math.NaN()}, - want: `"NaN"`, - }, { - desc: "StringValue empty", - input: &wrapperspb.StringValue{}, - want: `""`, - }, { - desc: "StringValue", - input: &wrapperspb.StringValue{Value: "谷歌"}, - want: `"谷歌"`, - }, { - desc: "StringValue with invalid UTF8 error", - input: &wrapperspb.StringValue{Value: "abc\xff"}, - wantErr: true, - }, { - desc: "StringValue field with invalid UTF8 error", - input: &pb2.KnownTypes{ - OptString: &wrapperspb.StringValue{Value: "abc\xff"}, - }, - wantErr: true, - }, { - desc: "BytesValue", - input: &wrapperspb.BytesValue{Value: []byte("hello")}, - want: `"aGVsbG8="`, - }, { - desc: "Empty", - input: &emptypb.Empty{}, - want: `{}`, - }, { - desc: "NullValue field", - input: &pb2.KnownTypes{OptNull: new(structpb.NullValue)}, - want: `{ - "optNull": null -}`, - }, { - desc: "Value empty", - input: &structpb.Value{}, - wantErr: true, - }, { - desc: "Value empty field", - input: &pb2.KnownTypes{ - OptValue: &structpb.Value{}, - }, - wantErr: true, - }, { - desc: "Value contains NullValue", - input: &structpb.Value{Kind: &structpb.Value_NullValue{}}, - want: `null`, - }, { - desc: "Value contains BoolValue", - input: &structpb.Value{Kind: &structpb.Value_BoolValue{}}, - want: `false`, - }, { - desc: "Value contains NumberValue", - input: &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}}, - want: `1.02`, - }, { - desc: "Value contains StringValue", - input: &structpb.Value{Kind: &structpb.Value_StringValue{"hello"}}, - want: `"hello"`, - }, { - desc: "Value contains StringValue with invalid UTF8", - input: &structpb.Value{Kind: &structpb.Value_StringValue{"\xff"}}, - wantErr: true, - }, { - desc: "Value contains Struct", - input: &structpb.Value{ - Kind: &structpb.Value_StructValue{ - &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "null": {Kind: &structpb.Value_NullValue{}}, - "number": {Kind: &structpb.Value_NumberValue{}}, - "string": {Kind: &structpb.Value_StringValue{}}, - "struct": {Kind: &structpb.Value_StructValue{}}, - "list": {Kind: &structpb.Value_ListValue{}}, - "bool": {Kind: &structpb.Value_BoolValue{}}, - }, - }, - }, - }, - want: `{ - "bool": false, - "list": [], - "null": null, - "number": 0, - "string": "", - "struct": {} -}`, - }, { - desc: "Value contains ListValue", - input: &structpb.Value{ - Kind: &structpb.Value_ListValue{ - &structpb.ListValue{ - Values: []*structpb.Value{ - {Kind: &structpb.Value_BoolValue{}}, - {Kind: &structpb.Value_NullValue{}}, - {Kind: &structpb.Value_NumberValue{}}, - {Kind: &structpb.Value_StringValue{}}, - {Kind: &structpb.Value_StructValue{}}, - {Kind: &structpb.Value_ListValue{}}, - }, - }, - }, - }, - want: `[ - false, - null, - 0, - "", - {}, - [] -]`, - }, { - desc: "Value with NaN", - input: structpb.NewNumberValue(math.NaN()), - wantErr: true, - }, { - desc: "Value with -Inf", - input: structpb.NewNumberValue(math.Inf(-1)), - wantErr: true, - }, { - desc: "Value with +Inf", - input: structpb.NewNumberValue(math.Inf(+1)), - wantErr: true, - }, { - desc: "Struct with nil map", - input: &structpb.Struct{}, - want: `{}`, - }, { - desc: "Struct with empty map", - input: &structpb.Struct{ - Fields: map[string]*structpb.Value{}, - }, - want: `{}`, - }, { - desc: "Struct", - input: &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "bool": {Kind: &structpb.Value_BoolValue{true}}, - "null": {Kind: &structpb.Value_NullValue{}}, - "number": {Kind: &structpb.Value_NumberValue{3.1415}}, - "string": {Kind: &structpb.Value_StringValue{"hello"}}, - "struct": { - Kind: &structpb.Value_StructValue{ - &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "string": {Kind: &structpb.Value_StringValue{"world"}}, - }, - }, - }, - }, - "list": { - Kind: &structpb.Value_ListValue{ - &structpb.ListValue{ - Values: []*structpb.Value{ - {Kind: &structpb.Value_BoolValue{}}, - {Kind: &structpb.Value_NullValue{}}, - {Kind: &structpb.Value_NumberValue{}}, - }, - }, - }, - }, - }, - }, - want: `{ - "bool": true, - "list": [ - false, - null, - 0 - ], - "null": null, - "number": 3.1415, - "string": "hello", - "struct": { - "string": "world" - } -}`, - }, { - desc: "Struct message with invalid UTF8 string", - input: &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "string": {Kind: &structpb.Value_StringValue{"\xff"}}, - }, - }, - wantErr: true, - }, { - desc: "ListValue with nil values", - input: &structpb.ListValue{}, - want: `[]`, - }, { - desc: "ListValue with empty values", - input: &structpb.ListValue{ - Values: []*structpb.Value{}, - }, - want: `[]`, - }, { - desc: "ListValue", - input: &structpb.ListValue{ - Values: []*structpb.Value{ - {Kind: &structpb.Value_BoolValue{true}}, - {Kind: &structpb.Value_NullValue{}}, - {Kind: &structpb.Value_NumberValue{3.1415}}, - {Kind: &structpb.Value_StringValue{"hello"}}, - { - Kind: &structpb.Value_ListValue{ - &structpb.ListValue{ - Values: []*structpb.Value{ - {Kind: &structpb.Value_BoolValue{}}, - {Kind: &structpb.Value_NullValue{}}, - {Kind: &structpb.Value_NumberValue{}}, - }, - }, - }, - }, - { - Kind: &structpb.Value_StructValue{ - &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "string": {Kind: &structpb.Value_StringValue{"world"}}, - }, - }, - }, - }, - }, - }, - want: `[ - true, - null, - 3.1415, - "hello", - [ - false, - null, - 0 - ], - { - "string": "world" - } -]`, - }, { - desc: "ListValue with invalid UTF8 string", - input: &structpb.ListValue{ - Values: []*structpb.Value{ - {Kind: &structpb.Value_StringValue{"\xff"}}, - }, - }, - wantErr: true, - }, { - desc: "Duration empty", - input: &durationpb.Duration{}, - want: `"0s"`, - }, { - desc: "Duration with secs", - input: &durationpb.Duration{Seconds: 3}, - want: `"3s"`, - }, { - desc: "Duration with -secs", - input: &durationpb.Duration{Seconds: -3}, - want: `"-3s"`, - }, { - desc: "Duration with nanos", - input: &durationpb.Duration{Nanos: 1e6}, - want: `"0.001s"`, - }, { - desc: "Duration with -nanos", - input: &durationpb.Duration{Nanos: -1e6}, - want: `"-0.001s"`, - }, { - desc: "Duration with large secs", - input: &durationpb.Duration{Seconds: 1e10, Nanos: 1}, - want: `"10000000000.000000001s"`, - }, { - desc: "Duration with 6-digit nanos", - input: &durationpb.Duration{Nanos: 1e4}, - want: `"0.000010s"`, - }, { - desc: "Duration with 3-digit nanos", - input: &durationpb.Duration{Nanos: 1e6}, - want: `"0.001s"`, - }, { - desc: "Duration with -secs -nanos", - input: &durationpb.Duration{Seconds: -123, Nanos: -450}, - want: `"-123.000000450s"`, - }, { - desc: "Duration max value", - input: &durationpb.Duration{Seconds: 315576000000, Nanos: 999999999}, - want: `"315576000000.999999999s"`, - }, { - desc: "Duration min value", - input: &durationpb.Duration{Seconds: -315576000000, Nanos: -999999999}, - want: `"-315576000000.999999999s"`, - }, { - desc: "Duration with +secs -nanos", - input: &durationpb.Duration{Seconds: 1, Nanos: -1}, - wantErr: true, - }, { - desc: "Duration with -secs +nanos", - input: &durationpb.Duration{Seconds: -1, Nanos: 1}, - wantErr: true, - }, { - desc: "Duration with +secs out of range", - input: &durationpb.Duration{Seconds: 315576000001}, - wantErr: true, - }, { - desc: "Duration with -secs out of range", - input: &durationpb.Duration{Seconds: -315576000001}, - wantErr: true, - }, { - desc: "Duration with +nanos out of range", - input: &durationpb.Duration{Seconds: 0, Nanos: 1e9}, - wantErr: true, - }, { - desc: "Duration with -nanos out of range", - input: &durationpb.Duration{Seconds: 0, Nanos: -1e9}, - wantErr: true, - }, { - desc: "Timestamp zero", - input: ×tamppb.Timestamp{}, - want: `"1970-01-01T00:00:00Z"`, - }, { - desc: "Timestamp", - input: ×tamppb.Timestamp{Seconds: 1553036601}, - want: `"2019-03-19T23:03:21Z"`, - }, { - desc: "Timestamp with nanos", - input: ×tamppb.Timestamp{Seconds: 1553036601, Nanos: 1}, - want: `"2019-03-19T23:03:21.000000001Z"`, - }, { - desc: "Timestamp with 6-digit nanos", - input: ×tamppb.Timestamp{Nanos: 1e3}, - want: `"1970-01-01T00:00:00.000001Z"`, - }, { - desc: "Timestamp with 3-digit nanos", - input: ×tamppb.Timestamp{Nanos: 1e7}, - want: `"1970-01-01T00:00:00.010Z"`, - }, { - desc: "Timestamp max value", - input: ×tamppb.Timestamp{Seconds: 253402300799, Nanos: 999999999}, - want: `"9999-12-31T23:59:59.999999999Z"`, - }, { - desc: "Timestamp min value", - input: ×tamppb.Timestamp{Seconds: -62135596800}, - want: `"0001-01-01T00:00:00Z"`, - }, { - desc: "Timestamp with +secs out of range", - input: ×tamppb.Timestamp{Seconds: 253402300800}, - wantErr: true, - }, { - desc: "Timestamp with -secs out of range", - input: ×tamppb.Timestamp{Seconds: -62135596801}, - wantErr: true, - }, { - desc: "Timestamp with -nanos", - input: ×tamppb.Timestamp{Nanos: -1}, - wantErr: true, - }, { - desc: "Timestamp with +nanos out of range", - input: ×tamppb.Timestamp{Nanos: 1e9}, - wantErr: true, - }, { - desc: "FieldMask empty", - input: &fieldmaskpb.FieldMask{}, - want: `""`, - }, { - desc: "FieldMask", - input: &fieldmaskpb.FieldMask{ - Paths: []string{ - "foo", - "foo_bar", - "foo.bar_qux", - "_foo", - }, - }, - want: `"foo,fooBar,foo.barQux,Foo"`, - }, { - desc: "FieldMask empty string path", - input: &fieldmaskpb.FieldMask{ - Paths: []string{""}, - }, - wantErr: true, - }, { - desc: "FieldMask path contains spaces only", - input: &fieldmaskpb.FieldMask{ - Paths: []string{" "}, - }, - wantErr: true, - }, { - desc: "FieldMask irreversible error 1", - input: &fieldmaskpb.FieldMask{ - Paths: []string{"foo_"}, - }, - wantErr: true, - }, { - desc: "FieldMask irreversible error 2", - input: &fieldmaskpb.FieldMask{ - Paths: []string{"foo__bar"}, - }, - wantErr: true, - }, { - desc: "FieldMask invalid char", - input: &fieldmaskpb.FieldMask{ - Paths: []string{"foo@bar"}, - }, - wantErr: true, - }, { - desc: "Any empty", - input: &anypb.Any{}, - want: `{}`, - }, { - desc: "Any with non-custom message", - input: func() proto.Message { - m := &pb2.Nested{ - OptString: proto.String("embedded inside Any"), - OptNested: &pb2.Nested{ - OptString: proto.String("inception"), - }, - } - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "foo/pb2.Nested", - Value: b, - } - }(), - want: `{ - "@type": "foo/pb2.Nested", - "optString": "embedded inside Any", - "optNested": { - "optString": "inception" - } -}`, - }, { - desc: "Any with empty embedded message", - input: &anypb.Any{TypeUrl: "foo/pb2.Nested"}, - want: `{ - "@type": "foo/pb2.Nested" -}`, - }, { - desc: "Any without registered type", - mo: protojson.MarshalOptions{Resolver: new(preg.Types)}, - input: &anypb.Any{TypeUrl: "foo/pb2.Nested"}, - wantErr: true, - }, { - desc: "Any with missing required", - input: func() proto.Message { - m := &pb2.PartialRequired{ - OptString: proto.String("embedded inside Any"), - } - b, err := proto.MarshalOptions{ - AllowPartial: true, - Deterministic: true, - }.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: string(m.ProtoReflect().Descriptor().FullName()), - Value: b, - } - }(), - want: `{ - "@type": "pb2.PartialRequired", - "optString": "embedded inside Any" -}`, - }, { - desc: "Any with partial required and AllowPartial", - mo: protojson.MarshalOptions{ - AllowPartial: true, - }, - input: func() proto.Message { - m := &pb2.PartialRequired{ - OptString: proto.String("embedded inside Any"), - } - b, err := proto.MarshalOptions{ - AllowPartial: true, - Deterministic: true, - }.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: string(m.ProtoReflect().Descriptor().FullName()), - Value: b, - } - }(), - want: `{ - "@type": "pb2.PartialRequired", - "optString": "embedded inside Any" -}`, - }, { - desc: "Any with EmitUnpopulated", - mo: protojson.MarshalOptions{ - EmitUnpopulated: true, - }, - input: func() proto.Message { - return &anypb.Any{ - TypeUrl: string(new(pb3.Scalars).ProtoReflect().Descriptor().FullName()), - } - }(), - want: `{ - "@type": "pb3.Scalars", - "sBool": false, - "sInt32": 0, - "sInt64": "0", - "sUint32": 0, - "sUint64": "0", - "sSint32": 0, - "sSint64": "0", - "sFixed32": 0, - "sFixed64": "0", - "sSfixed32": 0, - "sSfixed64": "0", - "sFloat": 0, - "sDouble": 0, - "sBytes": "", - "sString": "" -}`, - }, { - desc: "Any with invalid UTF8", - input: func() proto.Message { - m := &pb2.Nested{ - OptString: proto.String("abc\xff"), - } - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "foo/pb2.Nested", - Value: b, - } - }(), - wantErr: true, - }, { - desc: "Any with invalid value", - input: &anypb.Any{ - TypeUrl: "foo/pb2.Nested", - Value: []byte("\x80"), - }, - wantErr: true, - }, { - desc: "Any with BoolValue", - input: func() proto.Message { - m := &wrapperspb.BoolValue{Value: true} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "type.googleapis.com/google.protobuf.BoolValue", - Value: b, - } - }(), - want: `{ - "@type": "type.googleapis.com/google.protobuf.BoolValue", - "value": true -}`, - }, { - desc: "Any with Empty", - input: func() proto.Message { - m := &emptypb.Empty{} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "type.googleapis.com/google.protobuf.Empty", - Value: b, - } - }(), - want: `{ - "@type": "type.googleapis.com/google.protobuf.Empty", - "value": {} -}`, - }, { - desc: "Any with StringValue containing invalid UTF8", - input: func() proto.Message { - m := &wrapperspb.StringValue{Value: "abcd"} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "google.protobuf.StringValue", - Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1), - } - }(), - wantErr: true, - }, { - desc: "Any with Int64Value", - input: func() proto.Message { - m := &wrapperspb.Int64Value{Value: 42} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "google.protobuf.Int64Value", - Value: b, - } - }(), - want: `{ - "@type": "google.protobuf.Int64Value", - "value": "42" -}`, - }, { - desc: "Any with Duration", - input: func() proto.Message { - m := &durationpb.Duration{} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "type.googleapis.com/google.protobuf.Duration", - Value: b, - } - }(), - want: `{ - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "0s" -}`, - }, { - desc: "Any with empty Value", - input: func() proto.Message { - m := &structpb.Value{} - b, err := proto.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "type.googleapis.com/google.protobuf.Value", - Value: b, - } - }(), - wantErr: true, - }, { - desc: "Any with Value of StringValue", - input: func() proto.Message { - m := &structpb.Value{Kind: &structpb.Value_StringValue{"abcd"}} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "type.googleapis.com/google.protobuf.Value", - Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1), - } - }(), - wantErr: true, - }, { - desc: "Any with Value of NullValue", - input: func() proto.Message { - m := &structpb.Value{Kind: &structpb.Value_NullValue{}} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "type.googleapis.com/google.protobuf.Value", - Value: b, - } - }(), - want: `{ - "@type": "type.googleapis.com/google.protobuf.Value", - "value": null -}`, - }, { - desc: "Any with Struct", - input: func() proto.Message { - m := &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "bool": {Kind: &structpb.Value_BoolValue{true}}, - "null": {Kind: &structpb.Value_NullValue{}}, - "string": {Kind: &structpb.Value_StringValue{"hello"}}, - "struct": { - Kind: &structpb.Value_StructValue{ - &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "string": {Kind: &structpb.Value_StringValue{"world"}}, - }, - }, - }, - }, - }, - } - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - TypeUrl: "google.protobuf.Struct", - Value: b, - } - }(), - want: `{ - "@type": "google.protobuf.Struct", - "value": { - "bool": true, - "null": null, - "string": "hello", - "struct": { - "string": "world" - } - } -}`, - }, { - desc: "Any with missing type_url", - input: func() proto.Message { - m := &wrapperspb.BoolValue{Value: true} - b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) - if err != nil { - t.Fatalf("error in binary marshaling message for Any.value: %v", err) - } - return &anypb.Any{ - Value: b, - } - }(), - wantErr: true, - }, { - desc: "well known types as field values", - input: &pb2.KnownTypes{ - OptBool: &wrapperspb.BoolValue{Value: false}, - OptInt32: &wrapperspb.Int32Value{Value: 42}, - OptInt64: &wrapperspb.Int64Value{Value: 42}, - OptUint32: &wrapperspb.UInt32Value{Value: 42}, - OptUint64: &wrapperspb.UInt64Value{Value: 42}, - OptFloat: &wrapperspb.FloatValue{Value: 1.23}, - OptDouble: &wrapperspb.DoubleValue{Value: 3.1415}, - OptString: &wrapperspb.StringValue{Value: "hello"}, - OptBytes: &wrapperspb.BytesValue{Value: []byte("hello")}, - OptDuration: &durationpb.Duration{Seconds: 123}, - OptTimestamp: ×tamppb.Timestamp{Seconds: 1553036601}, - OptStruct: &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "string": {Kind: &structpb.Value_StringValue{"hello"}}, - }, - }, - OptList: &structpb.ListValue{ - Values: []*structpb.Value{ - {Kind: &structpb.Value_NullValue{}}, - {Kind: &structpb.Value_StringValue{}}, - {Kind: &structpb.Value_StructValue{}}, - {Kind: &structpb.Value_ListValue{}}, - }, - }, - OptValue: &structpb.Value{ - Kind: &structpb.Value_StringValue{"world"}, - }, - OptEmpty: &emptypb.Empty{}, - OptAny: &anypb.Any{ - TypeUrl: "google.protobuf.Empty", - }, - OptFieldmask: &fieldmaskpb.FieldMask{ - Paths: []string{"foo_bar", "bar_foo"}, - }, - }, - want: `{ - "optBool": false, - "optInt32": 42, - "optInt64": "42", - "optUint32": 42, - "optUint64": "42", - "optFloat": 1.23, - "optDouble": 3.1415, - "optString": "hello", - "optBytes": "aGVsbG8=", - "optDuration": "123s", - "optTimestamp": "2019-03-19T23:03:21Z", - "optStruct": { - "string": "hello" - }, - "optList": [ - null, - "", - {}, - [] - ], - "optValue": "world", - "optEmpty": {}, - "optAny": { - "@type": "google.protobuf.Empty", - "value": {} - }, - "optFieldmask": "fooBar,barFoo" -}`, - }, { - desc: "EmitUnpopulated: proto2 optional scalars", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Scalars{}, - want: `{ - "optBool": null, - "optInt32": null, - "optInt64": null, - "optUint32": null, - "optUint64": null, - "optSint32": null, - "optSint64": null, - "optFixed32": null, - "optFixed64": null, - "optSfixed32": null, - "optSfixed64": null, - "optFloat": null, - "optDouble": null, - "optBytes": null, - "optString": null -}`, - }, { - desc: "EmitUnpopulated: proto3 scalars", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Scalars{}, - want: `{ - "sBool": false, - "sInt32": 0, - "sInt64": "0", - "sUint32": 0, - "sUint64": "0", - "sSint32": 0, - "sSint64": "0", - "sFixed32": 0, - "sFixed64": "0", - "sSfixed32": 0, - "sSfixed64": "0", - "sFloat": 0, - "sDouble": 0, - "sBytes": "", - "sString": "" -}`, - }, { - desc: "EmitUnpopulated: proto2 enum", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Enums{}, - want: `{ - "optEnum": null, - "rptEnum": [], - "optNestedEnum": null, - "rptNestedEnum": [] -}`, - }, { - desc: "EmitUnpopulated: proto3 enum", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Enums{}, - want: `{ - "sEnum": "ZERO", - "sNestedEnum": "CERO" -}`, - }, { - desc: "EmitUnpopulated: proto2 message and group fields", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Nests{}, - want: `{ - "optNested": null, - "optgroup": null, - "rptNested": [], - "rptgroup": [] -}`, - }, { - desc: "EmitUnpopulated: proto3 message field", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Nests{}, - want: `{ - "sNested": null -}`, - }, { - desc: "EmitUnpopulated: proto2 empty message and group fields", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Nests{ - OptNested: &pb2.Nested{}, - Optgroup: &pb2.Nests_OptGroup{}, - }, - want: `{ - "optNested": { - "optString": null, - "optNested": null - }, - "optgroup": { - "optString": null, - "optNested": null, - "optnestedgroup": null - }, - "rptNested": [], - "rptgroup": [] -}`, - }, { - desc: "EmitUnpopulated: proto3 empty message field", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Nests{ - SNested: &pb3.Nested{}, - }, - want: `{ - "sNested": { - "sString": "", - "sNested": null - } -}`, - }, { - desc: "EmitUnpopulated: proto2 required fields", - mo: protojson.MarshalOptions{ - AllowPartial: true, - EmitUnpopulated: true, - }, - input: &pb2.Requireds{}, - want: `{ - "reqBool": null, - "reqSfixed64": null, - "reqDouble": null, - "reqString": null, - "reqEnum": null, - "reqNested": null -}`, - }, { - desc: "EmitUnpopulated: repeated fields", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Repeats{}, - want: `{ - "rptBool": [], - "rptInt32": [], - "rptInt64": [], - "rptUint32": [], - "rptUint64": [], - "rptFloat": [], - "rptDouble": [], - "rptString": [], - "rptBytes": [] -}`, - }, { - desc: "EmitUnpopulated: repeated containing empty message", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Nests{ - RptNested: []*pb2.Nested{nil, {}}, - }, - want: `{ - "optNested": null, - "optgroup": null, - "rptNested": [ - { - "optString": null, - "optNested": null - }, - { - "optString": null, - "optNested": null - } - ], - "rptgroup": [] -}`, - }, { - desc: "EmitUnpopulated: map fields", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Maps{}, - want: `{ - "int32ToStr": {}, - "boolToUint32": {}, - "uint64ToEnum": {}, - "strToNested": {}, - "strToOneofs": {} -}`, - }, { - desc: "EmitUnpopulated: map containing empty message", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Maps{ - StrToNested: map[string]*pb3.Nested{ - "nested": &pb3.Nested{}, - }, - StrToOneofs: map[string]*pb3.Oneofs{ - "nested": &pb3.Oneofs{}, - }, - }, - want: `{ - "int32ToStr": {}, - "boolToUint32": {}, - "uint64ToEnum": {}, - "strToNested": { - "nested": { - "sString": "", - "sNested": null - } - }, - "strToOneofs": { - "nested": {} - } -}`, - }, { - desc: "EmitUnpopulated: oneof fields", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb3.Oneofs{}, - want: `{}`, - }, { - desc: "EmitUnpopulated: extensions", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: func() proto.Message { - m := &pb2.Extensions{} - proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{}) - proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{ - nil, - {}, - }) - return m - }(), - want: `{ - "optString": null, - "optBool": null, - "optInt32": null, - "[pb2.opt_ext_nested]": { - "optString": null, - "optNested": null - }, - "[pb2.rpt_ext_nested]": [ - { - "optString": null, - "optNested": null - }, - { - "optString": null, - "optNested": null - } - ] -}`, - }, { - desc: "EmitUnpopulated: with populated fields", - mo: protojson.MarshalOptions{EmitUnpopulated: true}, - input: &pb2.Scalars{ - OptInt32: proto.Int32(0xff), - OptUint32: proto.Uint32(47), - OptSint32: proto.Int32(-1001), - OptFixed32: proto.Uint32(32), - OptSfixed32: proto.Int32(-32), - OptFloat: proto.Float32(1.02), - OptBytes: []byte("谷歌"), - }, - want: `{ - "optBool": null, - "optInt32": 255, - "optInt64": null, - "optUint32": 47, - "optUint64": null, - "optSint32": -1001, - "optSint64": null, - "optFixed32": 32, - "optFixed64": null, - "optSfixed32": -32, - "optSfixed64": null, - "optFloat": 1.02, - "optDouble": null, - "optBytes": "6LC35q2M", - "optString": null -}`, - }, { - desc: "UseEnumNumbers in singular field", - mo: protojson.MarshalOptions{UseEnumNumbers: true}, - input: &pb2.Enums{ - OptEnum: pb2.Enum_ONE.Enum(), - OptNestedEnum: pb2.Enums_UNO.Enum(), - }, - want: `{ - "optEnum": 1, - "optNestedEnum": 1 -}`, - }, { - desc: "UseEnumNumbers in repeated field", - mo: protojson.MarshalOptions{UseEnumNumbers: true}, - input: &pb2.Enums{ - RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42}, - RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_UNO, pb2.Enums_DOS, 47}, - }, - want: `{ - "rptEnum": [ - 1, - 2, - 10, - 42 - ], - "rptNestedEnum": [ - 1, - 2, - 47 - ] -}`, - }, { - desc: "UseEnumNumbers in map field", - mo: protojson.MarshalOptions{UseEnumNumbers: true}, - 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": 1, - "2": 2, - "10": 10, - "47": 47 - } -}`, - }, { - desc: "UseProtoNames", - mo: protojson.MarshalOptions{UseProtoNames: true}, - input: &pb2.Nests{ - OptNested: &pb2.Nested{}, - Optgroup: &pb2.Nests_OptGroup{ - OptString: proto.String("inside a group"), - OptNested: &pb2.Nested{ - OptString: proto.String("nested message inside a group"), - }, - Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{ - OptFixed32: proto.Uint32(47), - }, - }, - Rptgroup: []*pb2.Nests_RptGroup{ - { - RptString: []string{"hello", "world"}, - }, - }, - }, - want: `{ - "opt_nested": {}, - "OptGroup": { - "opt_string": "inside a group", - "opt_nested": { - "opt_string": "nested message inside a group" - }, - "OptNestedGroup": { - "opt_fixed32": 47 - } - }, - "RptGroup": [ - { - "rpt_string": [ - "hello", - "world" - ] - } - ] -}`, - }} - - for _, tt := range tests { - tt := tt - if tt.skip { - continue - } - t.Run(tt.desc, func(t *testing.T) { - // Use 2-space indentation on all MarshalOptions. - tt.mo.Indent = " " - b, err := tt.mo.Marshal(tt.input) - if err != nil && !tt.wantErr { - t.Errorf("Marshal() returned error: %v\n", err) - } - if err == nil && tt.wantErr { - t.Errorf("Marshal() got nil error, want error\n") - } - 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); diff != "" { - t.Errorf("Marshal() diff -want +got\n%v\n", diff) - } - } - }) - } -} |