legacy_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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/internal/scalar"
  16. "google.golang.org/protobuf/proto"
  17. pdesc "google.golang.org/protobuf/reflect/protodesc"
  18. pref "google.golang.org/protobuf/reflect/protoreflect"
  19. preg "google.golang.org/protobuf/reflect/protoregistry"
  20. piface "google.golang.org/protobuf/runtime/protoiface"
  21. proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
  22. "google.golang.org/protobuf/types/descriptorpb"
  23. )
  24. type LegacyTestMessage struct {
  25. XXX_unrecognized []byte
  26. XXX_InternalExtensions map[int32]pimpl.ExtensionField
  27. }
  28. func (*LegacyTestMessage) Reset() {}
  29. func (*LegacyTestMessage) String() string { return "" }
  30. func (*LegacyTestMessage) ProtoMessage() {}
  31. func (*LegacyTestMessage) ExtensionRangeArray() []piface.ExtensionRangeV1 {
  32. return []piface.ExtensionRangeV1{{Start: 10, End: 20}, {Start: 40, End: 80}, {Start: 10000, End: 20000}}
  33. }
  34. func (*LegacyTestMessage) Descriptor() ([]byte, []int) { return legacyFD, []int{0} }
  35. var legacyFD = func() []byte {
  36. b, _ := proto.Marshal(pdesc.ToFileDescriptorProto(mustMakeFileDesc(`
  37. name: "legacy.proto"
  38. syntax: "proto2"
  39. message_type: [{
  40. name: "LegacyTestMessage"
  41. extension_range: [{start:10 end:20}, {start:40 end:80}, {start:10000 end:20000}]
  42. }]
  43. `, nil)))
  44. return pimpl.Export{}.CompressGZIP(b)
  45. }()
  46. func init() {
  47. mt := pimpl.Export{}.MessageTypeOf((*LegacyTestMessage)(nil))
  48. preg.GlobalFiles.Register(mt.ParentFile())
  49. preg.GlobalTypes.Register(mt)
  50. }
  51. func mustMakeExtensionType(fileDesc, extDesc string, t interface{}, r pdesc.Resolver) pref.ExtensionType {
  52. s := fmt.Sprintf(`name:"test.proto" syntax:"proto2" %s extension:[{%s}]`, fileDesc, extDesc)
  53. xd := mustMakeFileDesc(s, r).Extensions().Get(0)
  54. return pimpl.LegacyExtensionTypeOf(xd, reflect.TypeOf(t))
  55. }
  56. func mustMakeFileDesc(s string, r pdesc.Resolver) pref.FileDescriptor {
  57. pb := new(descriptorpb.FileDescriptorProto)
  58. if err := prototext.Unmarshal([]byte(s), pb); err != nil {
  59. panic(err)
  60. }
  61. fd, err := pdesc.NewFile(pb, r)
  62. if err != nil {
  63. panic(err)
  64. }
  65. return fd
  66. }
  67. var (
  68. testParentDesc = pimpl.Export{}.MessageDescriptorOf((*LegacyTestMessage)(nil))
  69. testEnumV1Desc = pimpl.Export{}.EnumDescriptorOf(proto2_20180125.Message_ChildEnum(0))
  70. testMessageV1Desc = pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message_ChildMessage)(nil))
  71. testEnumV2Desc = enumProto2Type.Descriptor()
  72. testMessageV2Desc = enumMessagesType.PBType.Descriptor()
  73. depReg = preg.NewFiles(
  74. testParentDesc.ParentFile(),
  75. testEnumV1Desc.ParentFile(),
  76. testMessageV1Desc.ParentFile(),
  77. testEnumV2Desc.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. nil, 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. nil, 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. nil, 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. nil, 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. nil, 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. 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. 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. (*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. 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. (*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. 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. 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. 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. 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. 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. 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. proto2_20180125.Message_ChildEnum(0), 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. (*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. EnumProto2(0), 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. (*EnumMessages)(nil), depReg,
  180. ),
  181. }
  182. extensionDescs = []*piface.ExtensionDescV1{{
  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. if !(xt.IsList() || xt.IsMap() || xt.Message() != nil) {
  346. got = xt.InterfaceOf(m.Get(xt))
  347. }
  348. want := defaultValues[i]
  349. if diff := cmp.Diff(want, got, opts); diff != "" {
  350. t.Errorf("Message.Get(%d) mismatch (-want +got):\n%v", xt.Number(), diff)
  351. }
  352. }
  353. // All fields should be unpopulated.
  354. for _, xt := range extensionTypes {
  355. if m.Has(xt) {
  356. t.Errorf("Message.Has(%d) = true, want false", xt.Number())
  357. }
  358. }
  359. // Set some values and append to values to the lists.
  360. m1a := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m1a")}
  361. m1b := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m2b")}
  362. m2a := &EnumMessages{EnumP2: EnumProto2(0x1b).Enum()}
  363. m2b := &EnumMessages{EnumP2: EnumProto2(0x2b).Enum()}
  364. setValues := map[int]interface{}{
  365. 0: bool(false),
  366. 1: int32(-54321),
  367. 2: uint32(6400),
  368. 3: float32(2.71828),
  369. 4: string("goodbye, \"world!\"\n"),
  370. 5: []byte("live\xde\xad\xbe\xefchicken"),
  371. 6: proto2_20180125.Message_CHARLIE,
  372. 7: m1a,
  373. 8: EnumProto2(0xbeef),
  374. 9: m2a,
  375. 10: &[]bool{true},
  376. 11: &[]int32{-1000},
  377. 12: &[]uint32{1280},
  378. 13: &[]float32{1.6180},
  379. 14: &[]string{"zero"},
  380. 15: &[][]byte{[]byte("zero")},
  381. 16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
  382. 17: &[]*proto2_20180125.Message_ChildMessage{m1b},
  383. 18: &[]EnumProto2{0xdead},
  384. 19: &[]*EnumMessages{m2b},
  385. }
  386. for i, xt := range extensionTypes {
  387. m.Set(xt, xt.ValueOf(setValues[i]))
  388. }
  389. for i, xt := range extensionTypes[len(extensionTypes)/2:] {
  390. v := extensionTypes[i].ValueOf(setValues[i])
  391. m.Get(xt).List().Append(v)
  392. }
  393. // Get the values and check for equality.
  394. getValues := map[int]interface{}{
  395. 0: bool(false),
  396. 1: int32(-54321),
  397. 2: uint32(6400),
  398. 3: float32(2.71828),
  399. 4: string("goodbye, \"world!\"\n"),
  400. 5: []byte("live\xde\xad\xbe\xefchicken"),
  401. 6: proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE),
  402. 7: m1a,
  403. 8: EnumProto2(0xbeef),
  404. 9: m2a,
  405. 10: &[]bool{true, false},
  406. 11: &[]int32{-1000, -54321},
  407. 12: &[]uint32{1280, 6400},
  408. 13: &[]float32{1.6180, 2.71828},
  409. 14: &[]string{"zero", "goodbye, \"world!\"\n"},
  410. 15: &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
  411. 16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
  412. 17: &[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
  413. 18: &[]EnumProto2{0xdead, 0xbeef},
  414. 19: &[]*EnumMessages{m2b, m2a},
  415. }
  416. for i, xt := range extensionTypes {
  417. got := xt.InterfaceOf(m.Get(xt))
  418. want := getValues[i]
  419. if diff := cmp.Diff(want, got, opts); diff != "" {
  420. t.Errorf("Message.Get(%d) mismatch (-want +got):\n%v", xt.Number(), diff)
  421. }
  422. }
  423. // Clear all singular fields and truncate all repeated fields.
  424. for _, xt := range extensionTypes[:len(extensionTypes)/2] {
  425. m.Clear(xt)
  426. }
  427. for _, xt := range extensionTypes[len(extensionTypes)/2:] {
  428. m.Get(xt).List().Truncate(0)
  429. }
  430. // Clear all repeated fields.
  431. for _, xt := range extensionTypes[len(extensionTypes)/2:] {
  432. m.Clear(xt)
  433. }
  434. }
  435. func TestExtensionConvert(t *testing.T) {
  436. for i := range extensionTypes {
  437. i := i
  438. t.Run("", func(t *testing.T) {
  439. t.Parallel()
  440. wantType := extensionTypes[i]
  441. wantDesc := extensionDescs[i]
  442. gotType := pimpl.Export{}.ExtensionTypeFromDesc(wantDesc)
  443. gotDesc := pimpl.Export{}.ExtensionDescFromType(wantType)
  444. // TODO: We need a test package to compare descriptors.
  445. type list interface {
  446. Len() int
  447. pragma.DoNotImplement
  448. }
  449. opts := cmp.Options{
  450. cmp.Comparer(func(x, y reflect.Type) bool {
  451. return x == y
  452. }),
  453. cmp.Transformer("", func(x list) []interface{} {
  454. out := make([]interface{}, x.Len())
  455. v := reflect.ValueOf(x)
  456. for i := 0; i < x.Len(); i++ {
  457. m := v.MethodByName("Get")
  458. out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
  459. }
  460. return out
  461. }),
  462. cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
  463. out := make(map[string]interface{})
  464. v := reflect.ValueOf(x)
  465. for i := 0; i < v.NumMethod(); i++ {
  466. name := v.Type().Method(i).Name
  467. if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
  468. switch name {
  469. case "ParentFile", "Parent":
  470. // Ignore parents to avoid recursive cycle.
  471. case "New":
  472. // Ignore New since it a constructor.
  473. case "Options":
  474. // Ignore descriptor options since protos are not cmperable.
  475. case "ContainingOneof", "ContainingMessage", "Enum", "Message":
  476. // Avoid descending into a dependency to avoid a cycle.
  477. // Just record the full name if available.
  478. //
  479. // TODO: Cycle support in cmp would be useful here.
  480. v := m.Call(nil)[0]
  481. if !v.IsNil() {
  482. out[name] = v.Interface().(pref.Descriptor).FullName()
  483. }
  484. default:
  485. out[name] = m.Call(nil)[0].Interface()
  486. }
  487. }
  488. }
  489. return out
  490. }),
  491. cmp.Transformer("", func(v pref.Value) interface{} {
  492. return v.Interface()
  493. }),
  494. }
  495. if diff := cmp.Diff(&wantType, &gotType, opts); diff != "" {
  496. t.Errorf("ExtensionType mismatch (-want, +got):\n%v", diff)
  497. }
  498. opts = cmp.Options{
  499. cmpopts.IgnoreFields(piface.ExtensionDescV1{}, "Type"),
  500. }
  501. if diff := cmp.Diff(wantDesc, gotDesc, opts); diff != "" {
  502. t.Errorf("ExtensionDesc mismatch (-want, +got):\n%v", diff)
  503. }
  504. })
  505. }
  506. }
  507. type (
  508. MessageA struct {
  509. A1 *MessageA `protobuf:"bytes,1,req,name=a1"`
  510. A2 *MessageB `protobuf:"bytes,2,req,name=a2"`
  511. A3 Enum `protobuf:"varint,3,opt,name=a3,enum=legacy.Enum"`
  512. }
  513. MessageB struct {
  514. B1 *MessageA `protobuf:"bytes,1,req,name=b1"`
  515. B2 *MessageB `protobuf:"bytes,2,req,name=b2"`
  516. B3 Enum `protobuf:"varint,3,opt,name=b3,enum=legacy.Enum"`
  517. }
  518. Enum int32
  519. )
  520. func (*MessageA) Descriptor() ([]byte, []int) { return concurrentFD, []int{0} }
  521. func (*MessageB) Descriptor() ([]byte, []int) { return concurrentFD, []int{1} }
  522. func (Enum) EnumDescriptor() ([]byte, []int) { return concurrentFD, []int{0} }
  523. var concurrentFD = func() []byte {
  524. b, _ := proto.Marshal(pdesc.ToFileDescriptorProto(mustMakeFileDesc(`
  525. name: "concurrent.proto"
  526. syntax: "proto2"
  527. package: "legacy"
  528. message_type: [{
  529. name: "MessageA"
  530. field: [
  531. {name:"a1" number:1 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageA"},
  532. {name:"a2" number:2 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageB"},
  533. {name:"a3" number:3 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".legacy.Enum"}
  534. ]
  535. }, {
  536. name: "MessageB"
  537. field: [
  538. {name:"a1" number:1 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageA"},
  539. {name:"a2" number:2 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageB"},
  540. {name:"a3" number:3 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".legacy.Enum"}
  541. ]
  542. }]
  543. enum_type: [{
  544. name: "Enum"
  545. value: [{name:"FOO" number:500}]
  546. }]
  547. `, nil)))
  548. return pimpl.Export{}.CompressGZIP(b)
  549. }()
  550. // TestConcurrentInit tests that concurrent wrapping of multiple legacy types
  551. // results in the exact same descriptor being created.
  552. func TestConcurrentInit(t *testing.T) {
  553. const numParallel = 5
  554. var messageATypes [numParallel]pref.MessageType
  555. var messageBTypes [numParallel]pref.MessageType
  556. var enumDescs [numParallel]pref.EnumDescriptor
  557. // Concurrently load message and enum types.
  558. var wg sync.WaitGroup
  559. for i := 0; i < numParallel; i++ {
  560. i := i
  561. wg.Add(3)
  562. go func() {
  563. defer wg.Done()
  564. messageATypes[i] = pimpl.Export{}.MessageTypeOf((*MessageA)(nil))
  565. }()
  566. go func() {
  567. defer wg.Done()
  568. messageBTypes[i] = pimpl.Export{}.MessageTypeOf((*MessageB)(nil))
  569. }()
  570. go func() {
  571. defer wg.Done()
  572. enumDescs[i] = pimpl.Export{}.EnumDescriptorOf(Enum(0))
  573. }()
  574. }
  575. wg.Wait()
  576. var (
  577. wantMTA = messageATypes[0]
  578. wantMDA = messageATypes[0].Descriptor().Fields().ByNumber(1).Message()
  579. wantMTB = messageBTypes[0]
  580. wantMDB = messageBTypes[0].Descriptor().Fields().ByNumber(2).Message()
  581. wantED = messageATypes[0].Descriptor().Fields().ByNumber(3).Enum()
  582. )
  583. for _, gotMT := range messageATypes[1:] {
  584. if gotMT != wantMTA {
  585. t.Error("MessageType(MessageA) mismatch")
  586. }
  587. if gotMDA := gotMT.Descriptor().Fields().ByNumber(1).Message(); gotMDA != wantMDA {
  588. t.Error("MessageDescriptor(MessageA) mismatch")
  589. }
  590. if gotMDB := gotMT.Descriptor().Fields().ByNumber(2).Message(); gotMDB != wantMDB {
  591. t.Error("MessageDescriptor(MessageB) mismatch")
  592. }
  593. if gotED := gotMT.Descriptor().Fields().ByNumber(3).Enum(); gotED != wantED {
  594. t.Error("EnumDescriptor(Enum) mismatch")
  595. }
  596. }
  597. for _, gotMT := range messageBTypes[1:] {
  598. if gotMT != wantMTB {
  599. t.Error("MessageType(MessageB) mismatch")
  600. }
  601. if gotMDA := gotMT.Descriptor().Fields().ByNumber(1).Message(); gotMDA != wantMDA {
  602. t.Error("MessageDescriptor(MessageA) mismatch")
  603. }
  604. if gotMDB := gotMT.Descriptor().Fields().ByNumber(2).Message(); gotMDB != wantMDB {
  605. t.Error("MessageDescriptor(MessageB) mismatch")
  606. }
  607. if gotED := gotMT.Descriptor().Fields().ByNumber(3).Enum(); gotED != wantED {
  608. t.Error("EnumDescriptor(Enum) mismatch")
  609. }
  610. }
  611. for _, gotED := range enumDescs[1:] {
  612. if gotED != wantED {
  613. t.Error("EnumType(Enum) mismatch")
  614. }
  615. }
  616. }