protobuf-go/proto/extension_test.go
Damien Neil d025c95110 proto, internal/protobuild: add test proto template builder
The proto package tests often test several variations of messages with a
similar shape. For example, most tests are performed with a proto2
message with a regular field, a proto2 message with an extension field,
and a proto3 message.

Add a protobuild package which can initialize all these variations from
a single template. For example, these three messages:

	&testpb.TestAllTypes{OptionalInt32: proto.Int32(1)}

	&test3pb.TestAllTypes{OptionalInt32: 1}

	m := &testpb.TestAllExtensions{}
	proto.SetExtension(m, &testpb.E_OptionalInt32, 1)

can all be constructed from the template:

	protobuild.Message{"optional_int32": 1}

This reduces redundancy in tests and will make it more practical to
test alternative code generators.

Change-Id: I3245a4bf74ee1bce957bc772fed513d427720677
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/217457
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2020-02-03 19:14:55 +00:00

106 lines
3.3 KiB
Go

// 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 proto_test
import (
"fmt"
"sync"
"testing"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoimpl"
legacy1pb "google.golang.org/protobuf/internal/testprotos/legacy/proto2_20160225_2fc053c5"
testpb "google.golang.org/protobuf/internal/testprotos/test"
)
func TestExtensionFuncs(t *testing.T) {
for _, test := range []struct {
message proto.Message
ext pref.ExtensionType
wantDefault interface{}
value interface{}
}{
{
message: &testpb.TestAllExtensions{},
ext: testpb.E_OptionalInt32,
wantDefault: int32(0),
value: int32(1),
},
{
message: &testpb.TestAllExtensions{},
ext: testpb.E_RepeatedString,
wantDefault: ([]string)(nil),
value: []string{"a", "b", "c"},
},
{
message: protoimpl.X.MessageOf(&legacy1pb.Message{}).Interface(),
ext: legacy1pb.E_Message_ExtensionOptionalBool,
wantDefault: false,
value: true,
},
} {
desc := fmt.Sprintf("Extension %v, value %v", test.ext.TypeDescriptor().FullName(), test.value)
if proto.HasExtension(test.message, test.ext) {
t.Errorf("%v:\nbefore setting extension HasExtension(...) = true, want false", desc)
}
got := proto.GetExtension(test.message, test.ext)
if d := cmp.Diff(test.wantDefault, got); d != "" {
t.Errorf("%v:\nbefore setting extension GetExtension(...) returns unexpected value (-want,+got):\n%v", desc, d)
}
proto.SetExtension(test.message, test.ext, test.value)
if !proto.HasExtension(test.message, test.ext) {
t.Errorf("%v:\nafter setting extension HasExtension(...) = false, want true", desc)
}
got = proto.GetExtension(test.message, test.ext)
if d := cmp.Diff(test.value, got); d != "" {
t.Errorf("%v:\nafter setting extension GetExtension(...) returns unexpected value (-want,+got):\n%v", desc, d)
}
proto.ClearExtension(test.message, test.ext)
if proto.HasExtension(test.message, test.ext) {
t.Errorf("%v:\nafter clearing extension HasExtension(...) = true, want false", desc)
}
}
}
func TestExtensionGetRace(t *testing.T) {
// Concurrently fetch an extension value while marshaling the message containing it.
// Create the message with proto.Unmarshal to give lazy extension decoding (if present)
// a chance to occur.
want := int32(42)
m1 := &testpb.TestAllExtensions{}
proto.SetExtension(m1, testpb.E_OptionalNestedMessage, &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(want)})
b, err := proto.Marshal(m1)
if err != nil {
t.Fatal(err)
}
m := &testpb.TestAllExtensions{}
if err := proto.Unmarshal(b, m); err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
if _, err := proto.Marshal(m); err != nil {
t.Error(err)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
got := proto.GetExtension(m, testpb.E_OptionalNestedMessage).(*testpb.TestAllExtensions_NestedMessage).GetA()
if got != want {
t.Errorf("GetExtension(optional_nested_message).a = %v, want %v", got, want)
}
}()
}
wg.Wait()
}