legacy_test.go 26 KB

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