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