encoding/prototext: add MarshalOptions.EmitUnknown

This changes text marshaling to avoid unknown fields by default
and instead adds an option so that unknown fields be emitted.
This ensures that the default marshal/unknown can round-trip.

Change-Id: I85c84ba6ab7916d538ec6bfd4e9d399a8fcba14e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/195778
Reviewed-by: Herbie Ong <herbie@google.com>
This commit is contained in:
Joe Tsai 2019-09-14 19:14:24 -07:00
parent cbdefb1530
commit cd4a31e202
6 changed files with 40 additions and 9 deletions

View File

@ -38,6 +38,11 @@ type MarshalOptions struct {
// Marshal will return error if there are any missing required fields.
AllowPartial bool
// EmitUnknown specifies whether to emit unknown fields in the output.
// If specified, the unmarshaler may be unable to parse the output.
// The default is to exclude unknown fields.
EmitUnknown bool
// If Indent is a non-empty string, it causes entries for a Message to be
// preceded by the indent and trailed by a newline. Indent can only be
// composed of space or tab characters.
@ -123,8 +128,9 @@ func (o MarshalOptions) marshalMessage(m pref.Message) (text.Value, error) {
}
// Handle unknown fields.
// TODO: Provide option to exclude or include unknown fields.
msgFields = appendUnknown(msgFields, m.GetUnknown())
if o.EmitUnknown {
msgFields = appendUnknown(msgFields, m.GetUnknown())
}
return text.ValueOf(msgFields), nil
}

View File

@ -820,8 +820,25 @@ req_nested: {}
},
},
want: "oneof_nested: {}\n",
}, {
desc: "unknown fields not printed",
input: func() proto.Message {
m := &pb2.Scalars{
OptString: proto.String("this message contains unknown fields"),
}
m.ProtoReflect().SetUnknown(pack.Message{
pack.Tag{101, pack.VarintType}, pack.Bool(true),
pack.Tag{102, pack.VarintType}, pack.Varint(0xff),
pack.Tag{103, pack.Fixed32Type}, pack.Uint32(47),
pack.Tag{104, pack.Fixed64Type}, pack.Int64(0xdeadbeef),
}.Marshal())
return m
}(),
want: `opt_string: "this message contains unknown fields"
`,
}, {
desc: "unknown varint and fixed types",
mo: prototext.MarshalOptions{EmitUnknown: true},
input: func() proto.Message {
m := &pb2.Scalars{
OptString: proto.String("this message contains unknown fields"),
@ -842,6 +859,7 @@ req_nested: {}
`,
}, {
desc: "unknown length-delimited",
mo: prototext.MarshalOptions{EmitUnknown: true},
input: func() proto.Message {
m := new(pb2.Scalars)
m.ProtoReflect().SetUnknown(pack.Message{
@ -857,6 +875,7 @@ req_nested: {}
`,
}, {
desc: "unknown group type",
mo: prototext.MarshalOptions{EmitUnknown: true},
input: func() proto.Message {
m := new(pb2.Scalars)
m.ProtoReflect().SetUnknown(pack.Message{
@ -876,6 +895,7 @@ req_nested: {}
`,
}, {
desc: "unknown unpack repeated field",
mo: prototext.MarshalOptions{EmitUnknown: true},
input: func() proto.Message {
m := new(pb2.Scalars)
m.ProtoReflect().SetUnknown(pack.Message{

View File

@ -143,7 +143,9 @@ func handle(req *pb.ConformanceRequest) (res *pb.ConformanceResponse) {
},
}
case pb.WireFormat_TEXT_FORMAT:
b, err = prototext.Marshal(msg)
b, err = prototext.MarshalOptions{
EmitUnknown: req.PrintUnknownFields,
}.Marshal(msg)
res = &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_TextPayload{
TextPayload: string(b),

View File

@ -1,8 +1,4 @@
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue.ProtobufOutput

View File

@ -134,7 +134,10 @@ func (Export) MessageTypeOf(m message) pref.MessageType {
// MessageStringOf returns the message value as a string,
// which is the message serialized in the protobuf text format.
func (Export) MessageStringOf(m pref.ProtoMessage) string {
b, _ := prototext.MarshalOptions{AllowPartial: true}.Marshal(m)
b, _ := prototext.MarshalOptions{
AllowPartial: true,
EmitUnknown: true,
}.Marshal(m)
return string(b)
}

View File

@ -1748,6 +1748,10 @@ func extend(desc protoreflect.ExtensionType, value interface{}) buildOpt {
}
func marshalText(m proto.Message) string {
b, _ := prototext.MarshalOptions{Indent: "\t", AllowPartial: true}.Marshal(m)
b, _ := prototext.MarshalOptions{
AllowPartial: true,
EmitUnknown: true,
Indent: "\t",
}.Marshal(m)
return string(b)
}