1 package descriptor
2
3 import (
4 "testing"
5
6 "github.com/golang/protobuf/proto"
7 descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
8 plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
9 )
10
11 func loadFile(t *testing.T, reg *Registry, src string) *descriptor.FileDescriptorProto {
12 var file descriptor.FileDescriptorProto
13 if err := proto.UnmarshalText(src, &file); err != nil {
14 t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err)
15 }
16 reg.loadFile(&file)
17 return &file
18 }
19
20 func load(t *testing.T, reg *Registry, src string) error {
21 var req plugin.CodeGeneratorRequest
22 if err := proto.UnmarshalText(src, &req); err != nil {
23 t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err)
24 }
25 return reg.Load(&req)
26 }
27
28 func TestLoadFile(t *testing.T) {
29 reg := NewRegistry()
30 fd := loadFile(t, reg, `
31 name: 'example.proto'
32 package: 'example'
33 message_type <
34 name: 'ExampleMessage'
35 field <
36 name: 'str'
37 label: LABEL_OPTIONAL
38 type: TYPE_STRING
39 number: 1
40 >
41 >
42 `)
43
44 file := reg.files["example.proto"]
45 if file == nil {
46 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
47 return
48 }
49 wantPkg := GoPackage{Path: ".", Name: "example"}
50 if got, want := file.GoPkg, wantPkg; got != want {
51 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
52 }
53
54 msg, err := reg.LookupMsg("", ".example.ExampleMessage")
55 if err != nil {
56 t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", "", ".example.ExampleMessage", err)
57 return
58 }
59 if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
60 t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", "", ".example.ExampleMessage", got, want)
61 }
62 if got, want := msg.File, file; got != want {
63 t.Errorf("msg.File = %v; want %v", got, want)
64 }
65 if got := msg.Outers; got != nil {
66 t.Errorf("msg.Outers = %v; want %v", got, nil)
67 }
68 if got, want := len(msg.Fields), 1; got != want {
69 t.Errorf("len(msg.Fields) = %d; want %d", got, want)
70 } else if got, want := msg.Fields[0].FieldDescriptorProto, fd.MessageType[0].Field[0]; got != want {
71 t.Errorf("msg.Fields[0].FieldDescriptorProto = %v; want %v", got, want)
72 } else if got, want := msg.Fields[0].Message, msg; got != want {
73 t.Errorf("msg.Fields[0].Message = %v; want %v", got, want)
74 }
75
76 if got, want := len(file.Messages), 1; got != want {
77 t.Errorf("file.Meeesages = %#v; want %#v", file.Messages, []*Message{msg})
78 }
79 if got, want := file.Messages[0], msg; got != want {
80 t.Errorf("file.Meeesages[0] = %v; want %v", got, want)
81 }
82 }
83
84 func TestLoadFileNestedPackage(t *testing.T) {
85 reg := NewRegistry()
86 loadFile(t, reg, `
87 name: 'example.proto'
88 package: 'example.nested.nested2'
89 `)
90
91 file := reg.files["example.proto"]
92 if file == nil {
93 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
94 return
95 }
96 wantPkg := GoPackage{Path: ".", Name: "example_nested_nested2"}
97 if got, want := file.GoPkg, wantPkg; got != want {
98 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
99 }
100 }
101
102 func TestLoadFileWithDir(t *testing.T) {
103 reg := NewRegistry()
104 loadFile(t, reg, `
105 name: 'path/to/example.proto'
106 package: 'example'
107 `)
108
109 file := reg.files["path/to/example.proto"]
110 if file == nil {
111 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
112 return
113 }
114 wantPkg := GoPackage{Path: "path/to", Name: "example"}
115 if got, want := file.GoPkg, wantPkg; got != want {
116 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
117 }
118 }
119
120 func TestLoadFileWithoutPackage(t *testing.T) {
121 reg := NewRegistry()
122 loadFile(t, reg, `
123 name: 'path/to/example_file.proto'
124 `)
125
126 file := reg.files["path/to/example_file.proto"]
127 if file == nil {
128 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
129 return
130 }
131 wantPkg := GoPackage{Path: "path/to", Name: "example_file"}
132 if got, want := file.GoPkg, wantPkg; got != want {
133 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
134 }
135 }
136
137 func TestLoadFileWithMapping(t *testing.T) {
138 reg := NewRegistry()
139 reg.AddPkgMap("path/to/example.proto", "example.com/proj/example/proto")
140 loadFile(t, reg, `
141 name: 'path/to/example.proto'
142 package: 'example'
143 `)
144
145 file := reg.files["path/to/example.proto"]
146 if file == nil {
147 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
148 return
149 }
150 wantPkg := GoPackage{Path: "example.com/proj/example/proto", Name: "example"}
151 if got, want := file.GoPkg, wantPkg; got != want {
152 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
153 }
154 }
155
156 func TestLoadFileWithPackageNameCollision(t *testing.T) {
157 reg := NewRegistry()
158 loadFile(t, reg, `
159 name: 'path/to/another.proto'
160 package: 'example'
161 `)
162 loadFile(t, reg, `
163 name: 'path/to/example.proto'
164 package: 'example'
165 `)
166 if err := reg.ReserveGoPackageAlias("ioutil", "io/ioutil"); err != nil {
167 t.Fatalf("reg.ReserveGoPackageAlias(%q) failed with %v; want success", "ioutil", err)
168 }
169 loadFile(t, reg, `
170 name: 'path/to/ioutil.proto'
171 package: 'ioutil'
172 `)
173
174 file := reg.files["path/to/another.proto"]
175 if file == nil {
176 t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/another.proto")
177 return
178 }
179 wantPkg := GoPackage{Path: "path/to", Name: "example"}
180 if got, want := file.GoPkg, wantPkg; got != want {
181 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
182 }
183
184 file = reg.files["path/to/example.proto"]
185 if file == nil {
186 t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/example.proto")
187 return
188 }
189 wantPkg = GoPackage{Path: "path/to", Name: "example", Alias: ""}
190 if got, want := file.GoPkg, wantPkg; got != want {
191 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
192 }
193
194 file = reg.files["path/to/ioutil.proto"]
195 if file == nil {
196 t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/ioutil.proto")
197 return
198 }
199 wantPkg = GoPackage{Path: "path/to", Name: "ioutil", Alias: "ioutil_0"}
200 if got, want := file.GoPkg, wantPkg; got != want {
201 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
202 }
203 }
204
205 func TestLoadFileWithIdenticalGoPkg(t *testing.T) {
206 reg := NewRegistry()
207 reg.AddPkgMap("path/to/another.proto", "example.com/example")
208 reg.AddPkgMap("path/to/example.proto", "example.com/example")
209 loadFile(t, reg, `
210 name: 'path/to/another.proto'
211 package: 'example'
212 `)
213 loadFile(t, reg, `
214 name: 'path/to/example.proto'
215 package: 'example'
216 `)
217
218 file := reg.files["path/to/example.proto"]
219 if file == nil {
220 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
221 return
222 }
223 wantPkg := GoPackage{Path: "example.com/example", Name: "example"}
224 if got, want := file.GoPkg, wantPkg; got != want {
225 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
226 }
227
228 file = reg.files["path/to/another.proto"]
229 if file == nil {
230 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
231 return
232 }
233 wantPkg = GoPackage{Path: "example.com/example", Name: "example"}
234 if got, want := file.GoPkg, wantPkg; got != want {
235 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
236 }
237 }
238
239 func TestLoadFileWithPrefix(t *testing.T) {
240 reg := NewRegistry()
241 reg.SetPrefix("third_party")
242 loadFile(t, reg, `
243 name: 'path/to/example.proto'
244 package: 'example'
245 `)
246
247 file := reg.files["path/to/example.proto"]
248 if file == nil {
249 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
250 return
251 }
252 wantPkg := GoPackage{Path: "third_party/path/to", Name: "example"}
253 if got, want := file.GoPkg, wantPkg; got != want {
254 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
255 }
256 }
257
258 func TestLookupMsgWithoutPackage(t *testing.T) {
259 reg := NewRegistry()
260 fd := loadFile(t, reg, `
261 name: 'example.proto'
262 message_type <
263 name: 'ExampleMessage'
264 field <
265 name: 'str'
266 label: LABEL_OPTIONAL
267 type: TYPE_STRING
268 number: 1
269 >
270 >
271 `)
272
273 msg, err := reg.LookupMsg("", ".ExampleMessage")
274 if err != nil {
275 t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", "", ".ExampleMessage", err)
276 return
277 }
278 if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
279 t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", "", ".ExampleMessage", got, want)
280 }
281 }
282
283 func TestLookupMsgWithNestedPackage(t *testing.T) {
284 reg := NewRegistry()
285 fd := loadFile(t, reg, `
286 name: 'example.proto'
287 package: 'nested.nested2.mypackage'
288 message_type <
289 name: 'ExampleMessage'
290 field <
291 name: 'str'
292 label: LABEL_OPTIONAL
293 type: TYPE_STRING
294 number: 1
295 >
296 >
297 `)
298
299 for _, name := range []string{
300 "nested.nested2.mypackage.ExampleMessage",
301 "nested2.mypackage.ExampleMessage",
302 "mypackage.ExampleMessage",
303 "ExampleMessage",
304 } {
305 msg, err := reg.LookupMsg("nested.nested2.mypackage", name)
306 if err != nil {
307 t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", ".nested.nested2.mypackage", name, err)
308 return
309 }
310 if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
311 t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", ".nested.nested2.mypackage", name, got, want)
312 }
313 }
314
315 for _, loc := range []string{
316 ".nested.nested2.mypackage",
317 "nested.nested2.mypackage",
318 ".nested.nested2",
319 "nested.nested2",
320 ".nested",
321 "nested",
322 ".",
323 "",
324 "somewhere.else",
325 } {
326 name := "nested.nested2.mypackage.ExampleMessage"
327 msg, err := reg.LookupMsg(loc, name)
328 if err != nil {
329 t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", loc, name, err)
330 return
331 }
332 if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
333 t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", loc, name, got, want)
334 }
335 }
336
337 for _, loc := range []string{
338 ".nested.nested2.mypackage",
339 "nested.nested2.mypackage",
340 ".nested.nested2",
341 "nested.nested2",
342 ".nested",
343 "nested",
344 } {
345 name := "nested2.mypackage.ExampleMessage"
346 msg, err := reg.LookupMsg(loc, name)
347 if err != nil {
348 t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", loc, name, err)
349 return
350 }
351 if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
352 t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", loc, name, got, want)
353 }
354 }
355 }
356
357 func TestLoadWithInconsistentTargetPackage(t *testing.T) {
358 for _, spec := range []struct {
359 req string
360 consistent bool
361 }{
362
363 {
364 req: `
365 file_to_generate: 'a.proto'
366 file_to_generate: 'b.proto'
367 proto_file <
368 name: 'a.proto'
369 message_type < name: 'A' >
370 service <
371 name: "AService"
372 method <
373 name: "Meth"
374 input_type: "A"
375 output_type: "A"
376 options <
377 [google.api.http] < post: "/v1/a" body: "*" >
378 >
379 >
380 >
381 >
382 proto_file <
383 name: 'b.proto'
384 message_type < name: 'B' >
385 service <
386 name: "BService"
387 method <
388 name: "Meth"
389 input_type: "B"
390 output_type: "B"
391 options <
392 [google.api.http] < post: "/v1/b" body: "*" >
393 >
394 >
395 >
396 >
397 `,
398 consistent: false,
399 },
400
401 {
402 req: `
403 file_to_generate: 'a.proto'
404 file_to_generate: 'b.proto'
405 proto_file <
406 name: 'a.proto'
407 package: 'example.foo'
408 message_type < name: 'A' >
409 service <
410 name: "AService"
411 method <
412 name: "Meth"
413 input_type: "A"
414 output_type: "A"
415 options <
416 [google.api.http] < post: "/v1/a" body: "*" >
417 >
418 >
419 >
420 >
421 proto_file <
422 name: 'b.proto'
423 package: 'example.foo'
424 message_type < name: 'B' >
425 service <
426 name: "BService"
427 method <
428 name: "Meth"
429 input_type: "B"
430 output_type: "B"
431 options <
432 [google.api.http] < post: "/v1/b" body: "*" >
433 >
434 >
435 >
436 >
437 `,
438 consistent: true,
439 },
440
441 {
442 req: `
443 file_to_generate: 'a.proto'
444 file_to_generate: 'b.proto'
445 proto_file <
446 name: 'a.proto'
447 options < go_package: 'foo' >
448 message_type < name: 'A' >
449 service <
450 name: "AService"
451 method <
452 name: "Meth"
453 input_type: "A"
454 output_type: "A"
455 options <
456 [google.api.http] < post: "/v1/a" body: "*" >
457 >
458 >
459 >
460 >
461 proto_file <
462 name: 'b.proto'
463 options < go_package: 'foo' >
464 message_type < name: 'B' >
465 service <
466 name: "BService"
467 method <
468 name: "Meth"
469 input_type: "B"
470 output_type: "B"
471 options <
472 [google.api.http] < post: "/v1/b" body: "*" >
473 >
474 >
475 >
476 >
477 `,
478 consistent: true,
479 },
480
481 {
482 req: `
483 file_to_generate: 'a.proto'
484 file_to_generate: 'b.proto'
485 proto_file <
486 name: 'a.proto'
487 package: 'example.foo'
488 options < go_package: 'foo' >
489 message_type < name: 'A' >
490 service <
491 name: "AService"
492 method <
493 name: "Meth"
494 input_type: "A"
495 output_type: "A"
496 options <
497 [google.api.http] < post: "/v1/a" body: "*" >
498 >
499 >
500 >
501 >
502 proto_file <
503 name: 'b.proto'
504 package: 'example.foo'
505 options < go_package: 'foo' >
506 message_type < name: 'B' >
507 service <
508 name: "BService"
509 method <
510 name: "Meth"
511 input_type: "B"
512 output_type: "B"
513 options <
514 [google.api.http] < post: "/v1/b" body: "*" >
515 >
516 >
517 >
518 >
519 `,
520 consistent: true,
521 },
522 } {
523 reg := NewRegistry()
524 err := load(t, reg, spec.req)
525 if got, want := err == nil, spec.consistent; got != want {
526 if want {
527 t.Errorf("reg.Load(%s) failed with %v; want success", spec.req, err)
528 continue
529 }
530 t.Errorf("reg.Load(%s) succeeded; want an package inconsistency error", spec.req)
531 }
532 }
533 }
534
535 func TestLoadOverridedPackageName(t *testing.T) {
536 reg := NewRegistry()
537 loadFile(t, reg, `
538 name: 'example.proto'
539 package: 'example'
540 options < go_package: 'example.com/xyz;pb' >
541 `)
542 file := reg.files["example.proto"]
543 if file == nil {
544 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
545 return
546 }
547 wantPkg := GoPackage{Path: "example.com/xyz", Name: "pb"}
548 if got, want := file.GoPkg, wantPkg; got != want {
549 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
550 }
551 }
552
553 func TestLoadSetInputPath(t *testing.T) {
554 reg := NewRegistry()
555 reg.SetImportPath("foo/examplepb")
556 loadFile(t, reg, `
557 name: 'example.proto'
558 package: 'example'
559 `)
560 file := reg.files["example.proto"]
561 if file == nil {
562 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
563 return
564 }
565 wantPkg := GoPackage{Path: ".", Name: "examplepb"}
566 if got, want := file.GoPkg, wantPkg; got != want {
567 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
568 }
569 }
570
571 func TestLoadGoPackageInputPath(t *testing.T) {
572 reg := NewRegistry()
573 reg.SetImportPath("examplepb")
574 loadFile(t, reg, `
575 name: 'example.proto'
576 package: 'example'
577 options < go_package: 'example.com/xyz;pb' >
578 `)
579 file := reg.files["example.proto"]
580 if file == nil {
581 t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
582 return
583 }
584 wantPkg := GoPackage{Path: "example.com/xyz", Name: "pb"}
585 if got, want := file.GoPkg, wantPkg; got != want {
586 t.Errorf("file.GoPkg = %#v; want %#v", got, want)
587 }
588 }
589
590 func TestUnboundExternalHTTPRules(t *testing.T) {
591 reg := NewRegistry()
592 methodName := ".example.ExampleService.Echo"
593 reg.AddExternalHTTPRule(methodName, nil)
594 assertStringSlice(t, "unbound external HTTP rules", reg.UnboundExternalHTTPRules(), []string{methodName})
595 loadFile(t, reg, `
596 name: "path/to/example.proto",
597 package: "example"
598 message_type <
599 name: "StringMessage"
600 field <
601 name: "string"
602 number: 1
603 label: LABEL_OPTIONAL
604 type: TYPE_STRING
605 >
606 >
607 service <
608 name: "ExampleService"
609 method <
610 name: "Echo"
611 input_type: "StringMessage"
612 output_type: "StringMessage"
613 >
614 >
615 `)
616 assertStringSlice(t, "unbound external HTTP rules", reg.UnboundExternalHTTPRules(), []string{})
617 }
618
619 func assertStringSlice(t *testing.T, message string, got, want []string) {
620 if len(got) != len(want) {
621 t.Errorf("%s = %#v len(%d); want %#v len(%d)", message, got, len(got), want, len(want))
622 }
623 for i := range want {
624 if got[i] != want[i] {
625 t.Errorf("%s[%d] = %#v; want %#v", message, i, got[i], want[i])
626 }
627 }
628 }
629
View as plain text