encoding/textpb: initial textproto unmarshaling
This initial textproto unmarshaling implementation covers messages
without the use of extensions, Any expansion, nor weak.
Updated encoding tests. Split some testcases to keep each simpler.
Added TestRoundTrip for example messages like the well-known types.
Change-Id: Icffab02834aa004fa8409a9da70624f687f604fb
Reviewed-on: https://go-review.googlesource.com/c/153020
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/textpb/encode_test.go b/encoding/textpb/encode_test.go
index ffb2c5a..498b2a7 100644
--- a/encoding/textpb/encode_test.go
+++ b/encoding/textpb/encode_test.go
@@ -9,6 +9,7 @@
"strings"
"testing"
+ protoV1 "github.com/golang/protobuf/proto"
"github.com/golang/protobuf/v2/encoding/textpb"
"github.com/golang/protobuf/v2/internal/detrand"
"github.com/golang/protobuf/v2/internal/impl"
@@ -21,12 +22,6 @@
// TODO: Remove this when protoV1 registers these hooks for you.
_ "github.com/golang/protobuf/v2/internal/legacy"
- anypb "github.com/golang/protobuf/ptypes/any"
- durpb "github.com/golang/protobuf/ptypes/duration"
- emptypb "github.com/golang/protobuf/ptypes/empty"
- stpb "github.com/golang/protobuf/ptypes/struct"
- tspb "github.com/golang/protobuf/ptypes/timestamp"
- wpb "github.com/golang/protobuf/ptypes/wrappers"
"github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
"github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
)
@@ -45,26 +40,35 @@
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 TestMarshal(t *testing.T) {
tests := []struct {
desc string
- input proto.Message
+ input protoV1.Message
want string
wantErr bool
}{{
- desc: "nil message",
- want: "\n",
- }, {
desc: "proto2 optional scalar fields not set",
- input: M(&pb2.Scalars{}),
+ input: &pb2.Scalars{},
want: "\n",
}, {
desc: "proto3 scalar fields not set",
- input: M(&pb3.Scalars{}),
+ input: &pb3.Scalars{},
want: "\n",
}, {
desc: "proto2 optional scalar fields set to zero values",
- input: M(&pb2.Scalars{
+ input: &pb2.Scalars{
OptBool: scalar.Bool(false),
OptInt32: scalar.Int32(0),
OptInt64: scalar.Int64(0),
@@ -80,7 +84,7 @@
OptDouble: scalar.Float64(0),
OptBytes: []byte{},
OptString: scalar.String(""),
- }),
+ },
want: `opt_bool: false
opt_int32: 0
opt_int64: 0
@@ -99,7 +103,7 @@
`,
}, {
desc: "proto3 scalar fields set to zero values",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SBool: false,
SInt32: 0,
SInt64: 0,
@@ -115,11 +119,11 @@
SDouble: 0,
SBytes: []byte{},
SString: "",
- }),
+ },
want: "\n",
}, {
desc: "proto2 optional scalar fields set to some values",
- input: M(&pb2.Scalars{
+ input: &pb2.Scalars{
OptBool: scalar.Bool(true),
OptInt32: scalar.Int32(0xff),
OptInt64: scalar.Int64(0xdeadbeef),
@@ -135,7 +139,7 @@
// TODO: Update encoder to not output UTF8 for bytes.
OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
OptString: scalar.String("谷歌"),
- }),
+ },
want: `opt_bool: true
opt_int32: 255
opt_int64: 3735928559
@@ -151,84 +155,253 @@
opt_string: "谷歌"
`,
}, {
- desc: "proto3 enum empty message",
- input: M(&pb3.Enums{}),
- want: "\n",
- }, {
- desc: "proto3 enum",
- input: M(&pb3.Enums{
- SEnum: pb3.Enum_ONE,
- RptEnum: []pb3.Enum{pb3.Enum_ONE, 10, 0, 21, -1},
- SNestedEnum: pb3.Enums_DIEZ,
- RptNestedEnum: []pb3.Enums_NestedEnum{21, pb3.Enums_CERO, -7, 10},
- }),
- want: `s_enum: ONE
-rpt_enum: ONE
-rpt_enum: TEN
-rpt_enum: ZERO
-rpt_enum: 21
-rpt_enum: -1
-s_nested_enum: DIEZ
-rpt_nested_enum: 21
-rpt_nested_enum: CERO
-rpt_nested_enum: -7
-rpt_nested_enum: DIEZ
-`,
- }, {
desc: "float32 nan",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SFloat: float32(math.NaN()),
- }),
+ },
want: "s_float: nan\n",
}, {
desc: "float32 positive infinity",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SFloat: float32(math.Inf(1)),
- }),
+ },
want: "s_float: inf\n",
}, {
desc: "float32 negative infinity",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SFloat: float32(math.Inf(-1)),
- }),
+ },
want: "s_float: -inf\n",
}, {
desc: "float64 nan",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SDouble: math.NaN(),
- }),
+ },
want: "s_double: nan\n",
}, {
desc: "float64 positive infinity",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SDouble: math.Inf(1),
- }),
+ },
want: "s_double: inf\n",
}, {
desc: "float64 negative infinity",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SDouble: math.Inf(-1),
- }),
+ },
want: "s_double: -inf\n",
}, {
desc: "proto2 bytes set to empty string",
- input: M(&pb2.Scalars{
+ input: &pb2.Scalars{
OptBytes: []byte(""),
- }),
+ },
want: "opt_bytes: \"\"\n",
}, {
desc: "proto3 bytes set to empty string",
- input: M(&pb3.Scalars{
+ input: &pb3.Scalars{
SBytes: []byte(""),
- }),
+ },
want: "\n",
}, {
- desc: "proto2 repeated not set",
- input: M(&pb2.Repeats{}),
+ desc: "proto2 enum not set",
+ input: &pb2.Enums{},
want: "\n",
}, {
- desc: "proto2 repeated set to empty slices",
- input: M(&pb2.Repeats{
+ desc: "proto2 enum set to zero value",
+ input: &pb2.Enums{
+ OptEnum: pb2.Enum_UNKNOWN.Enum(),
+ OptNestedEnum: pb2Enums_NestedEnum(0),
+ },
+ want: `opt_enum: UNKNOWN
+opt_nested_enum: 0
+`,
+ }, {
+ desc: "proto2 enum",
+ input: &pb2.Enums{
+ OptEnum: pb2.Enum_FIRST.Enum(),
+ OptNestedEnum: pb2.Enums_UNO.Enum(),
+ },
+ want: `opt_enum: FIRST
+opt_nested_enum: UNO
+`,
+ }, {
+ desc: "proto2 enum set to numeric values",
+ input: &pb2.Enums{
+ OptEnum: pb2Enum(1),
+ OptNestedEnum: pb2Enums_NestedEnum(2),
+ },
+ want: `opt_enum: FIRST
+opt_nested_enum: DOS
+`,
+ }, {
+ desc: "proto2 enum set to unnamed numeric values",
+ input: &pb2.Enums{
+ OptEnum: pb2Enum(101),
+ OptNestedEnum: pb2Enums_NestedEnum(-101),
+ },
+ want: `opt_enum: 101
+opt_nested_enum: -101
+`,
+ }, {
+ desc: "proto3 enum not set",
+ input: &pb3.Enums{},
+ want: "\n",
+ }, {
+ desc: "proto3 enum set to zero value",
+ input: &pb3.Enums{
+ SEnum: pb3.Enum_ZERO,
+ SNestedEnum: pb3.Enums_CERO,
+ },
+ want: "\n",
+ }, {
+ desc: "proto3 enum",
+ input: &pb3.Enums{
+ SEnum: pb3.Enum_ONE,
+ SNestedEnum: pb3.Enums_DIEZ,
+ },
+ want: `s_enum: ONE
+s_nested_enum: DIEZ
+`,
+ }, {
+ desc: "proto3 enum set to numeric values",
+ input: &pb3.Enums{
+ SEnum: 2,
+ SNestedEnum: 1,
+ },
+ want: `s_enum: TWO
+s_nested_enum: UNO
+`,
+ }, {
+ desc: "proto3 enum set to unnamed numeric values",
+ input: &pb3.Enums{
+ SEnum: -47,
+ SNestedEnum: 47,
+ },
+ want: `s_enum: -47
+s_nested_enum: 47
+`,
+ }, {
+ desc: "proto2 nested message not set",
+ input: &pb2.Nests{},
+ want: "\n",
+ }, {
+ desc: "proto2 nested message set to empty",
+ input: &pb2.Nests{
+ OptNested: &pb2.Nested{},
+ Optgroup: &pb2.Nests_OptGroup{},
+ },
+ want: `opt_nested: {}
+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: `opt_nested: {
+ opt_string: "nested message"
+ opt_nested: {
+ opt_string: "another nested message"
+ }
+}
+`,
+ }, {
+ desc: "proto2 group fields",
+ input: &pb2.Nests{
+ Optgroup: &pb2.Nests_OptGroup{
+ OptBool: scalar.Bool(true),
+ OptString: scalar.String("inside a group"),
+ OptNested: &pb2.Nested{
+ OptString: scalar.String("nested message inside a group"),
+ },
+ Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
+ OptEnum: pb2.Enum_TENTH.Enum(),
+ },
+ },
+ },
+ want: `optgroup: {
+ opt_bool: true
+ opt_string: "inside a group"
+ opt_nested: {
+ opt_string: "nested message inside a group"
+ }
+ optnestedgroup: {
+ opt_enum: TENTH
+ }
+}
+`,
+ }, {
+ desc: "proto3 nested message not set",
+ input: &pb3.Nests{},
+ want: "\n",
+ }, {
+ desc: "proto3 nested message",
+ input: &pb3.Nests{
+ SNested: &pb3.Nested{
+ SString: "nested message",
+ SNested: &pb3.Nested{
+ SString: "another nested message",
+ },
+ },
+ },
+ want: `s_nested: {
+ s_string: "nested message"
+ s_nested: {
+ s_string: "another nested message"
+ }
+}
+`,
+ }, {
+ desc: "oneof fields",
+ input: &pb2.Oneofs{},
+ want: "\n",
+ }, {
+ desc: "oneof field set to empty string",
+ input: &pb2.Oneofs{
+ Union: &pb2.Oneofs_Str{},
+ },
+ want: "str: \"\"\n",
+ }, {
+ desc: "oneof field set to string",
+ input: &pb2.Oneofs{
+ Union: &pb2.Oneofs_Str{
+ Str: "hello",
+ },
+ },
+ want: "str: \"hello\"\n",
+ }, {
+ desc: "oneof field set to empty message",
+ input: &pb2.Oneofs{
+ Union: &pb2.Oneofs_Msg{
+ Msg: &pb2.Nested{},
+ },
+ },
+ want: "msg: {}\n",
+ }, {
+ desc: "oneof field set to message",
+ input: &pb2.Oneofs{
+ Union: &pb2.Oneofs_Msg{
+ Msg: &pb2.Nested{
+ OptString: scalar.String("nested message"),
+ },
+ },
+ },
+ want: `msg: {
+ opt_string: "nested message"
+}
+`,
+ }, {
+ desc: "repeated not set",
+ input: &pb2.Repeats{},
+ want: "\n",
+ }, {
+ desc: "repeated set to empty slices",
+ input: &pb2.Repeats{
RptBool: []bool{},
RptInt32: []int32{},
RptInt64: []int64{},
@@ -237,11 +410,11 @@
RptFloat: []float32{},
RptDouble: []float64{},
RptBytes: [][]byte{},
- }),
+ },
want: "\n",
}, {
- desc: "proto2 repeated set to some values",
- input: M(&pb2.Repeats{
+ desc: "repeated set to some values",
+ input: &pb2.Repeats{
RptBool: []bool{true, false, true, true},
RptInt32: []int32{1, 6, 0, 0},
RptInt64: []int64{-64, 47},
@@ -254,7 +427,7 @@
[]byte("hello"),
[]byte("\xe4\xb8\x96\xe7\x95\x8c"),
},
- }),
+ },
want: `rpt_bool: true
rpt_bool: false
rpt_bool: true
@@ -278,77 +451,29 @@
rpt_bytes: "世界"
`,
}, {
- desc: "proto2 enum fields not set",
- input: M(&pb2.Enums{}),
- want: "\n",
- }, {
- desc: "proto2 enum fields",
- input: M(&pb2.Enums{
- OptEnum: pb2.Enum_FIRST.Enum(),
+ desc: "repeated enum",
+ input: &pb2.Enums{
RptEnum: []pb2.Enum{pb2.Enum_FIRST, 2, pb2.Enum_TENTH, 42},
- OptNestedEnum: pb2.Enums_UNO.Enum(),
RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
- }),
- want: `opt_enum: FIRST
-rpt_enum: FIRST
+ },
+ want: `rpt_enum: FIRST
rpt_enum: SECOND
rpt_enum: TENTH
rpt_enum: 42
-opt_nested_enum: UNO
rpt_nested_enum: DOS
rpt_nested_enum: 47
rpt_nested_enum: DIEZ
`,
}, {
- desc: "proto3 enum fields set to zero value",
- input: M(&pb3.Enums{
- SEnum: pb3.Enum_ZERO,
- RptEnum: []pb3.Enum{},
- SNestedEnum: pb3.Enums_CERO,
- RptNestedEnum: []pb3.Enums_NestedEnum{},
- }),
- want: "\n",
- }, {
- desc: "proto3 enum fields",
- input: M(&pb3.Enums{
- SEnum: pb3.Enum_TWO,
- RptEnum: []pb3.Enum{1, 0, 0},
- SNestedEnum: pb3.Enums_DOS,
- RptNestedEnum: []pb3.Enums_NestedEnum{101, pb3.Enums_DIEZ, 10},
- }),
- want: `s_enum: TWO
-rpt_enum: ONE
-rpt_enum: ZERO
-rpt_enum: ZERO
-s_nested_enum: DOS
-rpt_nested_enum: 101
-rpt_nested_enum: DIEZ
-rpt_nested_enum: DIEZ
-`,
- }, {
- desc: "proto2 nested message not set",
- input: M(&pb2.Nests{}),
- want: "\n",
- }, {
- desc: "proto2 nested message set to empty",
- input: M(&pb2.Nests{
- OptNested: &pb2.Nested{},
- Optgroup: &pb2.Nests_OptGroup{},
+ desc: "repeated nested message set to empty",
+ input: &pb2.Nests{
RptNested: []*pb2.Nested{},
Rptgroup: []*pb2.Nests_RptGroup{},
- }),
- want: `opt_nested: {}
-optgroup: {}
-`,
+ },
+ want: "\n",
}, {
- desc: "proto2 nested messages",
- input: M(&pb2.Nests{
- OptNested: &pb2.Nested{
- OptString: scalar.String("nested message"),
- OptNested: &pb2.Nested{
- OptString: scalar.String("another nested message"),
- },
- },
+ desc: "repeated nested messages",
+ input: &pb2.Nests{
RptNested: []*pb2.Nested{
{
OptString: scalar.String("repeat nested one"),
@@ -361,14 +486,8 @@
},
{},
},
- }),
- want: `opt_nested: {
- opt_string: "nested message"
- opt_nested: {
- opt_string: "another nested message"
- }
-}
-rpt_nested: {
+ },
+ want: `rpt_nested: {
opt_string: "repeat nested one"
}
rpt_nested: {
@@ -380,191 +499,39 @@
rpt_nested: {}
`,
}, {
- desc: "proto2 group fields",
- input: M(&pb2.Nests{
- Optgroup: &pb2.Nests_OptGroup{
- OptBool: scalar.Bool(true),
- OptString: scalar.String("inside a group"),
- OptNested: &pb2.Nested{
- OptString: scalar.String("nested message inside a group"),
- },
- Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
- OptEnum: pb2.Enum_TENTH.Enum(),
- },
- },
+ desc: "repeated group fields",
+ input: &pb2.Nests{
Rptgroup: []*pb2.Nests_RptGroup{
{
RptBool: []bool{true, false},
},
{},
},
- }),
- want: `optgroup: {
- opt_bool: true
- opt_string: "inside a group"
- opt_nested: {
- opt_string: "nested message inside a group"
- }
- optnestedgroup: {
- opt_enum: TENTH
- }
-}
-rptgroup: {
+ },
+ want: `rptgroup: {
rpt_bool: true
rpt_bool: false
}
rptgroup: {}
`,
}, {
- desc: "proto3 nested message not set",
- input: M(&pb3.Nests{}),
- want: "\n",
- }, {
- desc: "proto3 nested message",
- input: M(&pb3.Nests{
- SNested: &pb3.Nested{
- SString: "nested message",
- SNested: &pb3.Nested{
- SString: "another nested message",
- },
- },
- RptNested: []*pb3.Nested{
- {
- SString: "repeated nested one",
- SNested: &pb3.Nested{
- SString: "inside repeated nested one",
- },
- },
- {
- SString: "repeated nested two",
- },
- {},
- },
- }),
- want: `s_nested: {
- s_string: "nested message"
- s_nested: {
- s_string: "another nested message"
- }
-}
-rpt_nested: {
- s_string: "repeated nested one"
- s_nested: {
- s_string: "inside repeated nested one"
- }
-}
-rpt_nested: {
- s_string: "repeated nested two"
-}
-rpt_nested: {}
-`,
- }, {
- desc: "proto2 required fields not set",
- input: M(&pb2.Requireds{}),
- want: "\n",
- wantErr: true,
- }, {
- desc: "proto2 required fields partially set",
- input: M(&pb2.Requireds{
- ReqBool: scalar.Bool(false),
- ReqFixed32: scalar.Uint32(47),
- ReqSfixed64: scalar.Int64(0xbeefcafe),
- ReqDouble: scalar.Float64(math.NaN()),
- ReqString: scalar.String("hello"),
- ReqEnum: pb2.Enum_FIRST.Enum(),
- }),
- want: `req_bool: false
-req_fixed32: 47
-req_sfixed64: 3203386110
-req_double: nan
-req_string: "hello"
-req_enum: FIRST
-`,
- wantErr: true,
- }, {
- desc: "proto2 required fields all set",
- input: M(&pb2.Requireds{
- ReqBool: scalar.Bool(false),
- ReqFixed32: scalar.Uint32(0),
- ReqFixed64: scalar.Uint64(0),
- ReqSfixed32: scalar.Int32(0),
- ReqSfixed64: scalar.Int64(0),
- ReqFloat: scalar.Float32(0),
- ReqDouble: scalar.Float64(0),
- ReqString: scalar.String(""),
- ReqEnum: pb2.Enum_UNKNOWN.Enum(),
- ReqBytes: []byte{},
- ReqNested: &pb2.Nested{},
- }),
- want: `req_bool: false
-req_fixed32: 0
-req_fixed64: 0
-req_sfixed32: 0
-req_sfixed64: 0
-req_float: 0
-req_double: 0
-req_string: ""
-req_bytes: ""
-req_enum: UNKNOWN
-req_nested: {}
-`,
- }, {
- desc: "oneof fields",
- input: M(&pb2.Oneofs{}),
- want: "\n",
- }, {
- desc: "oneof field set to empty string",
- input: M(&pb2.Oneofs{
- Union: &pb2.Oneofs_Str{},
- }),
- want: "str: \"\"\n",
- }, {
- desc: "oneof field set to string",
- input: M(&pb2.Oneofs{
- Union: &pb2.Oneofs_Str{
- Str: "hello",
- },
- }),
- want: "str: \"hello\"\n",
- }, {
- desc: "oneof field set to empty message",
- input: M(&pb2.Oneofs{
- Union: &pb2.Oneofs_Msg{
- Msg: &pb2.Nested{},
- },
- }),
- want: "msg: {}\n",
- }, {
- desc: "oneof field set to message",
- input: M(&pb2.Oneofs{
- Union: &pb2.Oneofs_Msg{
- Msg: &pb2.Nested{
- OptString: scalar.String("nested message"),
- },
- },
- }),
- want: `msg: {
- opt_string: "nested message"
-}
-`,
- }, {
desc: "map fields empty",
- input: M(&pb2.Maps{}),
+ input: &pb2.Maps{},
want: "\n",
}, {
desc: "map fields set to empty maps",
- input: M(&pb2.Maps{
+ input: &pb2.Maps{
Int32ToStr: map[int32]string{},
Sfixed64ToBool: map[int64]bool{},
BoolToUint32: map[bool]uint32{},
Uint64ToEnum: map[uint64]pb2.Enum{},
StrToNested: map[string]*pb2.Nested{},
StrToOneofs: map[string]*pb2.Oneofs{},
- }),
+ },
want: "\n",
}, {
desc: "map fields 1",
- input: M(&pb2.Maps{
+ input: &pb2.Maps{
Int32ToStr: map[int32]string{
-101: "-101",
0xff: "0xff",
@@ -578,7 +545,7 @@
true: 42,
false: 101,
},
- }),
+ },
want: `int32_to_str: {
key: -101
value: "-101"
@@ -610,13 +577,13 @@
`,
}, {
desc: "map fields 2",
- input: M(&pb2.Maps{
+ input: &pb2.Maps{
Uint64ToEnum: map[uint64]pb2.Enum{
1: pb2.Enum_FIRST,
2: pb2.Enum_SECOND,
10: pb2.Enum_TENTH,
},
- }),
+ },
want: `uint64_to_enum: {
key: 1
value: FIRST
@@ -632,13 +599,13 @@
`,
}, {
desc: "map fields 3",
- input: M(&pb2.Maps{
+ input: &pb2.Maps{
StrToNested: map[string]*pb2.Nested{
"nested_one": &pb2.Nested{
OptString: scalar.String("nested in a map"),
},
},
- }),
+ },
want: `str_to_nested: {
key: "nested_one"
value: {
@@ -648,7 +615,7 @@
`,
}, {
desc: "map fields 4",
- input: M(&pb2.Maps{
+ input: &pb2.Maps{
StrToOneofs: map[string]*pb2.Oneofs{
"string": &pb2.Oneofs{
Union: &pb2.Oneofs_Str{
@@ -663,7 +630,7 @@
},
},
},
- }),
+ },
want: `str_to_oneofs: {
key: "nested"
value: {
@@ -680,255 +647,113 @@
}
`,
}, {
- desc: "well-known type fields not set",
- input: M(&pb2.KnownTypes{}),
- want: "\n",
+ desc: "proto2 required fields not set",
+ input: &pb2.Requireds{},
+ want: "\n",
+ wantErr: true,
}, {
- desc: "well-known type fields set to empty messages",
- input: M(&pb2.KnownTypes{
- OptBool: &wpb.BoolValue{},
- OptInt32: &wpb.Int32Value{},
- OptInt64: &wpb.Int64Value{},
- OptUint32: &wpb.UInt32Value{},
- OptUint64: &wpb.UInt64Value{},
- OptFloat: &wpb.FloatValue{},
- OptDouble: &wpb.DoubleValue{},
- OptString: &wpb.StringValue{},
- OptBytes: &wpb.BytesValue{},
- OptDuration: &durpb.Duration{},
- OptTimestamp: &tspb.Timestamp{},
- OptStruct: &stpb.Struct{},
- OptList: &stpb.ListValue{},
- OptValue: &stpb.Value{},
- OptEmpty: &emptypb.Empty{},
- OptAny: &anypb.Any{},
- }),
- want: `opt_bool: {}
-opt_int32: {}
-opt_int64: {}
-opt_uint32: {}
-opt_uint64: {}
-opt_float: {}
-opt_double: {}
-opt_string: {}
-opt_bytes: {}
-opt_duration: {}
-opt_timestamp: {}
-opt_struct: {}
-opt_list: {}
-opt_value: {}
-opt_empty: {}
-opt_any: {}
+ desc: "proto2 required fields partially set",
+ input: &pb2.Requireds{
+ ReqBool: scalar.Bool(false),
+ ReqFixed32: scalar.Uint32(47),
+ ReqSfixed64: scalar.Int64(0xbeefcafe),
+ ReqDouble: scalar.Float64(math.NaN()),
+ ReqString: scalar.String("hello"),
+ ReqEnum: pb2.Enum_FIRST.Enum(),
+ },
+ want: `req_bool: false
+req_fixed32: 47
+req_sfixed64: 3203386110
+req_double: nan
+req_string: "hello"
+req_enum: FIRST
+`,
+ wantErr: true,
+ }, {
+ desc: "proto2 required fields all set",
+ input: &pb2.Requireds{
+ ReqBool: scalar.Bool(false),
+ ReqFixed32: scalar.Uint32(0),
+ ReqFixed64: scalar.Uint64(0),
+ ReqSfixed32: scalar.Int32(0),
+ ReqSfixed64: scalar.Int64(0),
+ ReqFloat: scalar.Float32(0),
+ ReqDouble: scalar.Float64(0),
+ ReqString: scalar.String(""),
+ ReqEnum: pb2.Enum_UNKNOWN.Enum(),
+ ReqBytes: []byte{},
+ ReqNested: &pb2.Nested{},
+ },
+ want: `req_bool: false
+req_fixed32: 0
+req_fixed64: 0
+req_sfixed32: 0
+req_sfixed64: 0
+req_float: 0
+req_double: 0
+req_string: ""
+req_bytes: ""
+req_enum: UNKNOWN
+req_nested: {}
`,
}, {
- desc: "well-known type scalar fields",
- input: M(&pb2.KnownTypes{
- OptBool: &wpb.BoolValue{
- Value: true,
- },
- OptInt32: &wpb.Int32Value{
- Value: -42,
- },
- OptInt64: &wpb.Int64Value{
- Value: -42,
- },
- OptUint32: &wpb.UInt32Value{
- Value: 0xff,
- },
- OptUint64: &wpb.UInt64Value{
- Value: 0xffff,
- },
- OptFloat: &wpb.FloatValue{
- Value: 1.234,
- },
- OptDouble: &wpb.DoubleValue{
- Value: 1.23e308,
- },
- OptString: &wpb.StringValue{
- Value: "谷歌",
- },
- OptBytes: &wpb.BytesValue{
- Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
- },
- }),
- want: `opt_bool: {
- value: true
-}
-opt_int32: {
- value: -42
-}
-opt_int64: {
- value: -42
-}
-opt_uint32: {
- value: 255
-}
-opt_uint64: {
- value: 65535
-}
-opt_float: {
- value: 1.2339999675750732
-}
-opt_double: {
- value: 1.23e+308
-}
-opt_string: {
- value: "谷歌"
-}
-opt_bytes: {
- value: "谷歌"
-}
-`,
+ desc: "indirect required field",
+ input: &pb2.IndirectRequired{
+ OptNested: &pb2.NestedWithRequired{},
+ },
+ want: "opt_nested: {}\n",
+ wantErr: true,
}, {
- desc: "well-known type time-related fields",
- input: M(&pb2.KnownTypes{
- OptDuration: &durpb.Duration{
- Seconds: -3600,
- Nanos: -123,
- },
- OptTimestamp: &tspb.Timestamp{
- Seconds: 1257894000,
- Nanos: 123,
- },
- }),
- want: `opt_duration: {
- seconds: -3600
- nanos: -123
-}
-opt_timestamp: {
- seconds: 1257894000
- nanos: 123
-}
-`,
+ desc: "indirect required field in empty repeated",
+ input: &pb2.IndirectRequired{
+ RptNested: []*pb2.NestedWithRequired{},
+ },
+ want: "\n",
}, {
- desc: "well-known type struct field and different Value types",
- input: M(&pb2.KnownTypes{
- OptStruct: &stpb.Struct{
- Fields: map[string]*stpb.Value{
- "bool": &stpb.Value{
- Kind: &stpb.Value_BoolValue{
- BoolValue: true,
- },
- },
- "double": &stpb.Value{
- Kind: &stpb.Value_NumberValue{
- NumberValue: 3.1415,
- },
- },
- "null": &stpb.Value{
- Kind: &stpb.Value_NullValue{
- NullValue: stpb.NullValue_NULL_VALUE,
- },
- },
- "string": &stpb.Value{
- Kind: &stpb.Value_StringValue{
- StringValue: "string",
- },
- },
- "struct": &stpb.Value{
- Kind: &stpb.Value_StructValue{
- StructValue: &stpb.Struct{
- Fields: map[string]*stpb.Value{
- "bool": &stpb.Value{
- Kind: &stpb.Value_BoolValue{
- BoolValue: false,
- },
- },
- },
- },
- },
- },
- "list": &stpb.Value{
- Kind: &stpb.Value_ListValue{
- ListValue: &stpb.ListValue{
- Values: []*stpb.Value{
- {
- Kind: &stpb.Value_BoolValue{
- BoolValue: false,
- },
- },
- {
- Kind: &stpb.Value_StringValue{
- StringValue: "hello",
- },
- },
- },
- },
- },
- },
- },
+ desc: "indirect required field in repeated",
+ input: &pb2.IndirectRequired{
+ RptNested: []*pb2.NestedWithRequired{
+ &pb2.NestedWithRequired{},
},
- }),
- want: `opt_struct: {
- fields: {
- key: "bool"
- value: {
- bool_value: true
- }
- }
- fields: {
- key: "double"
- value: {
- number_value: 3.1415
- }
- }
- fields: {
- key: "list"
- value: {
- list_value: {
- values: {
- bool_value: false
- }
- values: {
- string_value: "hello"
- }
- }
- }
- }
- fields: {
- key: "null"
- value: {
- null_value: NULL_VALUE
- }
- }
- fields: {
- key: "string"
- value: {
- string_value: "string"
- }
- }
- fields: {
- key: "struct"
- value: {
- struct_value: {
- fields: {
- key: "bool"
- value: {
- bool_value: false
- }
- }
- }
- }
- }
+ },
+ want: "rpt_nested: {}\n",
+ wantErr: true,
+ }, {
+ desc: "indirect required field in empty map",
+ input: &pb2.IndirectRequired{
+ StrToNested: map[string]*pb2.NestedWithRequired{},
+ },
+ want: "\n",
+ }, {
+ desc: "indirect required field in map",
+ input: &pb2.IndirectRequired{
+ StrToNested: map[string]*pb2.NestedWithRequired{
+ "fail": &pb2.NestedWithRequired{},
+ },
+ },
+ want: `str_to_nested: {
+ key: "fail"
+ value: {}
}
`,
+ wantErr: true,
}}
for _, tt := range tests {
tt := tt
t.Run(tt.desc, func(t *testing.T) {
t.Parallel()
- want := tt.want
- b, err := textpb.Marshal(tt.input)
+ b, err := textpb.Marshal(M(tt.input))
if err != nil && !tt.wantErr {
t.Errorf("Marshal() returned error: %v\n\n", err)
}
- if tt.wantErr && err == nil {
- t.Errorf("Marshal() got nil error, want error\n\n")
+ if err == nil && tt.wantErr {
+ t.Error("Marshal() got nil error, want error\n\n")
}
- if got := string(b); got != want {
- t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, want)
- if diff := cmp.Diff(want, got, splitLines); diff != "" {
+ got := string(b)
+ if tt.want != "" && 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)
}
}