...

Source file src/google.golang.org/protobuf/internal/impl/legacy_test.go

Documentation: google.golang.org/protobuf/internal/impl

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package impl_test
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/google/go-cmp/cmp"
    14  	"github.com/google/go-cmp/cmp/cmpopts"
    15  
    16  	"google.golang.org/protobuf/encoding/prototext"
    17  	pimpl "google.golang.org/protobuf/internal/impl"
    18  	"google.golang.org/protobuf/internal/pragma"
    19  	"google.golang.org/protobuf/proto"
    20  	"google.golang.org/protobuf/reflect/protodesc"
    21  	"google.golang.org/protobuf/reflect/protoreflect"
    22  	"google.golang.org/protobuf/reflect/protoregistry"
    23  	"google.golang.org/protobuf/runtime/protoiface"
    24  
    25  	proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2_20180125_92554152"
    26  	"google.golang.org/protobuf/types/descriptorpb"
    27  )
    28  
    29  type LegacyTestMessage struct {
    30  	XXX_unrecognized       []byte
    31  	XXX_InternalExtensions map[int32]pimpl.ExtensionField
    32  }
    33  
    34  func (*LegacyTestMessage) Reset()         {}
    35  func (*LegacyTestMessage) String() string { return "" }
    36  func (*LegacyTestMessage) ProtoMessage()  {}
    37  func (*LegacyTestMessage) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
    38  	return []protoiface.ExtensionRangeV1{{Start: 10, End: 20}, {Start: 40, End: 80}, {Start: 10000, End: 20000}}
    39  }
    40  func (*LegacyTestMessage) Descriptor() ([]byte, []int) { return legacyFD, []int{0} }
    41  
    42  var legacyFD = func() []byte {
    43  	b, _ := proto.Marshal(protodesc.ToFileDescriptorProto(mustMakeFileDesc(`
    44  		name:   "legacy.proto"
    45  		syntax: "proto2"
    46  		message_type: [{
    47  			name:            "LegacyTestMessage"
    48  			extension_range: [{start:10 end:20}, {start:40 end:80}, {start:10000 end:20000}]
    49  		}]
    50  	`, nil)))
    51  	return pimpl.Export{}.CompressGZIP(b)
    52  }()
    53  
    54  func init() {
    55  	mt := pimpl.Export{}.MessageTypeOf((*LegacyTestMessage)(nil))
    56  	protoregistry.GlobalFiles.RegisterFile(mt.Descriptor().ParentFile())
    57  	protoregistry.GlobalTypes.RegisterMessage(mt)
    58  }
    59  
    60  func mustMakeExtensionType(fileDesc, extDesc string, t reflect.Type, r protodesc.Resolver) protoreflect.ExtensionType {
    61  	s := fmt.Sprintf(`name:"test.proto" syntax:"proto2" %s extension:[{%s}]`, fileDesc, extDesc)
    62  	xd := mustMakeFileDesc(s, r).Extensions().Get(0)
    63  	xi := &pimpl.ExtensionInfo{}
    64  	pimpl.InitExtensionInfo(xi, xd, t)
    65  	return xi
    66  }
    67  
    68  func mustMakeFileDesc(s string, r protodesc.Resolver) protoreflect.FileDescriptor {
    69  	pb := new(descriptorpb.FileDescriptorProto)
    70  	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
    71  		panic(err)
    72  	}
    73  	fd, err := protodesc.NewFile(pb, r)
    74  	if err != nil {
    75  		panic(err)
    76  	}
    77  	return fd
    78  }
    79  
    80  var (
    81  	testParentDesc    = pimpl.Export{}.MessageDescriptorOf((*LegacyTestMessage)(nil))
    82  	testEnumV1Desc    = pimpl.Export{}.EnumDescriptorOf(proto2_20180125.Message_ChildEnum(0))
    83  	testMessageV1Desc = pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message_ChildMessage)(nil))
    84  	testMessageV2Desc = enumMessagesType.Desc
    85  
    86  	depReg = newFileRegistry(
    87  		testParentDesc.ParentFile(),
    88  		testEnumV1Desc.ParentFile(),
    89  		testMessageV1Desc.ParentFile(),
    90  		enumProto2Desc.ParentFile(),
    91  		testMessageV2Desc.ParentFile(),
    92  	)
    93  	extensionTypes = []protoreflect.ExtensionType{
    94  		mustMakeExtensionType(
    95  			`package:"fizz.buzz" dependency:"legacy.proto"`,
    96  			`name:"optional_bool" number:10000 label:LABEL_OPTIONAL type:TYPE_BOOL default_value:"true" extendee:".LegacyTestMessage"`,
    97  			reflect.TypeOf(false), depReg,
    98  		),
    99  		mustMakeExtensionType(
   100  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   101  			`name:"optional_int32" number:10001 label:LABEL_OPTIONAL type:TYPE_INT32 default_value:"-12345" extendee:".LegacyTestMessage"`,
   102  			reflect.TypeOf(int32(0)), depReg,
   103  		),
   104  		mustMakeExtensionType(
   105  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   106  			`name:"optional_uint32" number:10002 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"3200" extendee:".LegacyTestMessage"`,
   107  			reflect.TypeOf(uint32(0)), depReg,
   108  		),
   109  		mustMakeExtensionType(
   110  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   111  			`name:"optional_float" number:10003 label:LABEL_OPTIONAL type:TYPE_FLOAT default_value:"3.14159" extendee:".LegacyTestMessage"`,
   112  			reflect.TypeOf(float32(0)), depReg,
   113  		),
   114  		mustMakeExtensionType(
   115  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   116  			`name:"optional_string" number:10004 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"hello, \"world!\"\n" extendee:".LegacyTestMessage"`,
   117  			reflect.TypeOf(""), depReg,
   118  		),
   119  		mustMakeExtensionType(
   120  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   121  			`name:"optional_bytes" number:10005 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"dead\\336\\255\\276\\357beef" extendee:".LegacyTestMessage"`,
   122  			reflect.TypeOf(([]byte)(nil)), depReg,
   123  		),
   124  		mustMakeExtensionType(
   125  			`package:"fizz.buzz" dependency:["legacy.proto", "proto2_20180125_92554152/test.proto"]`,
   126  			`name:"optional_enum_v1" number:10006 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".google.golang.org.proto2_20180125.Message.ChildEnum" default_value:"ALPHA" extendee:".LegacyTestMessage"`,
   127  			reflect.TypeOf(proto2_20180125.Message_ChildEnum(0)), depReg,
   128  		),
   129  		mustMakeExtensionType(
   130  			`package:"fizz.buzz" dependency:["legacy.proto", "proto2_20180125_92554152/test.proto"]`,
   131  			`name:"optional_message_v1" number:10007 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message.ChildMessage" extendee:".LegacyTestMessage"`,
   132  			reflect.TypeOf((*proto2_20180125.Message_ChildMessage)(nil)), depReg,
   133  		),
   134  		mustMakeExtensionType(
   135  			`package:"fizz.buzz" dependency:["legacy.proto", "enum2.proto"]`,
   136  			`name:"optional_enum_v2" number:10008 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto2" default_value:"DEAD" extendee:".LegacyTestMessage"`,
   137  			reflect.TypeOf(EnumProto2(0)), depReg,
   138  		),
   139  		mustMakeExtensionType(
   140  			`package:"fizz.buzz" dependency:["legacy.proto", "enum-messages.proto"]`,
   141  			`name:"optional_message_v2" number:10009 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".EnumMessages" extendee:".LegacyTestMessage"`,
   142  			reflect.TypeOf((*EnumMessages)(nil)), depReg,
   143  		),
   144  		mustMakeExtensionType(
   145  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   146  			`name:"repeated_bool" number:10010 label:LABEL_REPEATED type:TYPE_BOOL extendee:".LegacyTestMessage"`,
   147  			reflect.TypeOf([]bool(nil)), depReg,
   148  		),
   149  		mustMakeExtensionType(
   150  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   151  			`name:"repeated_int32" number:10011 label:LABEL_REPEATED type:TYPE_INT32 extendee:".LegacyTestMessage"`,
   152  			reflect.TypeOf([]int32(nil)), depReg,
   153  		),
   154  		mustMakeExtensionType(
   155  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   156  			`name:"repeated_uint32" number:10012 label:LABEL_REPEATED type:TYPE_UINT32 extendee:".LegacyTestMessage"`,
   157  			reflect.TypeOf([]uint32(nil)), depReg,
   158  		),
   159  		mustMakeExtensionType(
   160  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   161  			`name:"repeated_float" number:10013 label:LABEL_REPEATED type:TYPE_FLOAT extendee:".LegacyTestMessage"`,
   162  			reflect.TypeOf([]float32(nil)), depReg,
   163  		),
   164  		mustMakeExtensionType(
   165  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   166  			`name:"repeated_string" number:10014 label:LABEL_REPEATED type:TYPE_STRING extendee:".LegacyTestMessage"`,
   167  			reflect.TypeOf([]string(nil)), depReg,
   168  		),
   169  		mustMakeExtensionType(
   170  			`package:"fizz.buzz" dependency:"legacy.proto"`,
   171  			`name:"repeated_bytes" number:10015 label:LABEL_REPEATED type:TYPE_BYTES extendee:".LegacyTestMessage"`,
   172  			reflect.TypeOf([][]byte(nil)), depReg,
   173  		),
   174  		mustMakeExtensionType(
   175  			`package:"fizz.buzz" dependency:["legacy.proto", "proto2_20180125_92554152/test.proto"]`,
   176  			`name:"repeated_enum_v1" number:10016 label:LABEL_REPEATED type:TYPE_ENUM type_name:".google.golang.org.proto2_20180125.Message.ChildEnum" extendee:".LegacyTestMessage"`,
   177  			reflect.TypeOf([]proto2_20180125.Message_ChildEnum(nil)), depReg,
   178  		),
   179  		mustMakeExtensionType(
   180  			`package:"fizz.buzz" dependency:["legacy.proto", "proto2_20180125_92554152/test.proto"]`,
   181  			`name:"repeated_message_v1" number:10017 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message.ChildMessage" extendee:".LegacyTestMessage"`,
   182  			reflect.TypeOf([]*proto2_20180125.Message_ChildMessage(nil)), depReg,
   183  		),
   184  		mustMakeExtensionType(
   185  			`package:"fizz.buzz" dependency:["legacy.proto", "enum2.proto"]`,
   186  			`name:"repeated_enum_v2" number:10018 label:LABEL_REPEATED type:TYPE_ENUM type_name:".EnumProto2" extendee:".LegacyTestMessage"`,
   187  			reflect.TypeOf([]EnumProto2(nil)), depReg,
   188  		),
   189  		mustMakeExtensionType(
   190  			`package:"fizz.buzz" dependency:["legacy.proto", "enum-messages.proto"]`,
   191  			`name:"repeated_message_v2" number:10019 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages" extendee:".LegacyTestMessage"`,
   192  			reflect.TypeOf([]*EnumMessages(nil)), depReg,
   193  		),
   194  	}
   195  
   196  	extensionDescs = []*pimpl.ExtensionInfo{{
   197  		ExtendedType:  (*LegacyTestMessage)(nil),
   198  		ExtensionType: (*bool)(nil),
   199  		Field:         10000,
   200  		Name:          "fizz.buzz.optional_bool",
   201  		Tag:           "varint,10000,opt,name=optional_bool,def=1",
   202  		Filename:      "test.proto",
   203  	}, {
   204  		ExtendedType:  (*LegacyTestMessage)(nil),
   205  		ExtensionType: (*int32)(nil),
   206  		Field:         10001,
   207  		Name:          "fizz.buzz.optional_int32",
   208  		Tag:           "varint,10001,opt,name=optional_int32,def=-12345",
   209  		Filename:      "test.proto",
   210  	}, {
   211  		ExtendedType:  (*LegacyTestMessage)(nil),
   212  		ExtensionType: (*uint32)(nil),
   213  		Field:         10002,
   214  		Name:          "fizz.buzz.optional_uint32",
   215  		Tag:           "varint,10002,opt,name=optional_uint32,def=3200",
   216  		Filename:      "test.proto",
   217  	}, {
   218  		ExtendedType:  (*LegacyTestMessage)(nil),
   219  		ExtensionType: (*float32)(nil),
   220  		Field:         10003,
   221  		Name:          "fizz.buzz.optional_float",
   222  		Tag:           "fixed32,10003,opt,name=optional_float,def=3.14159",
   223  		Filename:      "test.proto",
   224  	}, {
   225  		ExtendedType:  (*LegacyTestMessage)(nil),
   226  		ExtensionType: (*string)(nil),
   227  		Field:         10004,
   228  		Name:          "fizz.buzz.optional_string",
   229  		Tag:           "bytes,10004,opt,name=optional_string,def=hello, \"world!\"\n",
   230  		Filename:      "test.proto",
   231  	}, {
   232  		ExtendedType:  (*LegacyTestMessage)(nil),
   233  		ExtensionType: ([]byte)(nil),
   234  		Field:         10005,
   235  		Name:          "fizz.buzz.optional_bytes",
   236  		Tag:           "bytes,10005,opt,name=optional_bytes,def=dead\\336\\255\\276\\357beef",
   237  		Filename:      "test.proto",
   238  	}, {
   239  		ExtendedType:  (*LegacyTestMessage)(nil),
   240  		ExtensionType: (*proto2_20180125.Message_ChildEnum)(nil),
   241  		Field:         10006,
   242  		Name:          "fizz.buzz.optional_enum_v1",
   243  		Tag:           "varint,10006,opt,name=optional_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum,def=0",
   244  		Filename:      "test.proto",
   245  	}, {
   246  		ExtendedType:  (*LegacyTestMessage)(nil),
   247  		ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil),
   248  		Field:         10007,
   249  		Name:          "fizz.buzz.optional_message_v1",
   250  		Tag:           "bytes,10007,opt,name=optional_message_v1",
   251  		Filename:      "test.proto",
   252  	}, {
   253  		ExtendedType:  (*LegacyTestMessage)(nil),
   254  		ExtensionType: (*EnumProto2)(nil),
   255  		Field:         10008,
   256  		Name:          "fizz.buzz.optional_enum_v2",
   257  		Tag:           "varint,10008,opt,name=optional_enum_v2,enum=EnumProto2,def=57005",
   258  		Filename:      "test.proto",
   259  	}, {
   260  		ExtendedType:  (*LegacyTestMessage)(nil),
   261  		ExtensionType: (*EnumMessages)(nil),
   262  		Field:         10009,
   263  		Name:          "fizz.buzz.optional_message_v2",
   264  		Tag:           "bytes,10009,opt,name=optional_message_v2",
   265  		Filename:      "test.proto",
   266  	}, {
   267  		ExtendedType:  (*LegacyTestMessage)(nil),
   268  		ExtensionType: ([]bool)(nil),
   269  		Field:         10010,
   270  		Name:          "fizz.buzz.repeated_bool",
   271  		Tag:           "varint,10010,rep,name=repeated_bool",
   272  		Filename:      "test.proto",
   273  	}, {
   274  		ExtendedType:  (*LegacyTestMessage)(nil),
   275  		ExtensionType: ([]int32)(nil),
   276  		Field:         10011,
   277  		Name:          "fizz.buzz.repeated_int32",
   278  		Tag:           "varint,10011,rep,name=repeated_int32",
   279  		Filename:      "test.proto",
   280  	}, {
   281  		ExtendedType:  (*LegacyTestMessage)(nil),
   282  		ExtensionType: ([]uint32)(nil),
   283  		Field:         10012,
   284  		Name:          "fizz.buzz.repeated_uint32",
   285  		Tag:           "varint,10012,rep,name=repeated_uint32",
   286  		Filename:      "test.proto",
   287  	}, {
   288  		ExtendedType:  (*LegacyTestMessage)(nil),
   289  		ExtensionType: ([]float32)(nil),
   290  		Field:         10013,
   291  		Name:          "fizz.buzz.repeated_float",
   292  		Tag:           "fixed32,10013,rep,name=repeated_float",
   293  		Filename:      "test.proto",
   294  	}, {
   295  		ExtendedType:  (*LegacyTestMessage)(nil),
   296  		ExtensionType: ([]string)(nil),
   297  		Field:         10014,
   298  		Name:          "fizz.buzz.repeated_string",
   299  		Tag:           "bytes,10014,rep,name=repeated_string",
   300  		Filename:      "test.proto",
   301  	}, {
   302  		ExtendedType:  (*LegacyTestMessage)(nil),
   303  		ExtensionType: ([][]byte)(nil),
   304  		Field:         10015,
   305  		Name:          "fizz.buzz.repeated_bytes",
   306  		Tag:           "bytes,10015,rep,name=repeated_bytes",
   307  		Filename:      "test.proto",
   308  	}, {
   309  		ExtendedType:  (*LegacyTestMessage)(nil),
   310  		ExtensionType: ([]proto2_20180125.Message_ChildEnum)(nil),
   311  		Field:         10016,
   312  		Name:          "fizz.buzz.repeated_enum_v1",
   313  		Tag:           "varint,10016,rep,name=repeated_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum",
   314  		Filename:      "test.proto",
   315  	}, {
   316  		ExtendedType:  (*LegacyTestMessage)(nil),
   317  		ExtensionType: ([]*proto2_20180125.Message_ChildMessage)(nil),
   318  		Field:         10017,
   319  		Name:          "fizz.buzz.repeated_message_v1",
   320  		Tag:           "bytes,10017,rep,name=repeated_message_v1",
   321  		Filename:      "test.proto",
   322  	}, {
   323  		ExtendedType:  (*LegacyTestMessage)(nil),
   324  		ExtensionType: ([]EnumProto2)(nil),
   325  		Field:         10018,
   326  		Name:          "fizz.buzz.repeated_enum_v2",
   327  		Tag:           "varint,10018,rep,name=repeated_enum_v2,enum=EnumProto2",
   328  		Filename:      "test.proto",
   329  	}, {
   330  		ExtendedType:  (*LegacyTestMessage)(nil),
   331  		ExtensionType: ([]*EnumMessages)(nil),
   332  		Field:         10019,
   333  		Name:          "fizz.buzz.repeated_message_v2",
   334  		Tag:           "bytes,10019,rep,name=repeated_message_v2",
   335  		Filename:      "test.proto",
   336  	}}
   337  )
   338  
   339  func TestLegacyExtensions(t *testing.T) {
   340  	opts := cmp.Options{cmp.Comparer(func(x, y *proto2_20180125.Message_ChildMessage) bool {
   341  		return x == y // pointer compare messages for object identity
   342  	})}
   343  
   344  	m := pimpl.Export{}.MessageOf(new(LegacyTestMessage))
   345  
   346  	// Check that getting the zero value returns the default value for scalars,
   347  	// nil for singular messages, and an empty list for repeated fields.
   348  	defaultValues := map[int]interface{}{
   349  		0: bool(true),
   350  		1: int32(-12345),
   351  		2: uint32(3200),
   352  		3: float32(3.14159),
   353  		4: string("hello, \"world!\"\n"),
   354  		5: []byte("dead\xde\xad\xbe\xefbeef"),
   355  		6: proto2_20180125.Message_ALPHA,
   356  		7: nil,
   357  		8: EnumProto2(0xdead),
   358  		9: nil,
   359  	}
   360  	for i, xt := range extensionTypes {
   361  		var got interface{}
   362  		xd := xt.TypeDescriptor()
   363  		if !(xd.IsList() || xd.IsMap() || xd.Message() != nil) {
   364  			got = xt.InterfaceOf(m.Get(xd))
   365  		}
   366  		want := defaultValues[i]
   367  		if diff := cmp.Diff(want, got, opts); diff != "" {
   368  			t.Errorf("Message.Get(%d) mismatch (-want +got):\n%v", xd.Number(), diff)
   369  		}
   370  	}
   371  
   372  	// All fields should be unpopulated.
   373  	for _, xt := range extensionTypes {
   374  		xd := xt.TypeDescriptor()
   375  		if m.Has(xd) {
   376  			t.Errorf("Message.Has(%d) = true, want false", xd.Number())
   377  		}
   378  	}
   379  
   380  	// Set some values and append to values to the lists.
   381  	m1a := &proto2_20180125.Message_ChildMessage{F1: proto.String("m1a")}
   382  	m1b := &proto2_20180125.Message_ChildMessage{F1: proto.String("m2b")}
   383  	m2a := &EnumMessages{EnumP2: EnumProto2(0x1b).Enum()}
   384  	m2b := &EnumMessages{EnumP2: EnumProto2(0x2b).Enum()}
   385  	setValues := map[int]interface{}{
   386  		0:  bool(false),
   387  		1:  int32(-54321),
   388  		2:  uint32(6400),
   389  		3:  float32(2.71828),
   390  		4:  string("goodbye, \"world!\"\n"),
   391  		5:  []byte("live\xde\xad\xbe\xefchicken"),
   392  		6:  proto2_20180125.Message_CHARLIE,
   393  		7:  m1a,
   394  		8:  EnumProto2(0xbeef),
   395  		9:  m2a,
   396  		10: []bool{true},
   397  		11: []int32{-1000},
   398  		12: []uint32{1280},
   399  		13: []float32{1.6180},
   400  		14: []string{"zero"},
   401  		15: [][]byte{[]byte("zero")},
   402  		16: []proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
   403  		17: []*proto2_20180125.Message_ChildMessage{m1b},
   404  		18: []EnumProto2{0xdead},
   405  		19: []*EnumMessages{m2b},
   406  	}
   407  	for i, xt := range extensionTypes {
   408  		m.Set(xt.TypeDescriptor(), xt.ValueOf(setValues[i]))
   409  	}
   410  	for i, xt := range extensionTypes[len(extensionTypes)/2:] {
   411  		v := extensionTypes[i].ValueOf(setValues[i])
   412  		m.Get(xt.TypeDescriptor()).List().Append(v)
   413  	}
   414  
   415  	// Get the values and check for equality.
   416  	getValues := map[int]interface{}{
   417  		0:  bool(false),
   418  		1:  int32(-54321),
   419  		2:  uint32(6400),
   420  		3:  float32(2.71828),
   421  		4:  string("goodbye, \"world!\"\n"),
   422  		5:  []byte("live\xde\xad\xbe\xefchicken"),
   423  		6:  proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE),
   424  		7:  m1a,
   425  		8:  EnumProto2(0xbeef),
   426  		9:  m2a,
   427  		10: []bool{true, false},
   428  		11: []int32{-1000, -54321},
   429  		12: []uint32{1280, 6400},
   430  		13: []float32{1.6180, 2.71828},
   431  		14: []string{"zero", "goodbye, \"world!\"\n"},
   432  		15: [][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
   433  		16: []proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
   434  		17: []*proto2_20180125.Message_ChildMessage{m1b, m1a},
   435  		18: []EnumProto2{0xdead, 0xbeef},
   436  		19: []*EnumMessages{m2b, m2a},
   437  	}
   438  	for i, xt := range extensionTypes {
   439  		xd := xt.TypeDescriptor()
   440  		got := xt.InterfaceOf(m.Get(xd))
   441  		want := getValues[i]
   442  		if diff := cmp.Diff(want, got, opts); diff != "" {
   443  			t.Errorf("Message.Get(%d) mismatch (-want +got):\n%v", xd.Number(), diff)
   444  		}
   445  	}
   446  
   447  	// Clear all singular fields and truncate all repeated fields.
   448  	for _, xt := range extensionTypes[:len(extensionTypes)/2] {
   449  		m.Clear(xt.TypeDescriptor())
   450  	}
   451  	for _, xt := range extensionTypes[len(extensionTypes)/2:] {
   452  		m.Get(xt.TypeDescriptor()).List().Truncate(0)
   453  	}
   454  
   455  	// Clear all repeated fields.
   456  	for _, xt := range extensionTypes[len(extensionTypes)/2:] {
   457  		m.Clear(xt.TypeDescriptor())
   458  	}
   459  }
   460  
   461  func TestLegacyExtensionConvert(t *testing.T) {
   462  	for i := range extensionTypes {
   463  		i := i
   464  		t.Run("", func(t *testing.T) {
   465  			t.Parallel()
   466  
   467  			wantType := extensionTypes[i]
   468  			wantDesc := extensionDescs[i]
   469  			gotType := (protoreflect.ExtensionType)(wantDesc)
   470  			gotDesc := wantType.(*pimpl.ExtensionInfo)
   471  
   472  			// Concurrently call accessors to trigger possible races.
   473  			for _, xt := range []protoreflect.ExtensionType{wantType, wantDesc} {
   474  				xt := xt
   475  				go func() { xt.New() }()
   476  				go func() { xt.Zero() }()
   477  				go func() { xt.TypeDescriptor() }()
   478  			}
   479  
   480  			// TODO: We need a test package to compare descriptors.
   481  			type list interface {
   482  				Len() int
   483  				pragma.DoNotImplement
   484  			}
   485  			opts := cmp.Options{
   486  				cmp.Comparer(func(x, y reflect.Type) bool {
   487  					return x == y
   488  				}),
   489  				cmp.Transformer("", func(x list) []interface{} {
   490  					out := make([]interface{}, x.Len())
   491  					v := reflect.ValueOf(x)
   492  					for i := 0; i < x.Len(); i++ {
   493  						m := v.MethodByName("Get")
   494  						out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
   495  					}
   496  					return out
   497  				}),
   498  				cmp.Transformer("", func(x protoreflect.Descriptor) map[string]interface{} {
   499  					out := make(map[string]interface{})
   500  					v := reflect.ValueOf(x)
   501  					for i := 0; i < v.NumMethod(); i++ {
   502  						name := v.Type().Method(i).Name
   503  						if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
   504  							switch name {
   505  							case "ParentFile", "Parent":
   506  							// Ignore parents to avoid recursive cycle.
   507  							case "Options":
   508  								// Ignore descriptor options since protos are not cmperable.
   509  							case "ContainingOneof", "ContainingMessage", "Enum", "Message":
   510  								// Avoid descending into a dependency to avoid a cycle.
   511  								// Just record the full name if available.
   512  								//
   513  								// TODO: Cycle support in cmp would be useful here.
   514  								v := m.Call(nil)[0]
   515  								if !v.IsNil() {
   516  									out[name] = v.Interface().(protoreflect.Descriptor).FullName()
   517  								}
   518  							case "Type":
   519  								// Ignore ExtensionTypeDescriptor.Type method to avoid cycle.
   520  							default:
   521  								out[name] = m.Call(nil)[0].Interface()
   522  							}
   523  						}
   524  					}
   525  					return out
   526  				}),
   527  				cmp.Transformer("", func(xt protoreflect.ExtensionType) map[string]interface{} {
   528  					return map[string]interface{}{
   529  						"Descriptor": xt.TypeDescriptor(),
   530  					}
   531  				}),
   532  				cmp.Transformer("", func(v protoreflect.Value) interface{} {
   533  					return v.Interface()
   534  				}),
   535  			}
   536  			if diff := cmp.Diff(&wantType, &gotType, opts); diff != "" {
   537  				t.Errorf("ExtensionType mismatch (-want, +got):\n%v", diff)
   538  			}
   539  
   540  			opts = cmp.Options{
   541  				cmpopts.IgnoreFields(pimpl.ExtensionInfo{}, "ExtensionType"),
   542  				cmpopts.IgnoreUnexported(pimpl.ExtensionInfo{}),
   543  			}
   544  			if diff := cmp.Diff(wantDesc, gotDesc, opts); diff != "" {
   545  				t.Errorf("ExtensionDesc mismatch (-want, +got):\n%v", diff)
   546  			}
   547  		})
   548  	}
   549  }
   550  
   551  type (
   552  	MessageA struct {
   553  		A1 *MessageA `protobuf:"bytes,1,req,name=a1"`
   554  		A2 *MessageB `protobuf:"bytes,2,req,name=a2"`
   555  		A3 Enum      `protobuf:"varint,3,opt,name=a3,enum=legacy.Enum"`
   556  	}
   557  	MessageB struct {
   558  		B1 *MessageA `protobuf:"bytes,1,req,name=b1"`
   559  		B2 *MessageB `protobuf:"bytes,2,req,name=b2"`
   560  		B3 Enum      `protobuf:"varint,3,opt,name=b3,enum=legacy.Enum"`
   561  	}
   562  	Enum int32
   563  )
   564  
   565  func (*MessageA) Reset()                      { panic("not implemented") }
   566  func (*MessageA) String() string              { panic("not implemented") }
   567  func (*MessageA) ProtoMessage()               { panic("not implemented") }
   568  func (*MessageA) Descriptor() ([]byte, []int) { return concurrentFD, []int{0} }
   569  
   570  func (*MessageB) Reset()                      { panic("not implemented") }
   571  func (*MessageB) String() string              { panic("not implemented") }
   572  func (*MessageB) ProtoMessage()               { panic("not implemented") }
   573  func (*MessageB) Descriptor() ([]byte, []int) { return concurrentFD, []int{1} }
   574  
   575  func (Enum) EnumDescriptor() ([]byte, []int) { return concurrentFD, []int{0} }
   576  
   577  var concurrentFD = func() []byte {
   578  	b, _ := proto.Marshal(protodesc.ToFileDescriptorProto(mustMakeFileDesc(`
   579  		name:    "concurrent.proto"
   580  		syntax:  "proto2"
   581  		package: "legacy"
   582  		message_type: [{
   583  			name: "MessageA"
   584  			field: [
   585  				{name:"a1" number:1 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageA"},
   586  				{name:"a2" number:2 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageB"},
   587  				{name:"a3" number:3 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".legacy.Enum"}
   588  			]
   589  		}, {
   590  			name: "MessageB"
   591  			field: [
   592  				{name:"a1" number:1 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageA"},
   593  				{name:"a2" number:2 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageB"},
   594  				{name:"a3" number:3 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".legacy.Enum"}
   595  			]
   596  		}]
   597  		enum_type: [{
   598  			name:  "Enum"
   599  			value: [{name:"FOO" number:500}]
   600  		}]
   601  	`, nil)))
   602  	return pimpl.Export{}.CompressGZIP(b)
   603  }()
   604  
   605  // TestLegacyConcurrentInit tests that concurrent wrapping of multiple legacy types
   606  // results in the exact same descriptor being created.
   607  func TestLegacyConcurrentInit(t *testing.T) {
   608  	const numParallel = 5
   609  	var messageATypes [numParallel]protoreflect.MessageType
   610  	var messageBTypes [numParallel]protoreflect.MessageType
   611  	var enumDescs [numParallel]protoreflect.EnumDescriptor
   612  
   613  	// Concurrently load message and enum types.
   614  	var wg sync.WaitGroup
   615  	for i := 0; i < numParallel; i++ {
   616  		i := i
   617  		wg.Add(3)
   618  		go func() {
   619  			defer wg.Done()
   620  			messageATypes[i] = pimpl.Export{}.MessageTypeOf((*MessageA)(nil))
   621  		}()
   622  		go func() {
   623  			defer wg.Done()
   624  			messageBTypes[i] = pimpl.Export{}.MessageTypeOf((*MessageB)(nil))
   625  		}()
   626  		go func() {
   627  			defer wg.Done()
   628  			enumDescs[i] = pimpl.Export{}.EnumDescriptorOf(Enum(0))
   629  		}()
   630  	}
   631  	wg.Wait()
   632  
   633  	var (
   634  		wantMTA = messageATypes[0]
   635  		wantMDA = messageATypes[0].Descriptor().Fields().ByNumber(1).Message()
   636  		wantMTB = messageBTypes[0]
   637  		wantMDB = messageBTypes[0].Descriptor().Fields().ByNumber(2).Message()
   638  		wantED  = messageATypes[0].Descriptor().Fields().ByNumber(3).Enum()
   639  	)
   640  
   641  	for _, gotMT := range messageATypes[1:] {
   642  		if gotMT != wantMTA {
   643  			t.Error("MessageType(MessageA) mismatch")
   644  		}
   645  		if gotMDA := gotMT.Descriptor().Fields().ByNumber(1).Message(); gotMDA != wantMDA {
   646  			t.Error("MessageDescriptor(MessageA) mismatch")
   647  		}
   648  		if gotMDB := gotMT.Descriptor().Fields().ByNumber(2).Message(); gotMDB != wantMDB {
   649  			t.Error("MessageDescriptor(MessageB) mismatch")
   650  		}
   651  		if gotED := gotMT.Descriptor().Fields().ByNumber(3).Enum(); gotED != wantED {
   652  			t.Error("EnumDescriptor(Enum) mismatch")
   653  		}
   654  	}
   655  	for _, gotMT := range messageBTypes[1:] {
   656  		if gotMT != wantMTB {
   657  			t.Error("MessageType(MessageB) mismatch")
   658  		}
   659  		if gotMDA := gotMT.Descriptor().Fields().ByNumber(1).Message(); gotMDA != wantMDA {
   660  			t.Error("MessageDescriptor(MessageA) mismatch")
   661  		}
   662  		if gotMDB := gotMT.Descriptor().Fields().ByNumber(2).Message(); gotMDB != wantMDB {
   663  			t.Error("MessageDescriptor(MessageB) mismatch")
   664  		}
   665  		if gotED := gotMT.Descriptor().Fields().ByNumber(3).Enum(); gotED != wantED {
   666  			t.Error("EnumDescriptor(Enum) mismatch")
   667  		}
   668  	}
   669  	for _, gotED := range enumDescs[1:] {
   670  		if gotED != wantED {
   671  			t.Error("EnumType(Enum) mismatch")
   672  		}
   673  	}
   674  }
   675  
   676  type LegacyTestMessageName1 struct{}
   677  
   678  func (*LegacyTestMessageName1) Reset()         { panic("not implemented") }
   679  func (*LegacyTestMessageName1) String() string { panic("not implemented") }
   680  func (*LegacyTestMessageName1) ProtoMessage()  { panic("not implemented") }
   681  
   682  type LegacyTestMessageName2 struct{}
   683  
   684  func (*LegacyTestMessageName2) Reset()         { panic("not implemented") }
   685  func (*LegacyTestMessageName2) String() string { panic("not implemented") }
   686  func (*LegacyTestMessageName2) ProtoMessage()  { panic("not implemented") }
   687  func (*LegacyTestMessageName2) XXX_MessageName() string {
   688  	return "google.golang.org.LegacyTestMessageName2"
   689  }
   690  
   691  func TestLegacyMessageName(t *testing.T) {
   692  	tests := []struct {
   693  		in          protoiface.MessageV1
   694  		suggestName protoreflect.FullName
   695  		wantName    protoreflect.FullName
   696  	}{
   697  		{new(LegacyTestMessageName1), "google.golang.org.LegacyTestMessageName1", "google.golang.org.LegacyTestMessageName1"},
   698  		{new(LegacyTestMessageName2), "", "google.golang.org.LegacyTestMessageName2"},
   699  	}
   700  
   701  	for _, tt := range tests {
   702  		mt := pimpl.Export{}.LegacyMessageTypeOf(tt.in, tt.suggestName)
   703  		if got := mt.Descriptor().FullName(); got != tt.wantName {
   704  			t.Errorf("type: %T, name mismatch: got %v, want %v", tt.in, got, tt.wantName)
   705  		}
   706  	}
   707  }
   708  

View as plain text