blob: 1344430ea958c0b4d387dd68bd2448338fca5590 [file] [log] [blame]
Zsolt Harasztibae12752016-10-10 09:55:30 -07001#
2# Copyright 2016 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16import json
17import os
18from unittest import TestCase
19
20from chameleon.protoc_plugins.descriptor_parser import DescriptorParser
21from chameleon.protoc_plugins.swagger_template \
22 import native_descriptors_to_swagger, DuplicateMethodAndPathError, \
23 ProtobufCompilationFailedError, InvalidPathArgumentError
24from tests.utests.chameleon.protoc_plugins.test_utils import unindent, \
25 json_rt, generate_plugin_request, load_file
26
27
28class SwaggerTemplateTests(TestCase):
29
30 maxDiff = 10000
31
32 def gen_swagger(self, proto):
33 request = generate_plugin_request(proto)
34 parser = DescriptorParser()
35 native_data = parser.parse_file_descriptors(request.proto_file,
36 type_tag_name='_type',
37 fold_comments=True)
38 swagger = native_descriptors_to_swagger(native_data)
39 return swagger
40
41 def test_empty_def(self):
42
43 proto = unindent("""
44 syntax = "proto3";
45 package test;
46 """)
47
48 expected_swagger = {
49 u'swagger': u'2.0',
50 u'info': {
51 u'title': u'test.proto',
52 u'version': u'version not set'
53 },
54 u'schemes': [u"http", u"https"],
55 u'consumes': [u"application/json"],
56 u'produces': [u"application/json"],
57 u'paths': {},
58 u'definitions': {}
59 }
60
61 swagger = self.gen_swagger(proto)
62 self.assertEqual(json_rt(swagger), expected_swagger)
63
64 def test_empty_message_with_service(self):
65
66 proto = unindent("""
67 syntax = "proto3";
68 package test;
69 import "google/api/annotations.proto";
70 message Null {}
71 service TestService {
72 rpc Get(Null) returns(Null) {
73 option (google.api.http) = {
74 get: "/test"
75 };
76 }
77 }
78 """)
79
80 expected_swagger = {
81 u'swagger': u'2.0',
82 u'info': {
83 u'title': u'test.proto',
84 u'version': u"version not set"
85 },
86 u'schemes': [u"http", u"https"],
87 u'consumes': [u"application/json"],
88 u'produces': [u"application/json"],
89 u'paths': {
90 u'/test': {
91 u'get': {
92 u'operationId': u'Get',
93 u'responses': {
94 u'200': {
95 u'description': u'',
96 u'schema': {
97 u'$ref': u'#/definitions/test.Null'
98 }
99 }
100 },
101 u'tags': [u'TestService']
102 }
103 }
104 },
105 u'definitions': {
106 u'test.Null': {
107 u'type': u'object'
108 }
109 }
110 }
111
112 swagger = self.gen_swagger(proto)
113 self.assertEqual(json_rt(swagger), expected_swagger)
114
115 def test_simple_annotated_message_with_simple_annotated_service(self):
116
117 proto = unindent("""
118 syntax = "proto3";
119 package test;
120 import "google/api/annotations.proto";
121
122 // Simple Message
123 message Simple {
124 string str = 1; // a string attribute
125 int32 int = 2; // an int32 attribute
126 }
127
128 // Service to get things done
129 service TestService {
130
131 /* Get simple answer
132 *
133 * Returns the true answer to all of life's persistent questions.
134 */
135 rpc Get(Simple) returns(Simple) {
136 option (google.api.http) = {
137 get: "/test"
138 };
139 }
140 }
141 """)
142
143 expected_swagger = {
144 u'swagger': u'2.0',
145 u'info': {
146 u'title': u'test.proto',
147 u'version': u"version not set"
148 },
149 u'schemes': [u"http", u"https"],
150 u'consumes': [u"application/json"],
151 u'produces': [u"application/json"],
152 u'paths': {
153 u'/test': {
154 u'get': {
155 u'summary': u'Get simple answer',
156 u'description':
157 u' Returns the true answer to all of life\'s '
158 u'persistent questions.',
159 u'operationId': u'Get',
160 u'responses': {
161 u'200': {
162 u'description': u'',
163 u'schema': {
164 u'$ref': u'#/definitions/test.Simple'
165 }
166 }
167 },
168 u'tags': [u'TestService']
169 }
170 }
171 },
172 u'definitions': {
173 u'test.Simple': {
174 u'description': u'Simple Message',
175 u'type': u'object',
176 u'properties': {
177 u'int': {
178 u'description': u'an int32 attribute',
179 u'type': u'integer',
180 u'format': u'int32'
181 },
182 u'str': {
183 u'description': u'a string attribute',
184 u'type': u'string',
185 u'format': u'string'
186 }
187 }
188 }
189 }
190 }
191
192 swagger = self.gen_swagger(proto)
193 self.assertEqual(json_rt(swagger), expected_swagger)
194
195 def test_method_input_params_in_body(self):
196
197 proto = unindent("""
198 syntax = "proto3";
199 package test;
200 import "google/api/annotations.proto";
201
202 // Simple Message
203 message Simple {
204 string str = 1; // a string attribute
205 int32 int = 2; // an int32 attribute
206 }
207
208 // Service to get things done
209 service TestService {
210
211 /* Get simple answer
212 *
213 * Returns the true answer to all of life's persistent questions.
214 */
215 rpc Get(Simple) returns(Simple) {
216 option (google.api.http) = {
217 get: "/test"
218 };
219 }
220
221 /*
222 * Make up an answer (notice the leading blank line)
223 *
224 * Define the ultimate answer
225 */
226 rpc MakeUp(Simple) returns(Simple) {
227 option (google.api.http) = {
228 post: "/test"
229 body: "*"
230 };
231 }
232 }
233 """)
234
235 expected_swagger = {
236 u'swagger': u'2.0',
237 u'info': {
238 u'title': u'test.proto',
239 u'version': u"version not set"
240 },
241 u'schemes': [u"http", u"https"],
242 u'consumes': [u"application/json"],
243 u'produces': [u"application/json"],
244 u'paths': {
245 u'/test': {
246 u'get': {
247 u'summary': u'Get simple answer',
248 u'description':
249 u' Returns the true answer to all of life\'s '
250 u'persistent questions.',
251 u'operationId': u'Get',
252 u'responses': {
253 u'200': {
254 u'description': u'',
255 u'schema': {
256 u'$ref': u'#/definitions/test.Simple'
257 }
258 }
259 },
260 u'tags': [u'TestService']
261 },
262 u'post': {
263 u'summary': u'Make up an answer (notice the leading '
264 u'blank line)',
265 u'description': u' Define the ultimate answer',
266 u'operationId': u'MakeUp',
267 u'parameters': [{
268 u'name': u'body',
269 u'in': u'body',
270 u'required': True,
271 u'schema': {u'$ref': u'#/definitions/test.Simple'}
272 }],
273 u'responses': {
274 u'200': {
275 u'description': u'',
276 u'schema': {
277 u'$ref': u'#/definitions/test.Simple'
278 }
279 }
280 },
281 u'tags': [u'TestService']
282 }
283 }
284 },
285 u'definitions': {
286 u'test.Simple': {
287 u'description': u'Simple Message',
288 u'type': u'object',
289 u'properties': {
290 u'int': {
291 u'description': u'an int32 attribute',
292 u'type': u'integer',
293 u'format': u'int32'
294 },
295 u'str': {
296 u'description': u'a string attribute',
297 u'type': u'string',
298 u'format': u'string'
299 }
300 }
301 }
302 }
303 }
304
305 swagger = self.gen_swagger(proto)
306 self.assertEqual(json_rt(swagger), expected_swagger)
307
308 def test_catch_repeating_verbs_for_same_path(self):
309
310 proto = unindent("""
311 syntax = "proto3";
312 package test;
313 import "google/api/annotations.proto";
314 message Null {}
315 service TestService {
316 rpc Get(Null) returns(Null) {
317 option (google.api.http) = {
318 get: "/test"
319 };
320 }
321 rpc MakeUp(Null) returns(Null) {
322 option (google.api.http) = {
323 get: "/test"
324 body: "*"
325 };
326 }
327 }
328 """)
329
330 with self.assertRaises(DuplicateMethodAndPathError):
331 self.gen_swagger(proto)
332
333 def test_catch_unresolved_message_type_reference(self):
334
335 proto = unindent("""
336 syntax = "proto3";
337 package test;
338 import "google/api/annotations.proto";
339 message Null {}
340 service TestService {
341 rpc Get(Simple) returns(Simple) {
342 option (google.api.http) = {
343 get: "/test"
344 };
345 }
346 rpc MakeUp(Simple) returns(Simple) {
347 option (google.api.http) = {
348 get: "/test"
349 body: "*"
350 };
351 }
352 }
353 """)
354
355 with self.assertRaises(ProtobufCompilationFailedError):
356 self.gen_swagger(proto)
357
358 def test_path_parameter_handling(self):
359
360 proto = unindent("""
361 syntax = "proto3";
362 package test;
363 import "google/api/annotations.proto";
364 message Simple {
365 string str = 1;
366 int32 int = 2;
367 }
368 service TestService {
369 rpc Get(Simple) returns(Simple) {
370 option (google.api.http) = {
371 get: "/test/{str}/{int}"
372 };
373 }
374 }
375 """)
376
377 expected_swagger_path = {
378 u'/test/{str}/{int}': {
379 u'get': {
380 u'operationId': u'Get',
381 u'parameters': [{
382 u'name': u'str',
383 u'in': u'path',
384 u'type': u'string',
385 u'format': u'string',
386 u'required': True
387 }, {
388 u'name': u'int',
389 u'in': u'path',
390 u'type': u'integer',
391 u'format': u'int32',
392 u'required': True
393 }],
394 u'responses': {
395 u'200': {
396 u'description': u'',
397 u'schema': {
398 u'$ref': u'#/definitions/test.Simple'
399 }
400 }
401 },
402 u'tags': [u'TestService']
403 }
404 }
405 }
406
407 swagger = self.gen_swagger(proto)
408 self.assertEqual(json_rt(swagger['paths']), expected_swagger_path)
409
410 def test_path_parameter_error_handling(self):
411
412 proto = unindent("""
413 syntax = "proto3";
414 package test;
415 import "google/api/annotations.proto";
416 message Simple {
417 string str = 1;
418 int32 int = 2;
419 }
420 service TestService {
421 rpc Get(Simple) returns(Simple) {
422 option (google.api.http) = {
423 get: "/test/{str}/{xxxxx}/{int}"
424 };
425 }
426 }
427 """)
428
429 with self.assertRaises(InvalidPathArgumentError):
430 self.gen_swagger(proto)
431
432 def test_alternative_bindings(self):
433
434 proto = unindent("""
435 syntax = "proto3";
436 package test;
437 import "google/api/annotations.proto";
438 message Simple {
439 string str = 1;
440 int32 int = 2;
441 }
442 service TestService {
443 rpc Get(Simple) returns(Simple) {
444 option (google.api.http) = {
445 get: "/v1/test/{str}/{int}"
446 additional_bindings {
447 post: "/v2/test"
448 body: "*"
449 }
450 additional_bindings {
451 get: "/v2/test/{int}/{str}"
452 }
453 };
454 }
455 }
456 """)
457
458 expected_swagger_path = {
459 u'/v1/test/{str}/{int}': {
460 u'get': {
461 u'operationId': u'Get',
462 u'parameters': [{
463 u'name': u'str',
464 u'in': u'path',
465 u'type': u'string',
466 u'format': u'string',
467 u'required': True
468 }, {
469 u'name': u'int',
470 u'in': u'path',
471 u'type': u'integer',
472 u'format': u'int32',
473 u'required': True
474 }],
475 u'responses': {
476 u'200': {
477 u'description': u'',
478 u'schema': {
479 u'$ref': u'#/definitions/test.Simple'
480 }
481 }
482 },
483 u'tags': [u'TestService']
484 }
485 },
486 u'/v2/test': {
487 u'post': {
488 u'operationId': u'Get',
489 u'parameters': [{
490 u'in': u'body',
491 u'name': u'body',
492 u'required': True,
493 u'schema': {u'$ref': u'#/definitions/test.Simple'}
494 }],
495 u'responses': {
496 u'200': {
497 u'description': u'',
498 u'schema': {u'$ref': u'#/definitions/test.Simple'}
499 }
500 },
501 u'tags': [u'TestService']
502 }
503 },
504 u'/v2/test/{int}/{str}': {
505 u'get': {
506 u'operationId': u'Get',
507 u'parameters': [{
508 u'format': u'int32',
509 u'in': u'path',
510 u'name': u'int',
511 u'required': True,
512 u'type': u'integer'
513 }, {
514 u'format': u'string',
515 u'in': u'path',
516 u'name': u'str',
517 u'required': True,
518 u'type': u'string'
519 }],
520 u'responses': {
521 u'200': {
522 u'description': u'',
523 u'schema': {u'$ref': u'#/definitions/test.Simple'}
524 }
525 },
526 u'tags': [u'TestService']
527 }
528 }
529 }
530
531 swagger = self.gen_swagger(proto)
532 self.assertEqual(json_rt(swagger['paths']), expected_swagger_path)
533
534 def test_google_null(self):
535
536 proto = unindent("""
537 syntax = "proto3";
538 package test;
539 import "google/api/annotations.proto";
540 import "google/protobuf/empty.proto";
541 service TestService {
542 rpc Get(google.protobuf.Empty) returns(google.protobuf.Empty) {
543 option (google.api.http) = {
544 get: "/echo"
545 };
546 }
547 }
548 """)
549
550 expected_swagger = {
551 u'swagger': u'2.0',
552 u'info': {
553 u'title': u'test.proto',
554 u'version': u"version not set"
555 },
556 u'schemes': [u"http", u"https"],
557 u'consumes': [u"application/json"],
558 u'produces': [u"application/json"],
559 u'paths': {
560 u'/echo': {
561 u'get': {
562 u'operationId': u'Get',
563 u'responses': {
564 u'200': {
565 u'description': u'',
566 u'schema': {
567 u'$ref':
568 u'#/definitions/google.protobuf.Empty'
569 }
570 }
571 },
572 u'tags': [u'TestService']
573 }
574 }
575 },
576 u'definitions': {
577 u'google.protobuf.Empty': {
578 u'description': u'A generic empty message that you can '
579 u're-use to avoid defining duplicated\n '
580 u'empty messages in your APIs. A typical '
581 u'example is to use it as the request\n '
582 u'or the response type of an API method. '
583 u'For instance:\n\n service Foo {\n '
584 u' rpc Bar(google.protobuf.Empty) '
585 u'returns (google.protobuf.Empty);\n '
586 u'}\n\n The JSON representation for '
587 u'`Empty` is empty JSON object `{}`.',
588 u'type': u'object'
589 }
590 }
591 }
592
593 swagger = self.gen_swagger(proto)
594 self.assertEqual(json_rt(swagger), expected_swagger)
595
596
597 def test_nested_type_definitions(self):
598
599 proto = unindent("""
600 syntax = "proto3";
601 package test;
602 import "google/api/annotations.proto";
603 import "google/protobuf/empty.proto";
604 message Null {}
605 message Outer {
606 message Inner {
607 message Innermost {
608 bool healthy = 1;
609 string illness = 2;
610 }
611 Innermost innermost = 1;
612 string other = 2;
613 }
614 string name = 1;
615 Inner inner = 2;
616 }
617 service TestService {
618 rpc Get(Null) returns(Outer) {
619 option (google.api.http) = {
620 get: "/test"
621 };
622 }
623 }
624 """)
625
626 expected_swagger_definitions = {
627 u'test.Null': {u'type': u'object'},
628 u'test.Outer': {
629 u'type': u'object',
630 u'properties': {
631 u'inner': {
632 u'$ref': u'#/definitions/test.Outer.Inner'
633 },
634 u'name': {
635 u'type': u'string',
636 u'format': u'string'
637 }
638 }
639 },
640 u'test.Outer.Inner': {
641 u'type': u'object',
642 u'properties': {
643 u'innermost': {
644 u'$ref': u'#/definitions/test.Outer.Inner.Innermost'
645 },
646 u'other': {
647 u'type': u'string',
648 u'format': u'string'
649 }
650 }
651 },
652 u'test.Outer.Inner.Innermost': {
653 u'type': u'object',
654 u'properties': {
655 u'healthy': {
656 u'type': u'boolean',
657 u'format': u'boolean'
658 },
659 u'illness': {
660 u'type': u'string',
661 u'format': u'string'
662 }
663 }
664 }
665 }
666
667 swagger = self.gen_swagger(proto)
668 self.assertEqual(json_rt(swagger['definitions']),
669 expected_swagger_definitions)
670
671 def test_enum(self):
672
673 proto = unindent("""
674 syntax = "proto3";
675 package test;
676 import "google/api/annotations.proto";
677 message Null {};
678 // Detailed weather state
679 enum WeatherState {
680 GOOD = 0; // Weather is good
681 BAD = 1; // Weather is bad
682 }
683 message Forecast {
684 WeatherState forecast = 1;
685 }
686 service ForecastService {
687 rpc GetForecast(Null) returns(Forecast) {
688 option (google.api.http) = {
689 get: "/forecast"
690 };
691 }
692 }
693 """)
694
695 expected_swagger_definitions = {
696 u'test.Null': {u'type': u'object'},
697 u'test.WeatherState': {
698 u'default': u'GOOD',
699 u'description': u'Detailed weather state\n'
700 u'Valid values:\n'
701 u' - GOOD: Weather is good\n'
702 u' - BAD: Weather is bad',
703 u'type': u'string',
704 u'enum': [u'GOOD', u'BAD']
705 },
706 u'test.Forecast': {
707 u'type': u'object',
708 u'properties': {
709 u'forecast': {u'$ref': u'#/definitions/test.WeatherState'}
710 }
711 }
712 }
713
714 swagger = self.gen_swagger(proto)
715 self.assertEqual(json_rt(swagger['definitions']),
716 expected_swagger_definitions)
717
718 def test_nested_enum(self):
719
720 proto = unindent("""
721 syntax = "proto3";
722 package test;
723 import "google/api/annotations.proto";
724 message Null {};
725 message Forecast {
726 // Detailed weather state
727 enum WeatherState {
728 GOOD = 0; // Weather is good
729 BAD = 1; // Weather is bad
730 }
731 WeatherState forecast = 1;
732 }
733 service ForecastService {
734 rpc GetForecast(Null) returns(Forecast) {
735 option (google.api.http) = {
736 get: "/forecast"
737 };
738 }
739 }
740 """)
741
742 expected_swagger_definitions = {
743 u'test.Null': {u'type': u'object'},
744 u'test.Forecast.WeatherState': {
745 u'default': u'GOOD',
746 u'description': u'Detailed weather state\n'
747 u'Valid values:\n'
748 u' - GOOD: Weather is good\n'
749 u' - BAD: Weather is bad',
750 u'type': u'string',
751 u'enum': [u'GOOD', u'BAD']
752 },
753 u'test.Forecast': {
754 u'type': u'object',
755 u'properties': {
756 u'forecast': {
757 u'$ref': u'#/definitions/test.Forecast.WeatherState'}
758 }
759 }
760 }
761
762 swagger = self.gen_swagger(proto)
763 self.assertEqual(json_rt(swagger['definitions']),
764 expected_swagger_definitions)
765
766 def test_array_of_simple_types(self):
767
768 proto = unindent("""
769 syntax = "proto3";
770 package test;
771 import "google/api/annotations.proto";
772 message Null {};
773 message Invitations {
774 string event = 1;
775 repeated string names = 2;
776 repeated int32 ages = 3;
777 }
778 service RsvpService {
779 rpc Get(Null) returns(Invitations) {
780 option (google.api.http) = {
781 get: "/invitations"
782 };
783 }
784 }
785 """)
786
787 expected_swagger_definitions = {
788 u'test.Null': {u'type': u'object'},
789 u'test.Invitations': {
790 u'type': u'object',
791 u'properties': {
792 u'event': {
793 u'type': u'string',
794 u'format': u'string'
795 },
796 u'names': {
797 u'type': u'array',
798 u'items': {
799 u'type': u'string',
800 u'format': u'string'
801 }
802 },
803 u'ages': {
804 u'type': u'array',
805 u'items': {
806 u'type': u'integer',
807 u'format': u'int32'
808 }
809 }
810 }
811 }
812 }
813
814 swagger = self.gen_swagger(proto)
815 self.assertEqual(json_rt(swagger['definitions']),
816 expected_swagger_definitions)
817
818 def test_array_of_object_type(self):
819
820 proto = unindent("""
821 syntax = "proto3";
822 package test;
823 import "google/api/annotations.proto";
824 message Null {};
825 message Invitations {
826 message Address {
827 string street = 1;
828 string city = 2;
829 }
830 string event = 1;
831 repeated Null nulles = 2;
832 repeated Address addresses = 3;
833 }
834 service RsvpService {
835 rpc Get(Null) returns(Invitations) {
836 option (google.api.http) = {
837 get: "/invitations"
838 };
839 }
840 }
841 """)
842
843 expected_swagger_definitions = {
844 u'test.Null': {u'type': u'object'},
845 u'test.Invitations.Address': {
846 u'type': u'object',
847 u'properties': {
848 u'street': {
849 u'type': u'string',
850 u'format': u'string'
851 },
852 u'city': {
853 u'type': u'string',
854 u'format': u'string'
855 }
856 }
857 },
858 u'test.Invitations': {
859 u'type': u'object',
860 u'properties': {
861 u'event': {
862 u'type': u'string',
863 u'format': u'string'
864 },
865 u'nulles': {
866 u'type': u'array',
867 u'items': {
868 u'$ref': u'#/definitions/test.Null'
869 }
870 },
871 u'addresses': {
872 u'type': u'array',
873 u'items': {
874 u'$ref': u'#/definitions/test.Invitations.Address'
875 }
876 }
877 }
878 }
879 }
880
881 swagger = self.gen_swagger(proto)
882 self.assertEqual(json_rt(swagger['definitions']),
883 expected_swagger_definitions)
884
885 def test_recursively_nested_values(self):
886
887 proto = unindent("""
888 syntax = "proto3";
889 package test;
890 import "google/api/annotations.proto";
891 message Null {};
892 message TreeNode {
893 string name = 1;
894 repeated TreeNode children = 2;
895 }
896 service RsvpService {
897 rpc Get(Null) returns(TreeNode) {
898 option (google.api.http) = {
899 get: "/invitations"
900 };
901 }
902 }
903 """)
904
905 expected_swagger_definitions = {
906 u'test.Null': {u'type': u'object'},
907 u'test.TreeNode': {
908 u'type': u'object',
909 u'properties': {
910 u'name': {
911 u'type': u'string',
912 u'format': u'string'
913 },
914 u'children': {
915 u'type': u'array',
916 u'items': {
917 u'$ref': u'#/definitions/test.TreeNode'
918 }
919 }
920 }
921 }
922 }
923
924 swagger = self.gen_swagger(proto)
925 self.assertEqual(json_rt(swagger['definitions']),
926 expected_swagger_definitions)
927
928 def test_map_fields(self):
929
930 proto = unindent("""
931 syntax = "proto3";
932 package test;
933 import "google/api/annotations.proto";
934 message Null {};
935 message Maps {
936 map<string, string> string_map = 1;
937 map<string, int32> int32_map = 2;
938 map<string, Null> object_map = 3;
939 }
940 service RsvpService {
941 rpc Get(Null) returns(Maps) {
942 option (google.api.http) = {
943 get: "/maps"
944 };
945 }
946 }
947 """)
948
949 expected_swagger_definitions = {
950 u'test.Null': {u'type': u'object'},
951 u'test.Maps': {
952 u'type': u'object',
953 u'properties': {
954 u'string_map': {
955 u'type': u'object',
956 u'additionalProperties': {
957 u'type': u'string',
958 u'format': u'string'
959 }
960 },
961 u'int32_map': {
962 u'type': u'object',
963 u'additionalProperties': {
964 u'type': u'integer',
965 u'format': u'int32'
966 }
967 },
968 u'object_map': {
969 u'type': u'object',
970 u'additionalProperties': {
971 u'$ref': u'#/definitions/test.Null',
972 }
973 }
974 }
975 }
976 }
977
978 swagger = self.gen_swagger(proto)
979 self.assertEqual(json_rt(swagger['definitions']),
980 expected_swagger_definitions)
981
982 def test_array_and_map_of_enum(self):
983
984 proto = unindent("""
985 syntax = "proto3";
986 package test;
987 import "google/api/annotations.proto";
988 message Null {};
989 enum State {
990 GOOD = 0;
991 BAD = 1;
992 }
993 message Map {
994 map<string, State> enum_map = 1;
995 repeated State states = 2;
996 }
997 service RsvpService {
998 rpc Get(Null) returns(Map) {
999 option (google.api.http) = {
1000 get: "/maps"
1001 };
1002 }
1003 }
1004 """)
1005
1006 expected_swagger_definitions = {
1007 u'test.Null': {u'type': u'object'},
1008 u'test.State': {
1009 u'default': u'GOOD',
1010 u'description': u'State\n'
1011 u'Valid values:\n'
1012 u' - GOOD\n'
1013 u' - BAD',
1014 u'type': u'string',
1015 u'enum': [u'GOOD', u'BAD']
1016 },
1017 u'test.Map': {
1018 u'type': u'object',
1019 u'properties': {
1020 u'enum_map': {
1021 u'type': u'object',
1022 u'additionalProperties': {
1023 u'$ref': u'#/definitions/test.State',
1024 }
1025 },
1026 u'states': {
1027 u'type': u'array',
1028 u'items': {
1029 u'$ref': u'#/definitions/test.State'
1030 }
1031 }
1032 }
1033 }
1034 }
1035
1036 swagger = self.gen_swagger(proto)
1037 self.assertEqual(json_rt(swagger['definitions']),
1038 expected_swagger_definitions)
1039
1040 def test_kitchen_sink(self):
1041
1042 proto = load_file(
1043 os.path.dirname(__file__) + '/a_bit_of_everything.proto')
1044
1045 swagger = self.gen_swagger(proto)
1046
1047 expected_swagger = json.loads(load_file(
1048 os.path.dirname(__file__) + '/a_bit_of_everything.swagger.json')
1049 )
1050
1051 self.maxDiff = 100000
1052 self.assertEqual(json_rt(swagger), expected_swagger)