mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2024-12-26 21:24:22 +00:00
8878926ea7
This is the equivalent of CL 638495, but for the Opaque API. While the behavior is the same for non-synthetic oneofs between the Open Struct API and Opaque API, the behavior for synthetic oneofs is not the same: Because the Opaque API uses a bitfield to store presence, we need to use the Opaque presence check in WhichOneof(). This CL extends the testproto generator to use the protoc command-line flag for the test3 testproto (which specifies syntax = "proto3";), as the in-file api_level is only available in .proto files using editions (but editions does not use synthetic oneofs for optional fields, only proto3 does). For golang/protobuf#1659 Change-Id: I0a1fd6e5fc6f96eeab043f966728ce2a14dbd446 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/638515 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Chressie Himpel <chressie@google.com>
250 lines
7.6 KiB
Go
250 lines
7.6 KiB
Go
// Copyright 2024 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 (
|
|
"testing"
|
|
|
|
test3openpb "google.golang.org/protobuf/internal/testprotos/test3"
|
|
test3hybridpb "google.golang.org/protobuf/internal/testprotos/test3/test3_hybrid"
|
|
test3opaquepb "google.golang.org/protobuf/internal/testprotos/test3/test3_opaque"
|
|
testhybridpb "google.golang.org/protobuf/internal/testprotos/testeditions/testeditions_hybrid"
|
|
testopaquepb "google.golang.org/protobuf/internal/testprotos/testeditions/testeditions_opaque"
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
)
|
|
|
|
func TestOpenWhich(t *testing.T) {
|
|
var x *testhybridpb.TestAllTypes
|
|
if x.WhichOneofField() != 0 {
|
|
t.Errorf("WhichOneofField on nil returned %d, expected %d", x.WhichOneofField(), 0)
|
|
}
|
|
x = &testhybridpb.TestAllTypes{}
|
|
if x.WhichOneofField() != 0 {
|
|
t.Errorf("WhichOneofField returned %d, expected %d", x.WhichOneofField(), 0)
|
|
}
|
|
tab := []struct {
|
|
m *testhybridpb.TestAllTypes
|
|
v protoreflect.FieldNumber
|
|
}{
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofUint32: proto.Uint32(46),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofUint32_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofNestedMessage: testhybridpb.TestAllTypes_NestedMessage_builder{A: proto.Int32(46)}.Build(),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofNestedMessage_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofString: proto.String("foo"),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofString_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofBytes: []byte("foo"),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofBytes_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofBool: proto.Bool(true),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofBool_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofUint64: proto.Uint64(0),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofUint64_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofFloat: proto.Float32(0.0),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofFloat_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofDouble: proto.Float64(1.1),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofDouble_case),
|
|
},
|
|
{
|
|
m: testhybridpb.TestAllTypes_builder{
|
|
OneofEnum: testhybridpb.TestAllTypes_BAZ.Enum(),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testhybridpb.TestAllTypes_OneofEnum_case),
|
|
},
|
|
}
|
|
|
|
for _, mv := range tab {
|
|
if protoreflect.FieldNumber(mv.m.WhichOneofField()) != mv.v {
|
|
t.Errorf("WhichOneofField returned %d, expected %d", mv.m.WhichOneofField(), mv.v)
|
|
}
|
|
if !mv.m.HasOneofField() {
|
|
t.Errorf("HasOneofField returned %t, expected true", mv.m.HasOneofField())
|
|
|
|
}
|
|
mv.m.ClearOneofField()
|
|
if mv.m.WhichOneofField() != 0 {
|
|
t.Errorf("WhichOneofField returned %d, expected %d", mv.m.WhichOneofField(), 0)
|
|
}
|
|
if mv.m.HasOneofField() {
|
|
t.Errorf("HasOneofField returned %t, expected false", mv.m.HasOneofField())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOpaqueWhich(t *testing.T) {
|
|
var x *testopaquepb.TestAllTypes
|
|
if x.WhichOneofField() != 0 {
|
|
t.Errorf("WhichOneofField on nil returned %d, expected %d", x.WhichOneofField(), 0)
|
|
}
|
|
x = &testopaquepb.TestAllTypes{}
|
|
if x.WhichOneofField() != 0 {
|
|
t.Errorf("WhichOneofField returned %d, expected %d", x.WhichOneofField(), 0)
|
|
}
|
|
en := testopaquepb.TestAllTypes_BAZ
|
|
tab := []struct {
|
|
m *testopaquepb.TestAllTypes
|
|
v protoreflect.FieldNumber
|
|
}{
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofUint32: proto.Uint32(46),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofUint32_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofNestedMessage: testopaquepb.TestAllTypes_NestedMessage_builder{A: proto.Int32(46)}.Build(),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofNestedMessage_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofString: proto.String("foo"),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofString_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofBytes: []byte("foo"),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofBytes_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofBool: proto.Bool(true),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofBool_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofUint64: proto.Uint64(0),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofUint64_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofFloat: proto.Float32(0.0),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofFloat_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofDouble: proto.Float64(1.1),
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofDouble_case),
|
|
},
|
|
{
|
|
m: testopaquepb.TestAllTypes_builder{
|
|
OneofEnum: &en,
|
|
}.Build(),
|
|
v: protoreflect.FieldNumber(testopaquepb.TestAllTypes_OneofEnum_case),
|
|
},
|
|
}
|
|
|
|
for _, mv := range tab {
|
|
if protoreflect.FieldNumber(mv.m.WhichOneofField()) != mv.v {
|
|
t.Errorf("WhichOneofField returned %d, expected %d", mv.m.WhichOneofField(), mv.v)
|
|
}
|
|
if !mv.m.HasOneofField() {
|
|
t.Errorf("HasOneofField returned %t, expected true", mv.m.HasOneofField())
|
|
|
|
}
|
|
mv.m.ClearOneofField()
|
|
if mv.m.WhichOneofField() != 0 {
|
|
t.Errorf("WhichOneofField returned %d, expected %d", mv.m.WhichOneofField(), 0)
|
|
}
|
|
if mv.m.HasOneofField() {
|
|
t.Errorf("HasOneofField returned %t, expected false", mv.m.HasOneofField())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSyntheticOneofOpen(t *testing.T) {
|
|
msg := test3openpb.TestAllTypes{}
|
|
md := msg.ProtoReflect().Descriptor()
|
|
ood := md.Oneofs().ByName("_optional_int32")
|
|
if ood == nil {
|
|
t.Fatal("failed to find oneof _optional_int32")
|
|
}
|
|
if !ood.IsSynthetic() {
|
|
t.Fatal("oneof _optional_int32 should be synthetic")
|
|
}
|
|
if msg.ProtoReflect().WhichOneof(ood) != nil {
|
|
t.Error("oneof _optional_int32 should not have a field set yet")
|
|
}
|
|
msg.OptionalInt32 = proto.Int32(123)
|
|
if msg.ProtoReflect().WhichOneof(ood) == nil {
|
|
t.Error("oneof _optional_int32 should have a field set")
|
|
}
|
|
}
|
|
|
|
func TestSyntheticOneofHybrid(t *testing.T) {
|
|
msg := test3hybridpb.TestAllTypes{}
|
|
md := msg.ProtoReflect().Descriptor()
|
|
ood := md.Oneofs().ByName("_optional_int32")
|
|
if ood == nil {
|
|
t.Fatal("failed to find oneof _optional_int32")
|
|
}
|
|
if !ood.IsSynthetic() {
|
|
t.Fatal("oneof _optional_int32 should be synthetic")
|
|
}
|
|
if msg.ProtoReflect().WhichOneof(ood) != nil {
|
|
t.Error("oneof _optional_int32 should not have a field set yet")
|
|
}
|
|
msg.OptionalInt32 = proto.Int32(123)
|
|
if msg.ProtoReflect().WhichOneof(ood) == nil {
|
|
t.Error("oneof _optional_int32 should have a field set")
|
|
}
|
|
}
|
|
|
|
func TestSyntheticOneofOpaque(t *testing.T) {
|
|
msg := test3opaquepb.TestAllTypes{}
|
|
md := msg.ProtoReflect().Descriptor()
|
|
ood := md.Oneofs().ByName("_optional_int32")
|
|
if ood == nil {
|
|
t.Fatal("failed to find oneof _optional_int32")
|
|
}
|
|
if !ood.IsSynthetic() {
|
|
t.Fatal("oneof _optional_int32 should be synthetic")
|
|
}
|
|
if msg.ProtoReflect().WhichOneof(ood) != nil {
|
|
t.Error("oneof _optional_int32 should not have a field set yet")
|
|
}
|
|
msg.SetOptionalInt32(123)
|
|
if msg.ProtoReflect().WhichOneof(ood) == nil {
|
|
t.Error("oneof _optional_int32 should have a field set")
|
|
}
|
|
}
|