mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-01 11:58:21 +00:00
387873dd53
In the upcoming 3.12.x release of protoc, the proto3 language will be amended to support true presence for scalars. This CL adds support to both the generator and runtime to support these semantics. Newly added public API: protogen.Plugin.SupportedFeatures protoreflect.FieldDescriptor.HasPresence protoreflect.FieldDescriptor.HasOptionalKeyword protoreflect.OneofDescriptor.IsSynthetic Change-Id: I7c86bf66d0ae56642109beb5f2132184593747ad Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/230698 Reviewed-by: Damien Neil <dneil@google.com>
155 lines
4.6 KiB
Go
155 lines
4.6 KiB
Go
// Copyright 2018 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 proto_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"google.golang.org/protobuf/encoding/prototext"
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
"google.golang.org/protobuf/testing/protopack"
|
|
|
|
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
|
test3pb "google.golang.org/protobuf/internal/testprotos/test3"
|
|
)
|
|
|
|
func TestDecode(t *testing.T) {
|
|
for _, test := range testValidMessages {
|
|
if len(test.decodeTo) == 0 {
|
|
t.Errorf("%v: no test message types", test.desc)
|
|
}
|
|
for _, want := range test.decodeTo {
|
|
t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
|
|
opts := test.unmarshalOptions
|
|
opts.AllowPartial = test.partial
|
|
wire := append(([]byte)(nil), test.wire...)
|
|
got := reflect.New(reflect.TypeOf(want).Elem()).Interface().(proto.Message)
|
|
if err := opts.Unmarshal(wire, got); err != nil {
|
|
t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want))
|
|
return
|
|
}
|
|
|
|
// Aliasing check: Unmarshal shouldn't modify the original wire
|
|
// bytes, and modifying the original wire bytes shouldn't affect
|
|
// the unmarshaled message.
|
|
if !bytes.Equal(test.wire, wire) {
|
|
t.Errorf("Unmarshal unexpectedly modified its input")
|
|
}
|
|
for i := range wire {
|
|
wire[i] = 0
|
|
}
|
|
if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() {
|
|
t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeRequiredFieldChecks(t *testing.T) {
|
|
for _, test := range testValidMessages {
|
|
if !test.partial {
|
|
continue
|
|
}
|
|
for _, m := range test.decodeTo {
|
|
t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
|
|
opts := test.unmarshalOptions
|
|
opts.AllowPartial = false
|
|
got := reflect.New(reflect.TypeOf(m).Elem()).Interface().(proto.Message)
|
|
if err := proto.Unmarshal(test.wire, got); err == nil {
|
|
t.Fatalf("Unmarshal succeeded (want error)\nMessage:\n%v", prototext.Format(got))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeInvalidMessages(t *testing.T) {
|
|
for _, test := range testInvalidMessages {
|
|
if len(test.decodeTo) == 0 {
|
|
t.Errorf("%v: no test message types", test.desc)
|
|
}
|
|
for _, want := range test.decodeTo {
|
|
t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
|
|
opts := test.unmarshalOptions
|
|
opts.AllowPartial = test.partial
|
|
got := want.ProtoReflect().New().Interface()
|
|
if err := opts.Unmarshal(test.wire, got); err == nil {
|
|
t.Errorf("Unmarshal unexpectedly succeeded\ninput bytes: [%x]\nMessage:\n%v", test.wire, prototext.Format(got))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeZeroLengthBytes(t *testing.T) {
|
|
// Verify that proto3 bytes fields don't give the mistaken
|
|
// impression that they preserve presence.
|
|
wire := protopack.Message{
|
|
protopack.Tag{94, protopack.BytesType}, protopack.Bytes(nil),
|
|
}.Marshal()
|
|
m := &test3pb.TestAllTypes{}
|
|
if err := proto.Unmarshal(wire, m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if m.OptionalBytes != nil {
|
|
t.Errorf("unmarshal zero-length proto3 bytes field: got %v, want nil", m.OptionalBytes)
|
|
}
|
|
}
|
|
|
|
func TestDecodeOneofNilWrapper(t *testing.T) {
|
|
wire := protopack.Message{
|
|
protopack.Tag{111, protopack.VarintType}, protopack.Varint(1111),
|
|
}.Marshal()
|
|
m := &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofUint32)(nil)}
|
|
if err := proto.Unmarshal(wire, m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := m.GetOneofUint32(); got != 1111 {
|
|
t.Errorf("GetOneofUint32() = %v, want %v", got, 1111)
|
|
}
|
|
}
|
|
|
|
func TestDecodeEmptyBytes(t *testing.T) {
|
|
// There's really nothing wrong with a nil entry in a [][]byte,
|
|
// but we take care to produce non-nil []bytes for zero-length
|
|
// byte strings, so test for it.
|
|
m := &testpb.TestAllTypes{}
|
|
b := protopack.Message{
|
|
protopack.Tag{45, protopack.BytesType}, protopack.Bytes(nil),
|
|
}.Marshal()
|
|
if err := proto.Unmarshal(b, m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if m.RepeatedBytes[0] == nil {
|
|
t.Errorf("unmarshaling repeated bytes field containing zero-length value: Got nil bytes, want non-nil")
|
|
}
|
|
}
|
|
|
|
func build(m proto.Message, opts ...buildOpt) proto.Message {
|
|
for _, opt := range opts {
|
|
opt(m)
|
|
}
|
|
return m
|
|
}
|
|
|
|
type buildOpt func(proto.Message)
|
|
|
|
func unknown(raw protoreflect.RawFields) buildOpt {
|
|
return func(m proto.Message) {
|
|
m.ProtoReflect().SetUnknown(raw)
|
|
}
|
|
}
|
|
|
|
func extend(desc protoreflect.ExtensionType, value interface{}) buildOpt {
|
|
return func(m proto.Message) {
|
|
proto.SetExtension(m, desc, value)
|
|
}
|
|
}
|