encoding/textpb: add AllowPartial option to MarshalOptions and UnmarshalOptions

Provide AllowPartial option to accept messages with missing required
field during marshaling and unmarshaling.

Change-Id: Ia23783870a8125633f8ddc0b686984b4c5ca15ba
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/169500
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/encoding/textpb/encode_test.go b/encoding/textpb/encode_test.go
index 2654e05..d185fa6 100644
--- a/encoding/textpb/encode_test.go
+++ b/encoding/textpb/encode_test.go
@@ -683,12 +683,12 @@
 }
 `,
 	}, {
-		desc:    "proto2 required fields not set",
+		desc:    "required fields not set",
 		input:   &pb2.Requireds{},
 		want:    "\n",
 		wantErr: true,
 	}, {
-		desc: "proto2 required fields partially set",
+		desc: "required fields partially set",
 		input: &pb2.Requireds{
 			ReqBool:     scalar.Bool(false),
 			ReqSfixed64: scalar.Int64(0xbeefcafe),
@@ -704,7 +704,23 @@
 `,
 		wantErr: true,
 	}, {
-		desc: "proto2 required fields all set",
+		desc: "required fields not set with AllowPartial",
+		mo:   textpb.MarshalOptions{AllowPartial: true},
+		input: &pb2.Requireds{
+			ReqBool:     scalar.Bool(false),
+			ReqSfixed64: scalar.Int64(0xbeefcafe),
+			ReqDouble:   scalar.Float64(math.NaN()),
+			ReqString:   scalar.String("hello"),
+			ReqEnum:     pb2.Enum_ONE.Enum(),
+		},
+		want: `req_bool: false
+req_sfixed64: 3203386110
+req_double: nan
+req_string: "hello"
+req_enum: ONE
+`,
+	}, {
+		desc: "required fields all set",
 		input: &pb2.Requireds{
 			ReqBool:     scalar.Bool(false),
 			ReqSfixed64: scalar.Int64(0),
@@ -728,6 +744,13 @@
 		want:    "opt_nested: {}\n",
 		wantErr: true,
 	}, {
+		desc: "indirect required field with AllowPartial",
+		mo:   textpb.MarshalOptions{AllowPartial: true},
+		input: &pb2.IndirectRequired{
+			OptNested: &pb2.NestedWithRequired{},
+		},
+		want: "opt_nested: {}\n",
+	}, {
 		desc: "indirect required field in empty repeated",
 		input: &pb2.IndirectRequired{
 			RptNested: []*pb2.NestedWithRequired{},
@@ -743,6 +766,15 @@
 		want:    "rpt_nested: {}\n",
 		wantErr: true,
 	}, {
+		desc: "indirect required field in repeated with AllowPartial",
+		mo:   textpb.MarshalOptions{AllowPartial: true},
+		input: &pb2.IndirectRequired{
+			RptNested: []*pb2.NestedWithRequired{
+				&pb2.NestedWithRequired{},
+			},
+		},
+		want: "rpt_nested: {}\n",
+	}, {
 		desc: "indirect required field in empty map",
 		input: &pb2.IndirectRequired{
 			StrToNested: map[string]*pb2.NestedWithRequired{},
@@ -762,6 +794,19 @@
 `,
 		wantErr: true,
 	}, {
+		desc: "indirect required field in map with AllowPartial",
+		mo:   textpb.MarshalOptions{AllowPartial: true},
+		input: &pb2.IndirectRequired{
+			StrToNested: map[string]*pb2.NestedWithRequired{
+				"fail": &pb2.NestedWithRequired{},
+			},
+		},
+		want: `str_to_nested: {
+  key: "fail"
+  value: {}
+}
+`,
+	}, {
 		desc: "indirect required field in oneof",
 		input: &pb2.IndirectRequired{
 			Union: &pb2.IndirectRequired_OneofNested{
@@ -771,6 +816,15 @@
 		want:    "oneof_nested: {}\n",
 		wantErr: true,
 	}, {
+		desc: "indirect required field in oneof with AllowPartial",
+		mo:   textpb.MarshalOptions{AllowPartial: true},
+		input: &pb2.IndirectRequired{
+			Union: &pb2.IndirectRequired_OneofNested{
+				OneofNested: &pb2.NestedWithRequired{},
+			},
+		},
+		want: "oneof_nested: {}\n",
+	}, {
 		desc: "unknown varint and fixed types",
 		input: &pb2.Scalars{
 			OptString: scalar.String("this message contains unknown fields"),