35 #include <google/protobuf/compiler/parser.h>
42 #include <google/protobuf/test_util2.h>
43 #include <google/protobuf/unittest.pb.h>
44 #include <google/protobuf/any.pb.h>
45 #include <google/protobuf/unittest_custom_options.pb.h>
46 #include <google/protobuf/io/tokenizer.h>
47 #include <google/protobuf/io/zero_copy_stream_impl.h>
48 #include <google/protobuf/descriptor.pb.h>
49 #include <google/protobuf/text_format.h>
50 #include <google/protobuf/wire_format.h>
51 #include <google/protobuf/testing/googletest.h>
52 #include <gtest/gtest.h>
53 #include <google/protobuf/stubs/substitute.h>
54 #include <google/protobuf/stubs/map_util.h>
62 class MockErrorCollector :
public io::ErrorCollector {
64 MockErrorCollector() =
default;
65 ~MockErrorCollector()
override =
default;
80 class MockValidationErrorCollector :
public DescriptorPool::ErrorCollector {
82 MockValidationErrorCollector(
const SourceLocationTable& source_locations,
83 io::ErrorCollector* wrapped_collector)
86 ~MockValidationErrorCollector() {}
111 void SetupParser(
const char*
text) {
122 void ExpectParsesTo(
const char*
input,
const char*
output) {
141 EXPECT_EQ(expected.DebugString(), actual.DebugString());
145 void ExpectHasErrors(
const char*
text,
const char* expected_errors) {
146 ExpectHasEarlyExitErrors(
text, expected_errors);
152 void ExpectHasEarlyExitErrors(
const char*
text,
const char* expected_errors) {
161 void ExpectHasValidationErrors(
const char*
text,
162 const char* expected_errors) {
164 SourceLocationTable source_locations;
165 parser_->RecordSourceLocationsTo(&source_locations);
168 file.set_name(
"foo.proto");
173 MockValidationErrorCollector validation_error_collector(source_locations,
176 file, &validation_error_collector) == NULL);
191 TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
194 "syntax = \"foobar\";\n"
195 "this line will not be parsed\n");
196 parser_->SetStopAfterSyntaxIdentifier(
true);
202 TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
205 "this line will not be parsed\n");
206 parser_->SetStopAfterSyntaxIdentifier(
true);
212 TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
215 "syntax = error;\n");
216 parser_->SetStopAfterSyntaxIdentifier(
true);
221 TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
222 SetupParser(
"message A {}");
230 TEST_F(ParserTest, WarnIfFieldNameIsNotUpperCamel) {
232 "syntax = \"proto2\";"
237 "Message name should be in UpperCamelCase. Found: abc.") !=
241 TEST_F(ParserTest, WarnIfFieldNameIsNotLowerUnderscore) {
243 "syntax = \"proto2\";"
245 " optional string SongName = 1;"
250 "Field name should be lowercase. Found: SongName") !=
254 TEST_F(ParserTest, WarnIfFieldNameContainsNumberImmediatelyFollowUnderscore) {
256 "syntax = \"proto2\";"
258 " optional string song_name_1 = 1;"
263 "Number should not come right after an underscore. Found: "
264 "song_name_1.") != std::string::npos);
269 typedef ParserTest ParseMessageTest;
271 TEST_F(ParseMessageTest, IgnoreBOM) {
273 " message TestMessage {\n"
274 " required int32 foo = 1;\n"
277 input[0] = (char)0xEF;
278 input[1] = (char)0xBB;
279 input[2] = (char)0xBF;
283 " name: \"TestMessage\""
284 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
288 TEST_F(ParseMessageTest, BOMError) {
290 " message TestMessage {\n"
291 " required int32 foo = 1;\n"
293 input[0] = (char)0xEF;
294 ExpectHasErrors(
input,
295 "0:1: Proto file starts with 0xEF but not UTF-8 BOM. "
296 "Only UTF-8 is accepted for proto file.\n"
297 "0:0: Expected top-level statement (e.g. \"message\").\n");
300 TEST_F(ParseMessageTest, SimpleMessage) {
302 "message TestMessage {\n"
303 " required int32 foo = 1;\n"
307 " name: \"TestMessage\""
308 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
312 TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
315 "message TestMessage {\n"
316 " required int32 foo = 1;\n"
320 " name: \"TestMessage\""
321 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
326 TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
328 "syntax = \"proto2\";\n"
329 "message TestMessage {\n"
330 " required int32 foo = 1;\n"
335 " name: \"TestMessage\""
336 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
341 TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
344 "syntax = \"proto2\";\n"
345 "message TestMessage {\n"
346 " required int32 foo = 1;\n"
351 " name: \"TestMessage\""
352 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
357 TEST_F(ParseMessageTest, SimpleFields) {
359 "message TestMessage {\n"
360 " required int32 foo = 15;\n"
361 " optional int32 bar = 34;\n"
362 " repeated int32 baz = 3;\n"
366 " name: \"TestMessage\""
367 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
368 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
369 " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }"
373 TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
375 "message TestMessage {\n"
376 " required int32 foo = 1;\n"
377 " required int64 foo = 1;\n"
378 " required uint32 foo = 1;\n"
379 " required uint64 foo = 1;\n"
380 " required sint32 foo = 1;\n"
381 " required sint64 foo = 1;\n"
382 " required fixed32 foo = 1;\n"
383 " required fixed64 foo = 1;\n"
384 " required sfixed32 foo = 1;\n"
385 " required sfixed64 foo = 1;\n"
386 " required float foo = 1;\n"
387 " required double foo = 1;\n"
388 " required string foo = 1;\n"
389 " required bytes foo = 1;\n"
390 " required bool foo = 1;\n"
394 " name: \"TestMessage\""
395 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 "
397 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 "
399 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 "
401 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 "
403 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 "
405 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 "
407 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 "
409 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 "
411 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 "
413 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 "
415 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 "
417 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 "
419 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 "
421 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 "
423 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 "
428 TEST_F(ParseMessageTest, FieldDefaults) {
430 "message TestMessage {\n"
431 " required int32 foo = 1 [default= 1 ];\n"
432 " required int32 foo = 1 [default= -2 ];\n"
433 " required int64 foo = 1 [default= 3 ];\n"
434 " required int64 foo = 1 [default= -4 ];\n"
435 " required uint32 foo = 1 [default= 5 ];\n"
436 " required uint64 foo = 1 [default= 6 ];\n"
437 " required float foo = 1 [default= 7.5];\n"
438 " required float foo = 1 [default= -8.5];\n"
439 " required float foo = 1 [default= 9 ];\n"
440 " required double foo = 1 [default= 10.5];\n"
441 " required double foo = 1 [default=-11.5];\n"
442 " required double foo = 1 [default= 12 ];\n"
443 " required double foo = 1 [default= inf ];\n"
444 " required double foo = 1 [default=-inf ];\n"
445 " required double foo = 1 [default= nan ];\n"
446 " required string foo = 1 [default='13\\001'];\n"
447 " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
448 " required bytes foo = 1 [default='14\\002'];\n"
449 " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
450 " required bool foo = 1 [default=true ];\n"
451 " required Foo foo = 1 [default=FOO ];\n"
453 " required int32 foo = 1 [default= 0x7FFFFFFF];\n"
454 " required int32 foo = 1 [default=-0x80000000];\n"
455 " required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
456 " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
457 " required int64 foo = 1 [default=-0x8000000000000000];\n"
458 " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
459 " required double foo = 1 [default= 0xabcd];\n"
462 #define
ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
464 " name: \"TestMessage\""
465 " field { type:TYPE_INT32 default_value:\"1\" " ETC
467 " field { type:TYPE_INT32 default_value:\"-2\" " ETC
469 " field { type:TYPE_INT64 default_value:\"3\" " ETC
471 " field { type:TYPE_INT64 default_value:\"-4\" " ETC
473 " field { type:TYPE_UINT32 default_value:\"5\" " ETC
475 " field { type:TYPE_UINT64 default_value:\"6\" " ETC
477 " field { type:TYPE_FLOAT default_value:\"7.5\" " ETC
479 " field { type:TYPE_FLOAT default_value:\"-8.5\" " ETC
481 " field { type:TYPE_FLOAT default_value:\"9\" " ETC
483 " field { type:TYPE_DOUBLE default_value:\"10.5\" " ETC
485 " field { type:TYPE_DOUBLE default_value:\"-11.5\" " ETC
487 " field { type:TYPE_DOUBLE default_value:\"12\" " ETC
489 " field { type:TYPE_DOUBLE default_value:\"inf\" " ETC
491 " field { type:TYPE_DOUBLE default_value:\"-inf\" " ETC
493 " field { type:TYPE_DOUBLE default_value:\"nan\" " ETC
495 " field { type:TYPE_STRING default_value:\"13\\001\" " ETC
497 " field { type:TYPE_STRING default_value:\"abc\" " ETC
499 " field { type:TYPE_BYTES default_value:\"14\\\\002\" " ETC
501 " field { type:TYPE_BYTES default_value:\"abc\" " ETC
503 " field { type:TYPE_BOOL default_value:\"true\" " ETC
505 " field { type_name:\"Foo\" default_value:\"FOO\" " ETC
509 " type:TYPE_INT32 default_value:\"2147483647\" " ETC
512 " type:TYPE_INT32 default_value:\"-2147483648\" " ETC
515 " type:TYPE_UINT32 default_value:\"4294967295\" " ETC
518 " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC
521 " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC
524 " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC
527 " type:TYPE_DOUBLE default_value:\"43981\" " ETC
533 TEST_F(ParseMessageTest, FieldJsonName) {
535 "message TestMessage {\n"
536 " optional string foo = 1 [json_name = \"@type\"];\n"
539 " name: \"TestMessage\""
541 " name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
542 " json_name: \"@type\"\n"
549 "message TestMessage {\n"
550 " optional string foo = 1\n"
551 " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
552 " (quux)=\"x\040y\", (baz.qux)=hey];\n"
556 " name: \"TestMessage\""
557 " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: "
559 " options { uninterpreted_option: { name { name_part: \"ctype\" "
560 " is_extension: false "
562 " identifier_value: \"CORD\" "
564 " uninterpreted_option: { name { name_part: \"foo\" "
565 " is_extension: true } "
566 " positive_int_value: 7 }"
567 " uninterpreted_option: { name { name_part: \"foo\" "
568 " is_extension: false "
570 " name { name_part: "
572 " is_extension: true } "
573 " name { name_part: \"qux\" "
574 " is_extension: false "
576 " name { name_part: \"quux\" "
577 " is_extension: false "
579 " name { name_part: \"corge\" "
580 " is_extension: true } "
581 " negative_int_value: -33 }"
582 " uninterpreted_option: { name { name_part: \"quux\" "
583 " is_extension: true } "
584 " string_value: \"x y\" }"
585 " uninterpreted_option: { name { name_part: "
587 " is_extension: true } "
588 " identifier_value: \"hey\" }"
596 "message TestMessage {\n"
600 " TestMessage c = 3;\n"
601 " group D = 4 { optional int32 i = 5; }\n"
606 " name: \"TestMessage\""
607 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
609 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
611 " field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" "
612 " number:3 oneof_index:0 }"
613 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP "
614 " type_name:\"D\" number:4 oneof_index:0 }"
620 " field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }"
625 TEST_F(ParseMessageTest, MultipleOneofs) {
627 "message TestMessage {\n"
639 " name: \"TestMessage\""
640 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
642 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
644 " field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 "
646 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 "
657 TEST_F(ParseMessageTest, Maps) {
659 "message TestMessage {\n"
660 " map<int32, string> primitive_type_map = 1;\n"
661 " map<KeyType, ValueType> composite_type_map = 2;\n"
665 " name: \"TestMessage\""
667 " name: \"PrimitiveTypeMapEntry\""
669 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
673 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
676 " options { map_entry: true }"
679 " name: \"CompositeTypeMapEntry\""
681 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
682 " type_name: \"KeyType\""
685 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
686 " type_name: \"ValueType\""
688 " options { map_entry: true }"
691 " name: \"primitive_type_map\""
692 " label: LABEL_REPEATED"
693 " type_name: \"PrimitiveTypeMapEntry\""
697 " name: \"composite_type_map\""
698 " label: LABEL_REPEATED"
699 " type_name: \"CompositeTypeMapEntry\""
707 "message TestMessage {\n"
708 " optional group TestGroup = 1 {};\n"
712 " name: \"TestMessage\""
713 " nested_type { name: \"TestGroup\" }"
714 " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
715 " type:TYPE_GROUP type_name: \"TestGroup\" }"
719 TEST_F(ParseMessageTest, NestedMessage) {
721 "message TestMessage {\n"
722 " message Nested {}\n"
723 " optional Nested test_nested = 1;\n"
727 " name: \"TestMessage\""
728 " nested_type { name: \"Nested\" }"
729 " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
730 " type_name: \"Nested\" }"
734 TEST_F(ParseMessageTest, NestedEnum) {
736 "message TestMessage {\n"
737 " enum NestedEnum {}\n"
738 " optional NestedEnum test_enum = 1;\n"
742 " name: \"TestMessage\""
743 " enum_type { name: \"NestedEnum\" }"
744 " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
745 " type_name: \"NestedEnum\" }"
749 TEST_F(ParseMessageTest, ReservedRange) {
751 "message TestMessage {\n"
752 " required int32 foo = 1;\n"
753 " reserved 2, 15, 9 to 11, 3, 20 to max;\n"
757 " name: \"TestMessage\""
758 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
759 " reserved_range { start:2 end:3 }"
760 " reserved_range { start:15 end:16 }"
761 " reserved_range { start:9 end:12 }"
762 " reserved_range { start:3 end:4 }"
763 " reserved_range { start:20 end:536870912 }"
767 TEST_F(ParseMessageTest, ReservedRangeOnMessageSet) {
769 "message TestMessage {\n"
770 " option message_set_wire_format = true;\n"
771 " reserved 20 to max;\n"
775 " name: \"TestMessage\""
777 " uninterpreted_option {"
779 " name_part: \"message_set_wire_format\""
780 " is_extension: false"
782 " identifier_value: \"true\""
785 " reserved_range { start:20 end:2147483647 }"
789 TEST_F(ParseMessageTest, ReservedNames) {
791 "message TestMessage {\n"
792 " reserved \"foo\", \"bar\";\n"
796 " name: \"TestMessage\""
797 " reserved_name: \"foo\""
798 " reserved_name: \"bar\""
802 TEST_F(ParseMessageTest, ExtensionRange) {
804 "message TestMessage {\n"
805 " extensions 10 to 19;\n"
806 " extensions 30 to max;\n"
810 " name: \"TestMessage\""
811 " extension_range { start:10 end:20 }"
812 " extension_range { start:30 end:536870912 }"
816 TEST_F(ParseMessageTest, ExtensionRangeWithOptions) {
818 "message TestMessage {\n"
819 " extensions 10 to 19 [(i) = 5];\n"
823 " name: \"TestMessage\""
828 " uninterpreted_option {"
831 " is_extension: true"
833 " positive_int_value: 5"
840 TEST_F(ParseMessageTest, CompoundExtensionRange) {
842 "message TestMessage {\n"
843 " extensions 2, 15, 9 to 11, 100 to max, 3;\n"
847 " name: \"TestMessage\""
848 " extension_range { start:2 end:3 }"
849 " extension_range { start:15 end:16 }"
850 " extension_range { start:9 end:12 }"
851 " extension_range { start:100 end:536870912 }"
852 " extension_range { start:3 end:4 }"
856 TEST_F(ParseMessageTest, CompoundExtensionRangeWithOptions) {
858 "message TestMessage {\n"
859 " extensions 2, 15, 9 to 11, 100 to max, 3 [(i) = 5];\n"
863 " name: \"TestMessage\""
868 " uninterpreted_option {"
871 " is_extension: true"
873 " positive_int_value: 5"
881 " uninterpreted_option {"
884 " is_extension: true"
886 " positive_int_value: 5"
894 " uninterpreted_option {"
897 " is_extension: true"
899 " positive_int_value: 5"
907 " uninterpreted_option {"
910 " is_extension: true"
912 " positive_int_value: 5"
920 " uninterpreted_option {"
923 " is_extension: true"
925 " positive_int_value: 5"
932 TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
937 "message TestMessage {\n"
938 " extensions 4 to max;\n"
939 " option message_set_wire_format = true;\n"
943 " name: \"TestMessage\""
944 " extension_range { start:4 end: 0x7fffffff }"
946 " uninterpreted_option { \n"
948 " name_part: \"message_set_wire_format\"\n"
949 " is_extension: false\n"
951 " identifier_value: \"true\"\n"
959 "extend Extendee1 { optional int32 foo = 12; }\n"
960 "extend Extendee2 { repeated TestMessage bar = 22; }\n",
962 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
963 " extendee: \"Extendee1\" } "
964 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
965 " type_name:\"TestMessage\" extendee: \"Extendee2\" }");
968 TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
970 "message TestMessage {\n"
971 " extend Extendee1 { optional int32 foo = 12; }\n"
972 " extend Extendee2 { repeated TestMessage bar = 22; }\n"
976 " name: \"TestMessage\""
977 " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 "
979 " extendee: \"Extendee1\" }"
980 " extension { name:\"bar\" label:LABEL_REPEATED number:22"
981 " type_name:\"TestMessage\" extendee: \"Extendee2\" }"
985 TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
987 "extend Extendee1 {\n"
988 " optional int32 foo = 12;\n"
989 " repeated TestMessage bar = 22;\n"
992 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
993 " extendee: \"Extendee1\" } "
994 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
995 " type_name:\"TestMessage\" extendee: \"Extendee1\" }");
998 TEST_F(ParseMessageTest, OptionalLabelProto3) {
1000 "syntax = \"proto3\";\n"
1001 "message TestMessage {\n"
1005 "syntax: \"proto3\" "
1007 " name: \"TestMessage\""
1008 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } "
1012 TEST_F(ParseMessageTest, ExplicitOptionalLabelProto3) {
1014 "syntax = 'proto3';\n"
1015 "message TestMessage {\n"
1016 " optional int32 foo = 1;\n"
1019 "syntax: \"proto3\" "
1021 " name: \"TestMessage\""
1022 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
1023 " proto3_optional: true oneof_index: 0 } "
1024 " oneof_decl { name:\"_foo\" } "
1029 "syntax = 'proto3';\n"
1030 "message TestMessage {\n"
1031 " optional int32 foo = 1;\n"
1033 " int32 __foo = 2;\n"
1037 "syntax: \"proto3\" "
1039 " name: \"TestMessage\""
1040 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
1041 " proto3_optional: true oneof_index: 1 } "
1042 " field { name:\"__foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 "
1043 " oneof_index: 0 } "
1044 " oneof_decl { name:\"_foo\" } "
1045 " oneof_decl { name:\"X_foo\" } "
1051 typedef ParserTest ParseEnumTest;
1053 TEST_F(ParseEnumTest, SimpleEnum) {
1060 " name: \"TestEnum\""
1061 " value { name:\"FOO\" number:0 }"
1071 " HEX_MAX = 0x7FFFFFFF;\n"
1072 " HEX_MIN = -0x80000000;\n"
1073 " INT_MAX = 2147483647;\n"
1074 " INT_MIN = -2147483648;\n"
1078 " name: \"TestEnum\""
1079 " value { name:\"FOO\" number:13 }"
1080 " value { name:\"BAR\" number:-10 }"
1081 " value { name:\"BAZ\" number:500 }"
1082 " value { name:\"HEX_MAX\" number:2147483647 }"
1083 " value { name:\"HEX_MIN\" number:-2147483648 }"
1084 " value { name:\"INT_MAX\" number:2147483647 }"
1085 " value { name:\"INT_MIN\" number:-2147483648 }"
1089 TEST_F(ParseEnumTest, ValueOptions) {
1093 " BAR = -10 [ (something.text) = 'abc' ];\n"
1094 " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
1098 " name: \"TestEnum\""
1099 " value { name: \"FOO\" number: 13 }"
1100 " value { name: \"BAR\" number: -10 "
1102 " uninterpreted_option { "
1103 " name { name_part: \"something.text\" is_extension: true } "
1104 " string_value: \"abc\" "
1108 " value { name: \"BAZ\" number: 500 "
1110 " uninterpreted_option { "
1111 " name { name_part: \"something.text\" is_extension: true } "
1112 " string_value: \"def\" "
1114 " uninterpreted_option { "
1115 " name { name_part: \"other\" is_extension: false } "
1116 " positive_int_value: 1 "
1123 TEST_F(ParseEnumTest, ReservedRange) {
1127 " reserved -2147483648, -6 to -4, -1 to 1, 2, 15, 9 to 11, 3, 20 to "
1132 " name: \"TestEnum\""
1133 " value { name:\"FOO\" number:0 }"
1134 " reserved_range { start:-2147483648 end:-2147483648 }"
1135 " reserved_range { start:-6 end:-4 }"
1136 " reserved_range { start:-1 end:1 }"
1137 " reserved_range { start:2 end:2 }"
1138 " reserved_range { start:15 end:15 }"
1139 " reserved_range { start:9 end:11 }"
1140 " reserved_range { start:3 end:3 }"
1141 " reserved_range { start:20 end:2147483647 }"
1145 TEST_F(ParseEnumTest, ReservedNames) {
1149 " reserved \"foo\", \"bar\";\n"
1153 " name: \"TestEnum\""
1154 " value { name:\"FOO\" number:0 }"
1155 " reserved_name: \"foo\""
1156 " reserved_name: \"bar\""
1162 typedef ParserTest ParseServiceTest;
1164 TEST_F(ParseServiceTest, SimpleService) {
1166 "service TestService {\n"
1167 " rpc Foo(In) returns (Out);\n"
1171 " name: \"TestService\""
1172 " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
1176 TEST_F(ParseServiceTest, MethodsAndStreams) {
1178 "service TestService {\n"
1179 " rpc Foo(In1) returns (Out1);\n"
1180 " rpc Bar(In2) returns (Out2);\n"
1181 " rpc Baz(In3) returns (Out3);\n"
1185 " name: \"TestService\""
1186 " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
1187 " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
1188 " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
1196 typedef ParserTest ParseMiscTest;
1198 TEST_F(ParseMiscTest, ParseImport) {
1199 ExpectParsesTo(
"import \"foo/bar/baz.proto\";\n",
1200 "dependency: \"foo/bar/baz.proto\"");
1203 TEST_F(ParseMiscTest, ParseMultipleImports) {
1205 "import \"foo.proto\";\n"
1206 "import \"bar.proto\";\n"
1207 "import \"baz.proto\";\n",
1208 "dependency: \"foo.proto\""
1209 "dependency: \"bar.proto\""
1210 "dependency: \"baz.proto\"");
1213 TEST_F(ParseMiscTest, ParsePublicImports) {
1215 "import \"foo.proto\";\n"
1216 "import public \"bar.proto\";\n"
1217 "import \"baz.proto\";\n"
1218 "import public \"qux.proto\";\n",
1219 "dependency: \"foo.proto\""
1220 "dependency: \"bar.proto\""
1221 "dependency: \"baz.proto\""
1222 "dependency: \"qux.proto\""
1223 "public_dependency: 1 "
1224 "public_dependency: 3 ");
1227 TEST_F(ParseMiscTest, ParsePackage) {
1228 ExpectParsesTo(
"package foo.bar.baz;\n",
"package: \"foo.bar.baz\"");
1231 TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
1233 "package foo . bar. \n"
1235 "package: \"foo.bar.baz\"");
1241 TEST_F(ParseMiscTest, ParseFileOptions) {
1243 "option java_package = \"com.google.foo\";\n"
1244 "option optimize_for = CODE_SIZE;",
1247 "uninterpreted_option { name { name_part: \"java_package\" "
1248 " is_extension: false }"
1249 " string_value: \"com.google.foo\"} "
1250 "uninterpreted_option { name { name_part: \"optimize_for\" "
1251 " is_extension: false }"
1252 " identifier_value: \"CODE_SIZE\" } "
1266 typedef ParserTest ParseErrorTest;
1268 TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
1270 ExpectHasEarlyExitErrors(
"message TestMessage {}",
1271 "0:0: File must begin with a syntax statement, e.g. "
1272 "'syntax = \"proto2\";'.\n");
1276 TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
1277 ExpectHasEarlyExitErrors(
1278 "syntax = \"no_such_syntax\";",
1279 "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
1280 "only recognizes \"proto2\" and \"proto3\".\n");
1284 TEST_F(ParseErrorTest, SimpleSyntaxError) {
1285 ExpectHasErrors(
"message TestMessage @#$ { blah }",
1286 "0:20: Expected \"{\".\n");
1290 TEST_F(ParseErrorTest, ExpectedTopLevel) {
1291 ExpectHasErrors(
"blah;",
1292 "0:0: Expected top-level statement (e.g. \"message\").\n");
1295 TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
1297 ExpectHasErrors(
"}",
1298 "0:0: Expected top-level statement (e.g. \"message\").\n"
1299 "0:0: Unmatched \"}\".\n");
1305 TEST_F(ParseErrorTest, MessageMissingName) {
1306 ExpectHasErrors(
"message {}",
"0:8: Expected message name.\n");
1309 TEST_F(ParseErrorTest, MessageMissingBody) {
1310 ExpectHasErrors(
"message TestMessage;",
"0:19: Expected \"{\".\n");
1313 TEST_F(ParseErrorTest, EofInMessage) {
1315 "message TestMessage {",
1316 "0:21: Reached end of input in message definition (missing '}').\n");
1319 TEST_F(ParseErrorTest, MissingFieldNumber) {
1321 "message TestMessage {\n"
1322 " optional int32 foo;\n"
1324 "1:20: Missing field number.\n");
1327 TEST_F(ParseErrorTest, ExpectedFieldNumber) {
1329 "message TestMessage {\n"
1330 " optional int32 foo = ;\n"
1332 "1:23: Expected field number.\n");
1335 TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
1337 "message TestMessage {\n"
1338 " optional int32 foo = 0x100000000;\n"
1340 "1:23: Integer out of range.\n");
1343 TEST_F(ParseErrorTest, MissingLabel) {
1345 "message TestMessage {\n"
1348 "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
1351 TEST_F(ParseErrorTest, ExpectedOptionName) {
1353 "message TestMessage {\n"
1354 " optional uint32 foo = 1 [];\n"
1356 "1:27: Expected identifier.\n");
1359 TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
1361 "message TestMessage {\n"
1362 " optional uint32 foo = 1 [.foo=1];\n"
1364 "1:27: Expected identifier.\n");
1367 TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
1369 "message TestMessage {\n"
1370 " optional uint32 foo = 1 [default=true];\n"
1372 "1:35: Expected integer for field default value.\n");
1375 TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
1377 "message TestMessage {\n"
1378 " optional bool foo = 1 [default=blah];\n"
1380 "1:33: Expected \"true\" or \"false\".\n");
1383 TEST_F(ParseErrorTest, DefaultValueNotString) {
1385 "message TestMessage {\n"
1386 " optional string foo = 1 [default=1];\n"
1388 "1:35: Expected string for field default value.\n");
1391 TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
1393 "message TestMessage {\n"
1394 " optional uint32 foo = 1 [default=-1];\n"
1396 "1:36: Unsigned field can't have negative default value.\n");
1399 TEST_F(ParseErrorTest, DefaultValueTooLarge) {
1401 "message TestMessage {\n"
1402 " optional int32 foo = 1 [default= 0x80000000];\n"
1403 " optional int32 foo = 1 [default=-0x80000001];\n"
1404 " optional uint32 foo = 1 [default= 0x100000000];\n"
1405 " optional int64 foo = 1 [default= 0x80000000000000000];\n"
1406 " optional int64 foo = 1 [default=-0x80000000000000001];\n"
1407 " optional uint64 foo = 1 [default= 0x100000000000000000];\n"
1409 "1:36: Integer out of range.\n"
1410 "2:36: Integer out of range.\n"
1411 "3:36: Integer out of range.\n"
1412 "4:36: Integer out of range.\n"
1413 "5:36: Integer out of range.\n"
1414 "6:36: Integer out of range.\n");
1417 TEST_F(ParseErrorTest, JsonNameNotString) {
1419 "message TestMessage {\n"
1420 " optional string foo = 1 [json_name=1];\n"
1422 "1:37: Expected string for JSON name.\n");
1425 TEST_F(ParseErrorTest, DuplicateJsonName) {
1427 "message TestMessage {\n"
1428 " optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
1430 "1:41: Already set option \"json_name\".\n");
1433 TEST_F(ParseErrorTest, EnumValueOutOfRange) {
1436 " HEX_TOO_BIG = 0x80000000;\n"
1437 " HEX_TOO_SMALL = -0x80000001;\n"
1438 " INT_TOO_BIG = 2147483648;\n"
1439 " INT_TOO_SMALL = -2147483649;\n"
1441 "1:19: Integer out of range.\n"
1442 "2:19: Integer out of range.\n"
1443 "3:19: Integer out of range.\n"
1444 "4:19: Integer out of range.\n");
1447 TEST_F(ParseErrorTest, EnumAllowAliasFalse) {
1450 " option allow_alias = false;\n"
1454 "5:0: \"Foo\" declares 'option allow_alias = false;' which has no "
1456 "Please remove the declaration.\n");
1459 TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) {
1462 " option allow_alias = true;\n"
1466 "5:0: \"Foo\" declares support for enum aliases but no enum values share "
1467 "field numbers. Please remove the unnecessary 'option allow_alias = "
1472 TEST_F(ParseErrorTest, DefaultValueMissing) {
1474 "message TestMessage {\n"
1475 " optional uint32 foo = 1 [default=];\n"
1477 "1:35: Expected integer for field default value.\n");
1480 TEST_F(ParseErrorTest, DefaultValueForGroup) {
1482 "message TestMessage {\n"
1483 " optional group Foo = 1 [default=blah] {}\n"
1485 "1:34: Messages can't have default values.\n");
1488 TEST_F(ParseErrorTest, DuplicateDefaultValue) {
1490 "message TestMessage {\n"
1491 " optional uint32 foo = 1 [default=1,default=2];\n"
1493 "1:37: Already set option \"default\".\n");
1496 TEST_F(ParseErrorTest, MissingOneofName) {
1498 "message TestMessage {\n"
1503 "1:8: Expected oneof name.\n");
1506 TEST_F(ParseErrorTest, LabelInOneof) {
1508 "message TestMessage {\n"
1510 " optional int32 bar = 1;\n"
1513 "2:4: Fields in oneofs must not have labels (required / optional "
1517 TEST_F(ParseErrorTest, MapInOneof) {
1519 "message TestMessage {\n"
1521 " map<int32, int32> foo_map = 1;\n"
1522 " map message_field = 2;\n"
1525 "2:7: Map fields are not allowed in oneofs.\n");
1528 TEST_F(ParseErrorTest, LabelForMap) {
1530 "message TestMessage {\n"
1531 " optional map<int32, int32> int_map = 1;\n"
1532 " required map<int32, int32> int_map2 = 2;\n"
1533 " repeated map<int32, int32> int_map3 = 3;\n"
1534 " optional map map_message = 4;\n"
1536 "1:14: Field labels (required/optional/repeated) are not allowed on map "
1538 "2:14: Field labels (required/optional/repeated) are not allowed on map "
1540 "3:14: Field labels (required/optional/repeated) are not allowed on map "
1544 TEST_F(ParseErrorTest, MalformedMaps) {
1546 "message TestMessage {\n"
1547 " map map_message = 1;\n"
1548 " map<string> str_map = 2;\n"
1549 " map<string,> str_map2 = 3;\n"
1550 " map<,string> str_map3 = 4;\n"
1551 " map<> empty_map = 5;\n"
1552 " map<string,string str_map6 = 6;\n"
1554 "extend SomeMessage {\n"
1555 " map<int32, int32> int_map = 1;\n"
1557 "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
1558 "2:12: Expected \",\".\n"
1559 "3:13: Expected type name.\n"
1560 "4:6: Expected type name.\n"
1561 "5:6: Expected type name.\n"
1562 "6:20: Expected \">\".\n"
1563 "8:5: Map fields are not allowed to be extensions.\n");
1566 TEST_F(ParseErrorTest, GroupNotCapitalized) {
1568 "message TestMessage {\n"
1569 " optional group foo = 1 {}\n"
1571 "1:17: Group names must start with a capital letter.\n");
1574 TEST_F(ParseErrorTest, GroupMissingBody) {
1576 "message TestMessage {\n"
1577 " optional group Foo = 1;\n"
1579 "1:24: Missing group body.\n");
1582 TEST_F(ParseErrorTest, ExtendingPrimitive) {
1583 ExpectHasErrors(
"extend int32 { optional string foo = 4; }\n",
1584 "0:7: Expected message type.\n");
1587 TEST_F(ParseErrorTest, ErrorInExtension) {
1589 "message Foo { extensions 100 to 199; }\n"
1590 "extend Foo { optional string foo; }\n",
1591 "1:32: Missing field number.\n");
1594 TEST_F(ParseErrorTest, MultipleParseErrors) {
1598 "message TestMessage {\n"
1599 " optional int32 foo;\n"
1600 " !invalid statement ending in a block { blah blah { blah } blah }\n"
1601 " optional int32 bar = 3 {}\n"
1603 "1:20: Missing field number.\n"
1604 "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
1605 "2:2: Expected type name.\n"
1606 "3:25: Expected \";\".\n");
1609 TEST_F(ParseErrorTest, EofInAggregateValue) {
1611 "option (fileopt) = { i:100\n",
1612 "1:0: Unexpected end of stream while parsing aggregate value.\n");
1618 TEST_F(ParseErrorTest, EofInEnum) {
1621 "0:15: Reached end of input in enum definition (missing '}').\n");
1624 TEST_F(ParseErrorTest, EnumValueMissingNumber) {
1629 "1:5: Missing numeric value for enum constant.\n");
1632 TEST_F(ParseErrorTest, EnumReservedStandaloneMaxNotAllowed) {
1638 "2:11: Expected enum value or number range.\n");
1641 TEST_F(ParseErrorTest, EnumReservedMixNameAndNumber) {
1645 " reserved 10, \"foo\";\n"
1647 "2:15: Expected enum number range.\n");
1650 TEST_F(ParseErrorTest, EnumReservedPositiveNumberOutOfRange) {
1654 " reserved 2147483648;\n"
1656 "2:11: Integer out of range.\n");
1659 TEST_F(ParseErrorTest, EnumReservedNegativeNumberOutOfRange) {
1663 " reserved -2147483649;\n"
1665 "2:12: Integer out of range.\n");
1668 TEST_F(ParseErrorTest, EnumReservedMissingQuotes) {
1674 "2:11: Expected enum value or number range.\n");
1680 TEST_F(ParseErrorTest, ReservedStandaloneMaxNotAllowed) {
1685 "1:11: Expected field name or number range.\n");
1688 TEST_F(ParseErrorTest, ReservedMixNameAndNumber) {
1691 " reserved 10, \"foo\";\n"
1693 "1:15: Expected field number range.\n");
1696 TEST_F(ParseErrorTest, ReservedMissingQuotes) {
1701 "1:11: Expected field name or number range.\n");
1704 TEST_F(ParseErrorTest, ReservedNegativeNumber) {
1709 "1:11: Expected field name or number range.\n");
1712 TEST_F(ParseErrorTest, ReservedNumberOutOfRange) {
1715 " reserved 2147483648;\n"
1717 "1:11: Integer out of range.\n");
1723 TEST_F(ParseErrorTest, EofInService) {
1725 "service TestService {",
1726 "0:21: Reached end of input in service definition (missing '}').\n");
1729 TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
1731 "service TestService {\n"
1732 " rpc Foo(int32) returns (string);\n"
1734 "1:10: Expected message type.\n"
1735 "1:26: Expected message type.\n");
1739 TEST_F(ParseErrorTest, EofInMethodOptions) {
1741 "service TestService {\n"
1742 " rpc Foo(Bar) returns(Bar) {",
1743 "1:29: Reached end of input in method options (missing '}').\n"
1744 "1:29: Reached end of input in service definition (missing '}').\n");
1748 TEST_F(ParseErrorTest, PrimitiveMethodInput) {
1750 "service TestService {\n"
1751 " rpc Foo(int32) returns(Bar);\n"
1753 "1:10: Expected message type.\n");
1757 TEST_F(ParseErrorTest, MethodOptionTypeError) {
1762 " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
1764 "2:45: Expected \"=\".\n");
1771 TEST_F(ParseErrorTest, ImportNotQuoted) {
1772 ExpectHasErrors(
"import foo;\n",
1773 "0:7: Expected a string naming the file to import.\n");
1776 TEST_F(ParseErrorTest, MultiplePackagesInFile) {
1780 "1:0: Multiple package definitions.\n");
1788 typedef ParserTest ParserValidationErrorTest;
1790 TEST_F(ParserValidationErrorTest, PackageNameError) {
1798 ExpectHasValidationErrors(
1800 "0:0: \"foo\" is already defined (as something other than a package) "
1801 "in file \"bar.proto\".\n");
1804 TEST_F(ParserValidationErrorTest, ImportUnloadedError) {
1805 ExpectHasValidationErrors(
1808 "import \"unloaded.proto\";",
1809 "2:0: Import \"unloaded.proto\" has not been loaded.\n");
1812 TEST_F(ParserValidationErrorTest, ImportTwice) {
1818 ExpectHasValidationErrors(
1821 "import \"bar.proto\";\n"
1822 " import \"bar.proto\";",
1823 "3:2: Import \"bar.proto\" was listed twice.\n");
1826 TEST_F(ParserValidationErrorTest, DuplicateFileError) {
1831 ExpectHasValidationErrors(
1832 "package test;",
"0:0: A file with this name is already in the pool.\n");
1835 TEST_F(ParserValidationErrorTest, MessageNameError) {
1836 ExpectHasValidationErrors(
1839 "1:8: \"Foo\" is already defined.\n");
1842 TEST_F(ParserValidationErrorTest, FieldNameError) {
1843 ExpectHasValidationErrors(
1845 " optional int32 bar = 1;\n"
1846 " optional int32 bar = 2;\n"
1848 "2:17: \"bar\" is already defined in \"Foo\".\n");
1851 TEST_F(ParserValidationErrorTest, FieldTypeError) {
1852 ExpectHasValidationErrors(
1854 " optional Baz bar = 1;\n"
1856 "1:11: \"Baz\" is not defined.\n");
1859 TEST_F(ParserValidationErrorTest, FieldNumberError) {
1860 ExpectHasValidationErrors(
1862 " optional int32 bar = 0;\n"
1864 "1:23: Field numbers must be positive integers.\n");
1867 TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
1868 ExpectHasValidationErrors(
"extend Baz { optional int32 bar = 1; }\n",
1869 "0:7: \"Baz\" is not defined.\n");
1872 TEST_F(ParserValidationErrorTest, ExtensionJsonNameError) {
1873 ExpectHasValidationErrors(
1874 "message TestMessage {\n"
1875 " extensions 1 to 100;\n"
1877 "extend TestMessage {\n"
1878 " optional int32 foo = 12 [json_name = \"bar\"];\n"
1880 "4:27: option json_name is not allowed on extension fields.\n");
1883 TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
1884 ExpectHasValidationErrors(
1885 "enum Baz { QUX = 1; }\n"
1887 " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
1889 "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
1892 TEST_F(ParserValidationErrorTest, FileOptionNameError) {
1893 ExpectHasValidationErrors(
1895 "0:7: Option \"foo\" unknown. Ensure that your proto definition file "
1896 "imports the proto which defines the option.\n");
1899 TEST_F(ParserValidationErrorTest, FileOptionValueError) {
1900 ExpectHasValidationErrors(
1901 "option java_outer_classname = 5;",
1902 "0:30: Value must be quoted string for string option "
1903 "\"google.protobuf.FileOptions.java_outer_classname\".\n");
1906 TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
1907 ExpectHasValidationErrors(
1909 " optional bool bar = 1 [foo=1];\n"
1911 "1:25: Option \"foo\" unknown. Ensure that your proto definition file "
1912 "imports the proto which defines the option.\n");
1915 TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
1916 ExpectHasValidationErrors(
1918 " optional int32 bar = 1 [ctype=1];\n"
1920 "1:32: Value must be identifier for enum-valued option "
1921 "\"google.protobuf.FieldOptions.ctype\".\n");
1924 TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
1925 ExpectHasValidationErrors(
1929 "1:13: Extension numbers must be positive integers.\n");
1932 TEST_F(ParserValidationErrorTest, Proto3ExtensionError) {
1933 ExpectHasValidationErrors(
1934 "syntax = 'proto3';\n"
1936 " extensions 100 to 199;\n"
1938 "extend Foo { string foo = 101; }\n",
1939 "4:7: Extensions in proto3 are only allowed for defining options.\n"
1940 "2:13: Extension ranges are not allowed in proto3.\n");
1943 TEST_F(ParserValidationErrorTest, Proto3MessageSet) {
1944 ExpectHasValidationErrors(
1945 "syntax = 'proto3';\n"
1947 " option message_set_wire_format = true;\n"
1949 "1:8: MessageSet is not supported in proto3.\n");
1952 TEST_F(ParserValidationErrorTest, Proto3Required) {
1953 ExpectHasValidationErrors(
1954 "syntax = 'proto3';\n"
1956 " required int32 field = 1;"
1958 "2:11: Required fields are not allowed in proto3.\n");
1961 TEST_F(ParserValidationErrorTest, Proto3Default) {
1962 ExpectHasValidationErrors(
1963 "syntax = 'proto3';\n"
1965 " int32 field = 1 [default = 12];"
1967 "2:29: Explicit default values are not allowed in proto3.\n");
1970 TEST_F(ParserValidationErrorTest, Proto3JsonConflictError) {
1971 ExpectHasValidationErrors(
1972 "syntax = 'proto3';\n"
1973 "message TestMessage {\n"
1974 " uint32 foo = 1;\n"
1975 " uint32 Foo = 2;\n"
1977 "3:9: The JSON camel-case name of field \"Foo\" conflicts with field "
1978 "\"foo\". This is not allowed in proto3.\n");
1981 TEST_F(ParserValidationErrorTest, EnumNameError) {
1982 ExpectHasValidationErrors(
1983 "enum Foo {A = 1;}\n"
1984 "enum Foo {B = 1;}\n",
1985 "1:5: \"Foo\" is already defined.\n");
1988 TEST_F(ParserValidationErrorTest, Proto3EnumError) {
1989 ExpectHasValidationErrors(
1990 "syntax = 'proto3';\n"
1991 "enum Foo {A = 1;}\n",
1992 "1:14: The first enum value must be zero in proto3.\n");
1995 TEST_F(ParserValidationErrorTest, EnumValueNameError) {
1996 ExpectHasValidationErrors(
2001 "2:2: \"BAR\" is already defined.\n");
2004 TEST_F(ParserValidationErrorTest, EnumValueAliasError) {
2005 ExpectHasValidationErrors(
2010 "2:8: \"BAZ\" uses the same enum value as \"BAR\". If this is "
2011 "intended, set 'option allow_alias = true;' to the enum "
2015 TEST_F(ParserValidationErrorTest, ExplicitlyMapEntryError) {
2016 ExpectHasValidationErrors(
2018 " message ValueEntry {\n"
2019 " option map_entry = true;\n"
2020 " optional int32 key = 1;\n"
2021 " optional int32 value = 2;\n"
2022 " extensions 99 to 999;\n"
2024 " repeated ValueEntry value = 1;\n"
2026 "7:11: map_entry should not be set explicitly. Use "
2027 "map<KeyType, ValueType> instead.\n");
2030 TEST_F(ParserValidationErrorTest, ServiceNameError) {
2031 ExpectHasValidationErrors(
2034 "1:8: \"Foo\" is already defined.\n");
2037 TEST_F(ParserValidationErrorTest, MethodNameError) {
2038 ExpectHasValidationErrors(
2041 " rpc Bar(Baz) returns(Baz);\n"
2042 " rpc Bar(Baz) returns(Baz);\n"
2044 "3:6: \"Bar\" is already defined in \"Foo\".\n");
2048 TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
2049 ExpectHasValidationErrors(
2052 " rpc Bar(Qux) returns(Baz);\n"
2054 "2:10: \"Qux\" is not defined.\n");
2058 TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
2059 ExpectHasValidationErrors(
2062 " rpc Bar(Baz) returns(Qux);\n"
2064 "2:23: \"Qux\" is not defined.\n");
2068 TEST_F(ParserValidationErrorTest, ResolvedUndefinedError) {
2078 ExpectHasValidationErrors(
2079 "package foo.base;\n"
2080 "import \"base.proto\";\n"
2082 " optional base.bar baz = 1;\n"
2083 " optional .base.bar quz = 2;\n"
2085 "3:11: \"base.bar\" is resolved to \"foo.base.bar\","
2086 " which is not defined. The innermost scope is searched first "
2087 "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")"
2088 " to start from the outermost scope.\n");
2091 TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) {
2103 other_file.
set_name(
"base2.proto");
2111 field->set_name(
"foo");
2112 field->set_number(1);
2122 extension->set_extendee(
"google.protobuf.FileOptions");
2133 ExpectHasValidationErrors(
2134 "package qux.baz;\n"
2135 "import \"base2.proto\";\n"
2136 "option (baz.bar).foo = 1;\n",
2137 "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\","
2138 " which is not defined. The innermost scope is searched first "
2139 "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")"
2140 " to start from the outermost scope.\n");
2149 typedef ParserTest ParseDescriptorDebugTest;
2151 class CompareDescriptorNames {
2155 return left->
name() < right->
name();
2163 for (
int i = 0;
i <
size; ++
i) {
2168 std::sort(
data,
data +
size, CompareDescriptorNames());
2175 for (
int i = 0;
i <
size; ++
i) {
2180 std::sort(
data,
data +
size, CompareDescriptorNames());
2187 std::string::size_type
pos =
type_name.find_last_of(
'.');
2188 if (
pos != std::string::npos) {
2204 TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) {
2208 original_file->CopyTo(&expected);
2212 std::string debug_string = original_file->DebugString();
2215 SetupParser(debug_string.c_str());
2230 public_import->CopyTo(&public_import_proto);
2235 import->CopyTo(&import_proto);
2239 ASSERT_TRUE(actual != NULL) <<
"Failed to validate:\n" << debug_string;
2240 actual->CopyTo(&parsed);
2246 SortMessages(&expected);
2247 SortMessages(&parsed);
2252 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
2255 TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
2259 original_file->CopyTo(&expected);
2261 std::string debug_string = original_file->DebugString();
2264 SetupParser(debug_string.c_str());
2273 parsed.
set_name(original_file->name());
2278 import->CopyTo(&import_proto);
2288 actual->CopyTo(&parsed);
2293 SortMessages(&expected);
2294 SortMessages(&parsed);
2296 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
2302 TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
2304 "// Detached comment before syntax.\n"
2306 "// Syntax comment.\n"
2307 "syntax = \"proto2\";\n"
2309 "// Detached comment before package.\n"
2311 "// Package comment.\n"
2312 "package comment_test;\n"
2314 "// Detached comment before TestMessage1.\n"
2316 "// Message comment.\n"
2318 "// More detail in message comment.\n"
2319 "message TestMessage1 {\n"
2321 " // Detached comment before foo.\n"
2323 " // Field comment.\n"
2324 " optional int32 foo = 1;\n"
2326 " // Detached comment before NestedMessage.\n"
2328 " // Nested-message comment.\n"
2329 " message NestedMessage {\n"
2330 " optional int32 bar = 1;\n"
2334 "// Detached comment before MyEnumType.\n"
2336 "// Enum comment.\n"
2337 "enum MyEnumType {\n"
2339 " // Detached comment before ASDF.\n"
2341 " // Enum-value comment.\n"
2345 "// Detached comment before MyService.\n"
2347 "// Service comment.\n"
2348 "service MyService {\n"
2350 " // Detached comment before MyRPCCall.\n"
2352 " // RPC comment.\n"
2353 " rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
2358 SourceLocationTable source_locations;
2359 parser_->RecordSourceLocationsTo(&source_locations);
2365 MockValidationErrorCollector collector(source_locations, &
error_collector_);
2367 pool_.BuildFileCollectingErrors(parsed_desc, &collector);
2373 const char* expected_comments[] = {
2374 "Detached comment before syntax.",
2376 "Detached comment before package.",
2378 "Detached comment before TestMessage1.",
2380 "More detail in message comment.",
2381 "Detached comment before foo.",
2383 "Detached comment before NestedMessage.",
2384 "Nested-message comment",
2385 "Detached comment before MyEnumType.",
2387 "Detached comment before ASDF.",
2388 "Enum-value comment",
2389 "Detached comment before MyService.",
2391 "Detached comment before MyRPCCall.",
2395 DebugStringOptions debug_string_options;
2396 debug_string_options.include_comments =
true;
2400 descriptor->DebugStringWithOptions(debug_string_options);
2403 std::string::size_type found_pos =
2404 debug_string.find(expected_comments[i]);
2406 <<
"\"" << expected_comments[
i] <<
"\" not found.";
2410 SetupParser(debug_string.c_str());
2420 TEST_F(ParseDescriptorDebugTest, TestMaps) {
2422 "syntax = \"proto3\"; "
2425 " map<int32, Bar> enum_message_map = 1; "
2426 " map<string, float> primitive_map = 2; "
2437 EXPECT_TRUE(debug_string.find(
"map<") != std::string::npos);
2438 EXPECT_TRUE(debug_string.find(
"option map_entry") == std::string::npos);
2439 EXPECT_TRUE(debug_string.find(
"MapEntry") == std::string::npos);
2443 SetupParser(debug_string.c_str());
2449 StripFieldTypeName(&original);
2450 StripFieldTypeName(&parsed);
2451 EXPECT_EQ(original.DebugString(), parsed.DebugString());
2469 bool FollowPath(
const Message&
root,
const int* path_begin,
const int* path_end,
2470 const Message** output_message,
2472 if (path_begin == path_end) {
2474 *output_message = &
root;
2475 *output_field = NULL;
2481 const Reflection* reflection =
root.GetReflection();
2485 if (
field == NULL) {
2487 <<
" has no field number: " << *path_begin;
2493 if (
field->is_repeated()) {
2494 if (path_begin == path_end) {
2496 *output_message = &
root;
2497 *output_field =
field;
2502 int index = *path_begin++;
2507 <<
" has size " <<
size
2508 <<
", but path contained index: " <<
index;
2515 return FollowPath(
child, path_begin, path_end, output_message,
2516 output_field, output_index);
2517 }
else if (path_begin == path_end) {
2519 *output_message = &
root;
2520 *output_field =
field;
2521 *output_index =
index;
2525 <<
" is not a message; cannot descend into it.";
2531 return FollowPath(
child, path_begin, path_end, output_message,
2532 output_field, output_index);
2533 }
else if (path_begin == path_end) {
2535 *output_message = &
root;
2536 *output_field =
field;
2541 <<
" is not a message; cannot descend into it.";
2550 if (span1.
size() != span2.
size())
return false;
2551 for (
int i = 0;
i < span1.
size();
i++) {
2552 if (span1.Get(i) != span2.Get(i))
return false;
2559 class SourceInfoTest :
public ParserTest {
2567 ExtractMarkers(
text);
2579 if (!FollowPath(
file_, location.
path().begin(), location.
path().end(),
2591 void TearDown()
override {
2593 <<
spans_.begin()->second->DebugString();
2602 bool HasSpan(
char start_marker,
char end_marker,
2604 return HasSpanWithComment(start_marker, end_marker,
descriptor_proto, NULL,
2605 -1, NULL, NULL, NULL);
2608 bool HasSpanWithComment(
char start_marker,
char end_marker,
2610 const char* expected_leading_comments,
2611 const char* expected_trailing_comments,
2612 const char* expected_leading_detached_comments) {
2613 return HasSpanWithComment(start_marker, end_marker,
descriptor_proto, NULL,
2614 -1, expected_leading_comments,
2615 expected_trailing_comments,
2616 expected_leading_detached_comments);
2619 bool HasSpan(
char start_marker,
char end_marker,
2621 return HasSpan(start_marker, end_marker,
descriptor_proto, field_name, -1);
2624 bool HasSpan(
char start_marker,
char end_marker,
2628 index, NULL, NULL, NULL);
2631 bool HasSpan(
char start_marker,
char end_marker,
2633 int index,
const char* expected_leading_comments,
2634 const char* expected_trailing_comments,
2635 const char* expected_leading_detached_comments) {
2638 if (
field == NULL) {
2640 <<
" has no such field: " << field_name;
2645 index, expected_leading_comments,
2646 expected_trailing_comments,
2647 expected_leading_detached_comments);
2659 bool HasSpanWithComment(
char start_marker,
char end_marker,
2662 const char* expected_leading_comments,
2663 const char* expected_trailing_comments,
2664 const char* expected_leading_detached_comments) {
2665 std::pair<SpanMap::iterator, SpanMap::iterator>
range =
2668 if (start_marker ==
'\0') {
2680 expected_span.Add(start_pos.first);
2681 expected_span.Add(start_pos.second);
2682 if (end_pos.first != start_pos.first) {
2683 expected_span.Add(end_pos.first);
2685 expected_span.Add(end_pos.second);
2688 if (CompareSpans(expected_span,
iter->second->span())) {
2689 if (expected_leading_comments == NULL) {
2694 iter->second->leading_comments());
2696 if (expected_trailing_comments == NULL) {
2701 iter->second->trailing_comments());
2703 if (expected_leading_detached_comments == NULL) {
2704 EXPECT_EQ(0,
iter->second->leading_detached_comments_size());
2707 expected_leading_detached_comments,
2708 Join(
iter->second->leading_detached_comments(),
"\n"));
2727 inline SpanKey(
const Message& descriptor_proto_param,
2731 index(index_param) {}
2733 inline bool operator<(
const SpanKey& other)
const {
2736 if (
field < other.field)
return true;
2737 if (
field > other.field)
return false;
2738 return index < other.index;
2742 typedef std::multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
2747 void ExtractMarkers(
const char*
text) {
2752 while (*
text !=
'\0') {
2764 }
else if (*
text ==
'\n') {
2777 TEST_F(SourceInfoTest, BasicFileDecls) {
2779 Parse(
"$a$syntax = \"proto2\";$i$\n"
2780 "$b$package foo.bar;$c$\n"
2781 "$d$import \"baz.proto\";$e$\n"
2782 "$f$import\"qux.proto\";$h$\n"
2783 "$j$import $k$public$l$ \"bar.proto\";$m$\n"
2784 "$n$import $o$weak$p$ \"bar.proto\";$q$\n"
2786 "// comment ignored\n"));
2799 TEST_F(SourceInfoTest, Messages) {
2801 Parse(
"$a$message $b$Foo$c$ {}$d$\n"
2802 "$e$message $f$Bar$g$ {}$h$\n"));
2813 TEST_F(SourceInfoTest, Fields) {
2815 Parse(
"message Foo {\n"
2816 " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
2817 " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
2831 EXPECT_TRUE(HasSpan(
'l',
'm', field2,
"type_name"));
2841 TEST_F(SourceInfoTest, Proto3Fields) {
2843 Parse(
"syntax = \"proto3\";\n"
2845 " $a$int32$b$ $c$bar$d$ = $e$1$f$;$g$\n"
2846 " $h$repeated$i$ $j$X.Y$k$ $l$baz$m$ = $n$2$o$;$p$\n"
2859 EXPECT_TRUE(HasSpan(
'j',
'k', field2,
"type_name"));
2872 Parse(
"$a$extend $b$Foo$c$ {\n"
2873 " $d$optional$e$ int32 bar = 1;$f$\n"
2874 " $g$repeated$h$ X.Y baz = 2;$i$\n"
2876 "$k$extend $l$Bar$m$ {\n"
2877 " $n$optional int32 qux = 1;$o$\n"
2889 EXPECT_TRUE(HasSpan(
'b',
'c', field1,
"extendee"));
2893 EXPECT_TRUE(HasSpan(
'b',
'c', field2,
"extendee"));
2896 EXPECT_TRUE(HasSpan(
'l',
'm', field3,
"extendee"));
2912 TEST_F(SourceInfoTest, NestedExtensions) {
2914 Parse(
"message Message {\n"
2915 " $a$extend $b$Foo$c$ {\n"
2916 " $d$optional$e$ int32 bar = 1;$f$\n"
2917 " $g$repeated$h$ X.Y baz = 2;$i$\n"
2919 " $k$extend $l$Bar$m$ {\n"
2920 " $n$optional int32 qux = 1;$o$\n"
2933 EXPECT_TRUE(HasSpan(
'b',
'c', field1,
"extendee"));
2937 EXPECT_TRUE(HasSpan(
'b',
'c', field2,
"extendee"));
2940 EXPECT_TRUE(HasSpan(
'l',
'm', field3,
"extendee"));
2958 TEST_F(SourceInfoTest, ExtensionRanges) {
2960 Parse(
"message Message {\n"
2961 " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
2962 " $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
2993 TEST_F(SourceInfoTest, ReservedRanges) {
2995 Parse(
"message Message {\n"
2996 " $a$reserved $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
3020 TEST_F(SourceInfoTest, Oneofs) {
3022 Parse(
"message Foo {\n"
3023 " $a$oneof $c$foo$d$ {\n"
3024 " $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n"
3032 EXPECT_TRUE(HasSpan(
'c',
'd', oneof_decl,
"name"));
3045 TEST_F(SourceInfoTest, NestedMessages) {
3047 Parse(
"message Foo {\n"
3048 " $a$message $b$Bar$c$ {\n"
3049 " $d$message $e$Baz$f$ {}$g$\n"
3051 " $i$message $j$Qux$k$ {}$l$\n"
3071 TEST_F(SourceInfoTest, Groups) {
3073 Parse(
"message Foo {\n"
3075 " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
3076 " $i$message Qux {}$j$\n"
3105 TEST_F(SourceInfoTest, Enums) {
3107 Parse(
"$a$enum $b$Foo$c$ {}$d$\n"
3108 "$e$enum $f$Bar$g$ {}$h$\n"));
3119 TEST_F(SourceInfoTest, EnumValues) {
3121 Parse(
"enum Foo {\n"
3122 " $a$BAR$b$ = $c$1$d$;$e$\n"
3123 " $f$BAZ$g$ = $h$2$i$;$j$\n"
3142 TEST_F(SourceInfoTest, EnumReservedRange) {
3144 Parse(
"enum TestEnum {\n"
3145 " $a$reserved $b$1$c$ to $d$10$e$;$f$\n"
3162 TEST_F(SourceInfoTest, EnumReservedName) {
3164 Parse(
"enum TestEnum {\n"
3165 " $a$reserved $b$'foo'$c$;$d$\n"
3179 TEST_F(SourceInfoTest, NestedEnums) {
3181 Parse(
"message Foo {\n"
3182 " $a$enum $b$Bar$c$ {}$d$\n"
3183 " $e$enum $f$Baz$g$ {}$h$\n"
3200 TEST_F(SourceInfoTest, Services) {
3202 Parse(
"$a$service $b$Foo$c$ {}$d$\n"
3203 "$e$service $f$Bar$g$ {}$h$\n"));
3214 TEST_F(SourceInfoTest, MethodsAndStreams) {
3216 Parse(
"service Foo {\n"
3217 " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
3218 " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
3231 EXPECT_TRUE(HasSpan(
'l',
'm', baz,
"input_type"));
3232 EXPECT_TRUE(HasSpan(
'n',
'o', baz,
"output_type"));
3241 TEST_F(SourceInfoTest, Options) {
3243 Parse(
"$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
3245 "$k$option qux = $l$-123$m$;$n$\n"
3246 "$o$option corge = $p$abc$q$;$r$\n"
3247 "$s$option grault = $t$'blah'$u$;$v$\n"
3248 "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
3249 "$0$option waldo = $1$123.0$2$;$3$\n"));
3265 EXPECT_TRUE(HasSpan(
'h',
'i', option1,
"positive_int_value"));
3268 EXPECT_TRUE(HasSpan(
'l',
'm', option2,
"negative_int_value"));
3271 EXPECT_TRUE(HasSpan(
'p',
'q', option3,
"identifier_value"));
3274 EXPECT_TRUE(HasSpan(
't',
'u', option4,
"string_value"));
3277 EXPECT_TRUE(HasSpan(
'x',
'y', option5,
"aggregate_value"));
3280 EXPECT_TRUE(HasSpan(
'1',
'2', option6,
"double_value"));
3306 TEST_F(SourceInfoTest, ScopedOptions) {
3308 Parse(
"message Foo {\n"
3309 " $a$option mopt = 1;$b$\n"
3312 " $c$option eopt = 1;$d$\n"
3315 " $e$option sopt = 1;$f$\n"
3316 " rpc M(X) returns(Y) {\n"
3317 " $g$option mopt = 1;$h$\n"
3319 " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
3320 " $k$option mopt = 1;$l$\n"
3342 "positive_int_value"));
3347 HasSpan(
file_.
enum_type(0).options().uninterpreted_option(0),
"name"));
3349 HasSpan(
file_.
enum_type(0).options().uninterpreted_option(0).name(0)));
3351 HasSpan(
file_.
enum_type(0).options().uninterpreted_option(0).name(0),
3354 "positive_int_value"));
3360 HasSpan(
file_.
service(0).options().uninterpreted_option(0),
"name"));
3362 HasSpan(
file_.
service(0).options().uninterpreted_option(0).name(0)));
3364 file_.
service(0).options().uninterpreted_option(0).name(0),
"name_part"));
3366 "positive_int_value"));
3371 HasSpan(
file_.
service(0).method(0).options().uninterpreted_option(0)));
3373 file_.
service(0).method(0).options().uninterpreted_option(0),
"name"));
3375 file_.
service(0).method(0).options().uninterpreted_option(0).name(0)));
3377 file_.
service(0).method(0).options().uninterpreted_option(0).name(0),
3380 HasSpan(
file_.
service(0).method(0).options().uninterpreted_option(0),
3381 "positive_int_value"));
3389 HasSpan(
file_.
service(0).method(1).options().uninterpreted_option(0)));
3391 file_.
service(0).method(1).options().uninterpreted_option(0),
"name"));
3393 file_.
service(0).method(1).options().uninterpreted_option(0).name(0)));
3395 file_.
service(0).method(1).options().uninterpreted_option(0).name(0),
3398 HasSpan(
file_.
service(0).method(1).options().uninterpreted_option(0),
3399 "positive_int_value"));
3401 HasSpan(
'1',
'2',
file_.
service(0).method(1),
"client_streaming"));
3403 HasSpan(
'3',
'4',
file_.
service(0).method(1),
"server_streaming"));
3411 Parse(
"message Foo {"
3412 " optional int32 bar = 1 "
3413 "$a$[default=$b$123$c$,$d$opt1=123$e$,"
3414 "$f$opt2='hi'$g$]$h$;"
3441 EXPECT_TRUE(HasSpan(option1,
"positive_int_value"));
3451 " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
3475 EXPECT_TRUE(HasSpan(option1,
"positive_int_value"));
3479 TEST_F(SourceInfoTest, DocComments) {
3481 Parse(
"// Foo leading\n"
3483 "$a$message Foo {\n"
3484 " // Foo trailing\n"
3490 " $b$optional int32 bar = 1;$c$\n"
3491 " // bar trailing\n"
3498 EXPECT_TRUE(HasSpanWithComment(
'a',
'd',
foo,
" Foo leading\n line 2\n",
3499 " Foo trailing\n line 2\n", NULL));
3501 " bar trailing\n",
" detached\n"));
3512 TEST_F(SourceInfoTest, DocComments2) {
3514 Parse(
"// detached before message.\n"
3518 "$a$message Foo {\n"
3519 " /* Foo trailing\n"
3524 " $b$optional int32 bar = 1;$c$ // bar trailing\n"
3525 " // ignored detached\n"
3529 "// detached before option\n"
3531 "// option leading\n"
3532 "$e$option baz = 123;$f$\n"
3533 "// option trailing\n"));
3539 EXPECT_TRUE(HasSpanWithComment(
'a',
'd',
foo,
" Foo leading\n line 2\n",
3540 " Foo trailing\n line 2 ",
3541 " detached before message.\n"));
3543 " bar trailing\n",
" detached\n"));
3544 EXPECT_TRUE(HasSpanWithComment(
'e',
'f', baz,
" option leading\n",
3545 " option trailing\n",
3546 " detached before option\n"));
3562 TEST_F(SourceInfoTest, DocComments3) {
3564 Parse(
"$a$message Foo {\n"
3566 " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
3567 " // bar trailing\n"
3575 " bar trailing\n", NULL));
3587 EXPECT_TRUE(HasSpan(
bar.options().uninterpreted_option(0),
"name"));
3588 EXPECT_TRUE(HasSpan(
bar.options().uninterpreted_option(0).name(0)));
3590 HasSpan(
bar.options().uninterpreted_option(0).name(0),
"name_part"));
3592 HasSpan(
bar.options().uninterpreted_option(0),
"aggregate_value"));
3595 TEST_F(SourceInfoTest, DocCommentsTopLevel) {
3597 Parse(
"// detached before syntax paragraph 1\n"
3599 "// detached before syntax paragraph 2\n"
3601 "// syntax leading\n"
3602 "$a$syntax = \"proto2\";$b$\n"
3603 "// syntax trailing\n"
3605 "// syntax-package detached comments\n"
3609 "// detached after empty before package\n"
3611 "// package leading\n"
3612 "$c$package foo;$d$\n"
3613 "// package trailing\n"
3615 "// ignored detach\n"
3619 " syntax trailing\n",
3620 " detached before syntax paragraph 1\n"
3622 " detached before syntax paragraph 2\n"));
3624 " package trailing\n",
3625 " syntax-package detached comments\n"
3627 " detached after empty before package\n"));
3633 TEST_F(SourceInfoTest, DocCommentsOneof) {
3635 Parse(
"// Foo leading\n"
3636 "$a$message Foo {\n"
3637 " /* Foo trailing\n"
3639 " // detached before oneof\n"
3643 " /* bar trailing\n"
3645 " // detached before bar_int\n"
3646 " /* bar_int leading\n"
3648 " $c$int32 bar_int = 1;$d$ // bar_int trailing\n"
3649 " // detach comment ignored\n"
3658 " Foo trailing\n", NULL));
3659 EXPECT_TRUE(HasSpanWithComment(
'b',
'e',
bar,
" bar leading\n line 2 ",
3660 " bar trailing\n line 2 ",
3661 " detached before oneof\n"));
3662 EXPECT_TRUE(HasSpanWithComment(
'c',
'd', bar_int,
" bar_int leading\n",
3663 " bar_int trailing\n",
3664 " detached before bar_int\n"));