desc_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  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 filedesc_test
  5. import (
  6. "fmt"
  7. "reflect"
  8. "regexp"
  9. "strconv"
  10. "strings"
  11. "testing"
  12. "github.com/google/go-cmp/cmp"
  13. detrand "google.golang.org/protobuf/internal/detrand"
  14. "google.golang.org/protobuf/internal/filedesc"
  15. "google.golang.org/protobuf/proto"
  16. pdesc "google.golang.org/protobuf/reflect/protodesc"
  17. pref "google.golang.org/protobuf/reflect/protoreflect"
  18. "google.golang.org/protobuf/types/descriptorpb"
  19. )
  20. func init() {
  21. // Disable detrand to enable direct comparisons on outputs.
  22. detrand.Disable()
  23. }
  24. // TODO: Test protodesc.NewFile with imported files.
  25. func TestFile(t *testing.T) {
  26. f1 := &descriptorpb.FileDescriptorProto{
  27. Syntax: proto.String("proto2"),
  28. Name: proto.String("path/to/file.proto"),
  29. Package: proto.String("test"),
  30. Options: &descriptorpb.FileOptions{Deprecated: proto.Bool(true)},
  31. MessageType: []*descriptorpb.DescriptorProto{{
  32. Name: proto.String("A"),
  33. Options: &descriptorpb.MessageOptions{
  34. Deprecated: proto.Bool(true),
  35. },
  36. }, {
  37. Name: proto.String("B"),
  38. Field: []*descriptorpb.FieldDescriptorProto{{
  39. Name: proto.String("field_one"),
  40. Number: proto.Int32(1),
  41. Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
  42. Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
  43. DefaultValue: proto.String("hello, \"world!\"\n"),
  44. OneofIndex: proto.Int32(0),
  45. }, {
  46. Name: proto.String("field_two"),
  47. JsonName: proto.String("Field2"),
  48. Number: proto.Int32(2),
  49. Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
  50. Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
  51. DefaultValue: proto.String("BAR"),
  52. TypeName: proto.String(".test.E1"),
  53. OneofIndex: proto.Int32(1),
  54. }, {
  55. Name: proto.String("field_three"),
  56. Number: proto.Int32(3),
  57. Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
  58. Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
  59. TypeName: proto.String(".test.C"),
  60. OneofIndex: proto.Int32(1),
  61. }, {
  62. Name: proto.String("field_four"),
  63. JsonName: proto.String("Field4"),
  64. Number: proto.Int32(4),
  65. Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
  66. Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
  67. TypeName: proto.String(".test.B.FieldFourEntry"),
  68. }, {
  69. Name: proto.String("field_five"),
  70. Number: proto.Int32(5),
  71. Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
  72. Type: descriptorpb.FieldDescriptorProto_Type(pref.Int32Kind).Enum(),
  73. Options: &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
  74. }, {
  75. Name: proto.String("field_six"),
  76. Number: proto.Int32(6),
  77. Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
  78. Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
  79. }},
  80. OneofDecl: []*descriptorpb.OneofDescriptorProto{
  81. {
  82. Name: proto.String("O1"),
  83. Options: &descriptorpb.OneofOptions{
  84. UninterpretedOption: []*descriptorpb.UninterpretedOption{
  85. {StringValue: []byte("option")},
  86. },
  87. },
  88. },
  89. {Name: proto.String("O2")},
  90. },
  91. ReservedName: []string{"fizz", "buzz"},
  92. ReservedRange: []*descriptorpb.DescriptorProto_ReservedRange{
  93. {Start: proto.Int32(100), End: proto.Int32(200)},
  94. {Start: proto.Int32(300), End: proto.Int32(301)},
  95. },
  96. ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{
  97. {Start: proto.Int32(1000), End: proto.Int32(2000)},
  98. {Start: proto.Int32(3000), End: proto.Int32(3001), Options: new(descriptorpb.ExtensionRangeOptions)},
  99. },
  100. NestedType: []*descriptorpb.DescriptorProto{{
  101. Name: proto.String("FieldFourEntry"),
  102. Field: []*descriptorpb.FieldDescriptorProto{{
  103. Name: proto.String("key"),
  104. Number: proto.Int32(1),
  105. Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
  106. Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
  107. }, {
  108. Name: proto.String("value"),
  109. Number: proto.Int32(2),
  110. Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
  111. Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
  112. TypeName: proto.String(".test.B"),
  113. }},
  114. Options: &descriptorpb.MessageOptions{
  115. MapEntry: proto.Bool(true),
  116. },
  117. }},
  118. }, {
  119. Name: proto.String("C"),
  120. NestedType: []*descriptorpb.DescriptorProto{{
  121. Name: proto.String("A"),
  122. Field: []*descriptorpb.FieldDescriptorProto{{
  123. Name: proto.String("F"),
  124. Number: proto.Int32(1),
  125. Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
  126. Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
  127. DefaultValue: proto.String(`dead\276\357`),
  128. }},
  129. }},
  130. EnumType: []*descriptorpb.EnumDescriptorProto{{
  131. Name: proto.String("E1"),
  132. Value: []*descriptorpb.EnumValueDescriptorProto{
  133. {Name: proto.String("FOO"), Number: proto.Int32(0)},
  134. {Name: proto.String("BAR"), Number: proto.Int32(1)},
  135. },
  136. }},
  137. Extension: []*descriptorpb.FieldDescriptorProto{{
  138. Name: proto.String("X"),
  139. Number: proto.Int32(1000),
  140. Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
  141. Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
  142. TypeName: proto.String(".test.C"),
  143. Extendee: proto.String(".test.B"),
  144. }},
  145. }},
  146. EnumType: []*descriptorpb.EnumDescriptorProto{{
  147. Name: proto.String("E1"),
  148. Options: &descriptorpb.EnumOptions{Deprecated: proto.Bool(true)},
  149. Value: []*descriptorpb.EnumValueDescriptorProto{
  150. {
  151. Name: proto.String("FOO"),
  152. Number: proto.Int32(0),
  153. Options: &descriptorpb.EnumValueOptions{Deprecated: proto.Bool(true)},
  154. },
  155. {Name: proto.String("BAR"), Number: proto.Int32(1)},
  156. },
  157. ReservedName: []string{"FIZZ", "BUZZ"},
  158. ReservedRange: []*descriptorpb.EnumDescriptorProto_EnumReservedRange{
  159. {Start: proto.Int32(10), End: proto.Int32(19)},
  160. {Start: proto.Int32(30), End: proto.Int32(30)},
  161. },
  162. }},
  163. Extension: []*descriptorpb.FieldDescriptorProto{{
  164. Name: proto.String("X"),
  165. Number: proto.Int32(1000),
  166. Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
  167. Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
  168. Options: &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
  169. TypeName: proto.String(".test.E1"),
  170. Extendee: proto.String(".test.B"),
  171. }},
  172. Service: []*descriptorpb.ServiceDescriptorProto{{
  173. Name: proto.String("S"),
  174. Options: &descriptorpb.ServiceOptions{Deprecated: proto.Bool(true)},
  175. Method: []*descriptorpb.MethodDescriptorProto{{
  176. Name: proto.String("M"),
  177. InputType: proto.String(".test.A"),
  178. OutputType: proto.String(".test.C.A"),
  179. ClientStreaming: proto.Bool(true),
  180. ServerStreaming: proto.Bool(true),
  181. Options: &descriptorpb.MethodOptions{Deprecated: proto.Bool(true)},
  182. }},
  183. }},
  184. }
  185. fd1, err := pdesc.NewFile(f1, nil)
  186. if err != nil {
  187. t.Fatalf("protodesc.NewFile() error: %v", err)
  188. }
  189. b, err := proto.Marshal(f1)
  190. if err != nil {
  191. t.Fatalf("proto.Marshal() error: %v", err)
  192. }
  193. fd2 := filedesc.Builder{RawDescriptor: b}.Build().File
  194. tests := []struct {
  195. name string
  196. desc pref.FileDescriptor
  197. }{
  198. {"protodesc.NewFile", fd1},
  199. {"filedesc.Builder.Build", fd2},
  200. }
  201. for _, tt := range tests {
  202. tt := tt
  203. t.Run(tt.name, func(t *testing.T) {
  204. // Run sub-tests in parallel to induce potential races.
  205. for i := 0; i < 2; i++ {
  206. t.Run("Accessors", func(t *testing.T) { t.Parallel(); testFileAccessors(t, tt.desc) })
  207. t.Run("Format", func(t *testing.T) { t.Parallel(); testFileFormat(t, tt.desc) })
  208. }
  209. })
  210. }
  211. }
  212. func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
  213. // Represent the descriptor as a map where each key is an accessor method
  214. // and the value is either the wanted tail value or another accessor map.
  215. type M = map[string]interface{}
  216. want := M{
  217. "Parent": nil,
  218. "Index": 0,
  219. "Syntax": pref.Proto2,
  220. "Name": pref.Name("test"),
  221. "FullName": pref.FullName("test"),
  222. "Path": "path/to/file.proto",
  223. "Package": pref.FullName("test"),
  224. "IsPlaceholder": false,
  225. "Options": &descriptorpb.FileOptions{Deprecated: proto.Bool(true)},
  226. "Messages": M{
  227. "Len": 3,
  228. "Get:0": M{
  229. "Parent": M{"FullName": pref.FullName("test")},
  230. "Index": 0,
  231. "Syntax": pref.Proto2,
  232. "Name": pref.Name("A"),
  233. "FullName": pref.FullName("test.A"),
  234. "IsPlaceholder": false,
  235. "IsMapEntry": false,
  236. "Options": &descriptorpb.MessageOptions{
  237. Deprecated: proto.Bool(true),
  238. },
  239. "Oneofs": M{"Len": 0},
  240. "RequiredNumbers": M{"Len": 0},
  241. "ExtensionRanges": M{"Len": 0},
  242. "Messages": M{"Len": 0},
  243. "Enums": M{"Len": 0},
  244. "Extensions": M{"Len": 0},
  245. },
  246. "ByName:B": M{
  247. "Name": pref.Name("B"),
  248. "Index": 1,
  249. "Fields": M{
  250. "Len": 6,
  251. "ByJSONName:field_one": nil,
  252. "ByJSONName:fieldOne": M{
  253. "Name": pref.Name("field_one"),
  254. "Index": 0,
  255. "JSONName": "fieldOne",
  256. "Default": "hello, \"world!\"\n",
  257. "ContainingOneof": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
  258. "ContainingMessage": M{"FullName": pref.FullName("test.B")},
  259. },
  260. "ByJSONName:fieldTwo": nil,
  261. "ByJSONName:Field2": M{
  262. "Name": pref.Name("field_two"),
  263. "Index": 1,
  264. "HasJSONName": true,
  265. "JSONName": "Field2",
  266. "Default": pref.EnumNumber(1),
  267. "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
  268. },
  269. "ByName:fieldThree": nil,
  270. "ByName:field_three": M{
  271. "IsExtension": false,
  272. "IsMap": false,
  273. "MapKey": nil,
  274. "MapValue": nil,
  275. "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
  276. "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
  277. "ContainingMessage": M{"FullName": pref.FullName("test.B")},
  278. },
  279. "ByNumber:12": nil,
  280. "ByNumber:4": M{
  281. "Cardinality": pref.Repeated,
  282. "IsExtension": false,
  283. "IsList": false,
  284. "IsMap": true,
  285. "MapKey": M{"Kind": pref.StringKind},
  286. "MapValue": M{"Kind": pref.MessageKind, "Message": M{"FullName": pref.FullName("test.B")}},
  287. "Default": nil,
  288. "Message": M{"FullName": pref.FullName("test.B.FieldFourEntry"), "IsPlaceholder": false},
  289. },
  290. "ByNumber:5": M{
  291. "Cardinality": pref.Repeated,
  292. "Kind": pref.Int32Kind,
  293. "IsPacked": true,
  294. "IsList": true,
  295. "IsMap": false,
  296. "Default": nil,
  297. },
  298. "ByNumber:6": M{
  299. "Cardinality": pref.Required,
  300. "Default": []byte(nil),
  301. "ContainingOneof": nil,
  302. },
  303. },
  304. "Oneofs": M{
  305. "Len": 2,
  306. "ByName:O0": nil,
  307. "ByName:O1": M{
  308. "FullName": pref.FullName("test.B.O1"),
  309. "Index": 0,
  310. "Options": &descriptorpb.OneofOptions{
  311. UninterpretedOption: []*descriptorpb.UninterpretedOption{
  312. {StringValue: []byte("option")},
  313. },
  314. },
  315. "Fields": M{
  316. "Len": 1,
  317. "Get:0": M{"FullName": pref.FullName("test.B.field_one")},
  318. },
  319. },
  320. "Get:1": M{
  321. "FullName": pref.FullName("test.B.O2"),
  322. "Index": 1,
  323. "Fields": M{
  324. "Len": 2,
  325. "ByName:field_two": M{"Name": pref.Name("field_two")},
  326. "Get:1": M{"Name": pref.Name("field_three")},
  327. },
  328. },
  329. },
  330. "ReservedNames": M{
  331. "Len": 2,
  332. "Get:0": pref.Name("fizz"),
  333. "Has:buzz": true,
  334. "Has:noexist": false,
  335. },
  336. "ReservedRanges": M{
  337. "Len": 2,
  338. "Get:0": [2]pref.FieldNumber{100, 200},
  339. "Has:99": false,
  340. "Has:100": true,
  341. "Has:150": true,
  342. "Has:199": true,
  343. "Has:200": false,
  344. "Has:300": true,
  345. "Has:301": false,
  346. },
  347. "RequiredNumbers": M{
  348. "Len": 1,
  349. "Get:0": pref.FieldNumber(6),
  350. "Has:1": false,
  351. "Has:6": true,
  352. },
  353. "ExtensionRanges": M{
  354. "Len": 2,
  355. "Get:0": [2]pref.FieldNumber{1000, 2000},
  356. "Has:999": false,
  357. "Has:1000": true,
  358. "Has:1500": true,
  359. "Has:1999": true,
  360. "Has:2000": false,
  361. "Has:3000": true,
  362. "Has:3001": false,
  363. },
  364. "ExtensionRangeOptions:0": (*descriptorpb.ExtensionRangeOptions)(nil),
  365. "ExtensionRangeOptions:1": new(descriptorpb.ExtensionRangeOptions),
  366. "Messages": M{
  367. "Get:0": M{
  368. "Fields": M{
  369. "Len": 2,
  370. "ByNumber:1": M{
  371. "Parent": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
  372. "Index": 0,
  373. "Name": pref.Name("key"),
  374. "FullName": pref.FullName("test.B.FieldFourEntry.key"),
  375. "Number": pref.FieldNumber(1),
  376. "Cardinality": pref.Optional,
  377. "Kind": pref.StringKind,
  378. "Options": (*descriptorpb.FieldOptions)(nil),
  379. "HasJSONName": false,
  380. "JSONName": "key",
  381. "IsPacked": false,
  382. "IsList": false,
  383. "IsMap": false,
  384. "IsExtension": false,
  385. "IsWeak": false,
  386. "Default": "",
  387. "ContainingOneof": nil,
  388. "ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
  389. "Message": nil,
  390. "Enum": nil,
  391. },
  392. "ByNumber:2": M{
  393. "Parent": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
  394. "Index": 1,
  395. "Name": pref.Name("value"),
  396. "FullName": pref.FullName("test.B.FieldFourEntry.value"),
  397. "Number": pref.FieldNumber(2),
  398. "Cardinality": pref.Optional,
  399. "Kind": pref.MessageKind,
  400. "JSONName": "value",
  401. "IsPacked": false,
  402. "IsList": false,
  403. "IsMap": false,
  404. "IsExtension": false,
  405. "IsWeak": false,
  406. "Default": nil,
  407. "ContainingOneof": nil,
  408. "ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
  409. "Message": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
  410. "Enum": nil,
  411. },
  412. "ByNumber:3": nil,
  413. },
  414. },
  415. },
  416. },
  417. "Get:2": M{
  418. "Name": pref.Name("C"),
  419. "Index": 2,
  420. "Messages": M{
  421. "Len": 1,
  422. "Get:0": M{"FullName": pref.FullName("test.C.A")},
  423. },
  424. "Enums": M{
  425. "Len": 1,
  426. "Get:0": M{"FullName": pref.FullName("test.C.E1")},
  427. },
  428. "Extensions": M{
  429. "Len": 1,
  430. "Get:0": M{"FullName": pref.FullName("test.C.X")},
  431. },
  432. },
  433. },
  434. "Enums": M{
  435. "Len": 1,
  436. "Get:0": M{
  437. "Name": pref.Name("E1"),
  438. "Options": &descriptorpb.EnumOptions{Deprecated: proto.Bool(true)},
  439. "Values": M{
  440. "Len": 2,
  441. "ByName:Foo": nil,
  442. "ByName:FOO": M{
  443. "FullName": pref.FullName("test.FOO"),
  444. "Options": &descriptorpb.EnumValueOptions{Deprecated: proto.Bool(true)},
  445. },
  446. "ByNumber:2": nil,
  447. "ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
  448. },
  449. "ReservedNames": M{
  450. "Len": 2,
  451. "Get:0": pref.Name("FIZZ"),
  452. "Has:BUZZ": true,
  453. "Has:NOEXIST": false,
  454. },
  455. "ReservedRanges": M{
  456. "Len": 2,
  457. "Get:0": [2]pref.EnumNumber{10, 19},
  458. "Has:9": false,
  459. "Has:10": true,
  460. "Has:15": true,
  461. "Has:19": true,
  462. "Has:20": false,
  463. "Has:30": true,
  464. "Has:31": false,
  465. },
  466. },
  467. },
  468. "Extensions": M{
  469. "Len": 1,
  470. "ByName:X": M{
  471. "Name": pref.Name("X"),
  472. "Number": pref.FieldNumber(1000),
  473. "Cardinality": pref.Repeated,
  474. "Kind": pref.EnumKind,
  475. "IsExtension": true,
  476. "IsPacked": true,
  477. "IsList": true,
  478. "IsMap": false,
  479. "MapKey": nil,
  480. "MapValue": nil,
  481. "ContainingOneof": nil,
  482. "ContainingMessage": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
  483. "Enum": M{"FullName": pref.FullName("test.E1"), "IsPlaceholder": false},
  484. "Options": &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
  485. },
  486. },
  487. "Services": M{
  488. "Len": 1,
  489. "ByName:s": nil,
  490. "ByName:S": M{
  491. "Parent": M{"FullName": pref.FullName("test")},
  492. "Name": pref.Name("S"),
  493. "FullName": pref.FullName("test.S"),
  494. "Options": &descriptorpb.ServiceOptions{Deprecated: proto.Bool(true)},
  495. "Methods": M{
  496. "Len": 1,
  497. "Get:0": M{
  498. "Parent": M{"FullName": pref.FullName("test.S")},
  499. "Name": pref.Name("M"),
  500. "FullName": pref.FullName("test.S.M"),
  501. "Input": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
  502. "Output": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
  503. "IsStreamingClient": true,
  504. "IsStreamingServer": true,
  505. "Options": &descriptorpb.MethodOptions{Deprecated: proto.Bool(true)},
  506. },
  507. },
  508. },
  509. },
  510. }
  511. checkAccessors(t, "", reflect.ValueOf(fd), want)
  512. }
  513. func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
  514. p0 := p
  515. defer func() {
  516. if ex := recover(); ex != nil {
  517. t.Errorf("panic at %v: %v", p, ex)
  518. }
  519. }()
  520. if rv.Interface() == nil {
  521. t.Errorf("%v is nil, want non-nil", p)
  522. return
  523. }
  524. for s, v := range want {
  525. // Call the accessor method.
  526. p = p0 + "." + s
  527. var rets []reflect.Value
  528. if i := strings.IndexByte(s, ':'); i >= 0 {
  529. // Accessor method takes in a single argument, which is encoded
  530. // after the accessor name, separated by a ':' delimiter.
  531. fnc := rv.MethodByName(s[:i])
  532. arg := reflect.New(fnc.Type().In(0)).Elem()
  533. s = s[i+len(":"):]
  534. switch arg.Kind() {
  535. case reflect.String:
  536. arg.SetString(s)
  537. case reflect.Int32, reflect.Int:
  538. n, _ := strconv.ParseInt(s, 0, 64)
  539. arg.SetInt(n)
  540. }
  541. rets = fnc.Call([]reflect.Value{arg})
  542. } else {
  543. rets = rv.MethodByName(s).Call(nil)
  544. }
  545. // Check that (val, ok) pattern is internally consistent.
  546. if len(rets) == 2 {
  547. if rets[0].IsNil() && rets[1].Bool() {
  548. t.Errorf("%v = (nil, true), want (nil, false)", p)
  549. }
  550. if !rets[0].IsNil() && !rets[1].Bool() {
  551. t.Errorf("%v = (non-nil, false), want (non-nil, true)", p)
  552. }
  553. }
  554. // Check that the accessor output matches.
  555. if want, ok := v.(map[string]interface{}); ok {
  556. checkAccessors(t, p, rets[0], want)
  557. continue
  558. }
  559. got := rets[0].Interface()
  560. if pv, ok := got.(pref.Value); ok {
  561. got = pv.Interface()
  562. }
  563. // Compare with proto.Equal if possible.
  564. gotMsg, gotMsgOK := got.(proto.Message)
  565. wantMsg, wantMsgOK := v.(proto.Message)
  566. if gotMsgOK && wantMsgOK {
  567. gotNil := reflect.ValueOf(gotMsg).IsNil()
  568. wantNil := reflect.ValueOf(wantMsg).IsNil()
  569. switch {
  570. case !gotNil && wantNil:
  571. t.Errorf("%v = non-nil, want nil", p)
  572. case gotNil && !wantNil:
  573. t.Errorf("%v = nil, want non-nil", p)
  574. case !proto.Equal(gotMsg, wantMsg):
  575. t.Errorf("%v = %v, want %v", p, gotMsg, wantMsg)
  576. }
  577. continue
  578. }
  579. if want := v; !reflect.DeepEqual(got, want) {
  580. t.Errorf("%v = %T(%v), want %T(%v)", p, got, got, want, want)
  581. }
  582. }
  583. }
  584. func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
  585. const want = `FileDescriptor{
  586. Syntax: proto2
  587. Path: "path/to/file.proto"
  588. Package: test
  589. Messages: [{
  590. Name: A
  591. }, {
  592. Name: B
  593. Fields: [{
  594. Name: field_one
  595. Number: 1
  596. Cardinality: optional
  597. Kind: string
  598. JSONName: "fieldOne"
  599. HasDefault: true
  600. Default: "hello, \"world!\"\n"
  601. Oneof: O1
  602. }, {
  603. Name: field_two
  604. Number: 2
  605. Cardinality: optional
  606. Kind: enum
  607. HasJSONName: true
  608. JSONName: "Field2"
  609. HasDefault: true
  610. Default: 1
  611. Oneof: O2
  612. Enum: test.E1
  613. }, {
  614. Name: field_three
  615. Number: 3
  616. Cardinality: optional
  617. Kind: message
  618. JSONName: "fieldThree"
  619. Oneof: O2
  620. Message: test.C
  621. }, {
  622. Name: field_four
  623. Number: 4
  624. Cardinality: repeated
  625. Kind: message
  626. HasJSONName: true
  627. JSONName: "Field4"
  628. IsMap: true
  629. MapKey: string
  630. MapValue: test.B
  631. }, {
  632. Name: field_five
  633. Number: 5
  634. Cardinality: repeated
  635. Kind: int32
  636. JSONName: "fieldFive"
  637. IsPacked: true
  638. IsList: true
  639. }, {
  640. Name: field_six
  641. Number: 6
  642. Cardinality: required
  643. Kind: bytes
  644. JSONName: "fieldSix"
  645. }]
  646. Oneofs: [{
  647. Name: O1
  648. Fields: [field_one]
  649. }, {
  650. Name: O2
  651. Fields: [field_two, field_three]
  652. }]
  653. ReservedNames: [fizz, buzz]
  654. ReservedRanges: [100:200, 300]
  655. RequiredNumbers: [6]
  656. ExtensionRanges: [1000:2000, 3000]
  657. Messages: [{
  658. Name: FieldFourEntry
  659. IsMapEntry: true
  660. Fields: [{
  661. Name: key
  662. Number: 1
  663. Cardinality: optional
  664. Kind: string
  665. JSONName: "key"
  666. }, {
  667. Name: value
  668. Number: 2
  669. Cardinality: optional
  670. Kind: message
  671. JSONName: "value"
  672. Message: test.B
  673. }]
  674. }]
  675. }, {
  676. Name: C
  677. Messages: [{
  678. Name: A
  679. Fields: [{
  680. Name: F
  681. Number: 1
  682. Cardinality: required
  683. Kind: bytes
  684. JSONName: "F"
  685. HasDefault: true
  686. Default: "dead\xbe\xef"
  687. }]
  688. RequiredNumbers: [1]
  689. }]
  690. Enums: [{
  691. Name: E1
  692. Values: [
  693. {Name: FOO}
  694. {Name: BAR, Number: 1}
  695. ]
  696. }]
  697. Extensions: [{
  698. Name: X
  699. Number: 1000
  700. Cardinality: repeated
  701. Kind: message
  702. JSONName: "X"
  703. IsExtension: true
  704. IsList: true
  705. Extendee: test.B
  706. Message: test.C
  707. }]
  708. }]
  709. Enums: [{
  710. Name: E1
  711. Values: [
  712. {Name: FOO}
  713. {Name: BAR, Number: 1}
  714. ]
  715. ReservedNames: [FIZZ, BUZZ]
  716. ReservedRanges: [10:20, 30]
  717. }]
  718. Extensions: [{
  719. Name: X
  720. Number: 1000
  721. Cardinality: repeated
  722. Kind: enum
  723. JSONName: "X"
  724. IsPacked: true
  725. IsExtension: true
  726. IsList: true
  727. Extendee: test.B
  728. Enum: test.E1
  729. }]
  730. Services: [{
  731. Name: S
  732. Methods: [{
  733. Name: M
  734. Input: test.A
  735. Output: test.C.A
  736. IsStreamingClient: true
  737. IsStreamingServer: true
  738. }]
  739. }]
  740. }`
  741. tests := []struct{ fmt, want string }{{"%v", compactMultiFormat(want)}, {"%+v", want}}
  742. for _, tt := range tests {
  743. got := fmt.Sprintf(tt.fmt, fd)
  744. if diff := cmp.Diff(got, tt.want); diff != "" {
  745. t.Errorf("fmt.Sprintf(%q, fd) mismatch (-got +want):\n%s", tt.fmt, diff)
  746. }
  747. }
  748. }
  749. // compactMultiFormat returns the single line form of a multi line output.
  750. func compactMultiFormat(s string) string {
  751. var b []byte
  752. for _, s := range strings.Split(s, "\n") {
  753. s = strings.TrimSpace(s)
  754. s = regexp.MustCompile(": +").ReplaceAllString(s, ": ")
  755. prevWord := len(b) > 0 && b[len(b)-1] != '[' && b[len(b)-1] != '{'
  756. nextWord := len(s) > 0 && s[0] != ']' && s[0] != '}'
  757. if prevWord && nextWord {
  758. b = append(b, ", "...)
  759. }
  760. b = append(b, s...)
  761. }
  762. return string(b)
  763. }