1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <memory>
36 #ifndef _SHARED_PTR_H
37 #include <google/protobuf/stubs/shared_ptr.h>
38 #endif
39 #include <vector>
40 #include <algorithm>
41 #include <map>
42
43 #include <google/protobuf/compiler/parser.h>
44
45 #include <google/protobuf/io/tokenizer.h>
46 #include <google/protobuf/io/zero_copy_stream_impl.h>
47 #include <google/protobuf/descriptor.pb.h>
48 #include <google/protobuf/wire_format.h>
49 #include <google/protobuf/text_format.h>
50 #include <google/protobuf/unittest.pb.h>
51 #include <google/protobuf/unittest_custom_options.pb.h>
52 #include <google/protobuf/stubs/strutil.h>
53 #include <google/protobuf/stubs/substitute.h>
54 #include <google/protobuf/stubs/map_util.h>
55
56 #include <google/protobuf/testing/googletest.h>
57 #include <gtest/gtest.h>
58
59 namespace google {
60 namespace protobuf {
61 namespace compiler {
62
63 namespace {
64
65 class MockErrorCollector : public io::ErrorCollector {
66 public:
MockErrorCollector()67 MockErrorCollector() {}
~MockErrorCollector()68 ~MockErrorCollector() {}
69
70 string text_;
71
72 // implements ErrorCollector ---------------------------------------
AddError(int line,int column,const string & message)73 void AddError(int line, int column, const string& message) {
74 strings::SubstituteAndAppend(&text_, "$0:$1: $2\n",
75 line, column, message);
76 }
77 };
78
79 class MockValidationErrorCollector : public DescriptorPool::ErrorCollector {
80 public:
MockValidationErrorCollector(const SourceLocationTable & source_locations,io::ErrorCollector * wrapped_collector)81 MockValidationErrorCollector(const SourceLocationTable& source_locations,
82 io::ErrorCollector* wrapped_collector)
83 : source_locations_(source_locations),
84 wrapped_collector_(wrapped_collector) {}
~MockValidationErrorCollector()85 ~MockValidationErrorCollector() {}
86
87 // implements ErrorCollector ---------------------------------------
AddError(const string & filename,const string & element_name,const Message * descriptor,ErrorLocation location,const string & message)88 void AddError(const string& filename,
89 const string& element_name,
90 const Message* descriptor,
91 ErrorLocation location,
92 const string& message) {
93 int line, column;
94 source_locations_.Find(descriptor, location, &line, &column);
95 wrapped_collector_->AddError(line, column, message);
96 }
97
98 private:
99 const SourceLocationTable& source_locations_;
100 io::ErrorCollector* wrapped_collector_;
101 };
102
103 class ParserTest : public testing::Test {
104 protected:
ParserTest()105 ParserTest()
106 : require_syntax_identifier_(false) {}
107
108 // Set up the parser to parse the given text.
SetupParser(const char * text)109 void SetupParser(const char* text) {
110 raw_input_.reset(new io::ArrayInputStream(text, strlen(text)));
111 input_.reset(new io::Tokenizer(raw_input_.get(), &error_collector_));
112 parser_.reset(new Parser());
113 parser_->RecordErrorsTo(&error_collector_);
114 parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_);
115 }
116
117 // Parse the input and expect that the resulting FileDescriptorProto matches
118 // the given output. The output is a FileDescriptorProto in protocol buffer
119 // text format.
ExpectParsesTo(const char * input,const char * output)120 void ExpectParsesTo(const char* input, const char* output) {
121 SetupParser(input);
122 FileDescriptorProto actual, expected;
123
124 parser_->Parse(input_.get(), &actual);
125 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
126 ASSERT_EQ("", error_collector_.text_);
127
128 // We don't cover SourceCodeInfo in these tests.
129 actual.clear_source_code_info();
130
131 // Parse the ASCII representation in order to canonicalize it. We could
132 // just compare directly to actual.DebugString(), but that would require
133 // that the caller precisely match the formatting that DebugString()
134 // produces.
135 ASSERT_TRUE(TextFormat::ParseFromString(output, &expected));
136
137 // Compare by comparing debug strings.
138 // TODO(kenton): Use differencer, once it is available.
139 EXPECT_EQ(expected.DebugString(), actual.DebugString());
140 }
141
142 // Parse the text and expect that the given errors are reported.
ExpectHasErrors(const char * text,const char * expected_errors)143 void ExpectHasErrors(const char* text, const char* expected_errors) {
144 ExpectHasEarlyExitErrors(text, expected_errors);
145 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
146 }
147
148 // Same as above but does not expect that the parser parses the complete
149 // input.
ExpectHasEarlyExitErrors(const char * text,const char * expected_errors)150 void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) {
151 SetupParser(text);
152 FileDescriptorProto file;
153 parser_->Parse(input_.get(), &file);
154 EXPECT_EQ(expected_errors, error_collector_.text_);
155 }
156
157 // Parse the text as a file and validate it (with a DescriptorPool), and
158 // expect that the validation step reports the given errors.
ExpectHasValidationErrors(const char * text,const char * expected_errors)159 void ExpectHasValidationErrors(const char* text,
160 const char* expected_errors) {
161 SetupParser(text);
162 SourceLocationTable source_locations;
163 parser_->RecordSourceLocationsTo(&source_locations);
164
165 FileDescriptorProto file;
166 file.set_name("foo.proto");
167 parser_->Parse(input_.get(), &file);
168 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
169 ASSERT_EQ("", error_collector_.text_);
170
171 MockValidationErrorCollector validation_error_collector(
172 source_locations, &error_collector_);
173 EXPECT_TRUE(pool_.BuildFileCollectingErrors(
174 file, &validation_error_collector) == NULL);
175 EXPECT_EQ(expected_errors, error_collector_.text_);
176 }
177
178 MockErrorCollector error_collector_;
179 DescriptorPool pool_;
180
181 google::protobuf::scoped_ptr<io::ZeroCopyInputStream> raw_input_;
182 google::protobuf::scoped_ptr<io::Tokenizer> input_;
183 google::protobuf::scoped_ptr<Parser> parser_;
184 bool require_syntax_identifier_;
185 };
186
187 // ===================================================================
188
TEST_F(ParserTest,StopAfterSyntaxIdentifier)189 TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
190 SetupParser(
191 "// blah\n"
192 "syntax = \"foobar\";\n"
193 "this line will not be parsed\n");
194 parser_->SetStopAfterSyntaxIdentifier(true);
195 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
196 EXPECT_EQ("", error_collector_.text_);
197 EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
198 }
199
TEST_F(ParserTest,StopAfterOmittedSyntaxIdentifier)200 TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
201 SetupParser(
202 "// blah\n"
203 "this line will not be parsed\n");
204 parser_->SetStopAfterSyntaxIdentifier(true);
205 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
206 EXPECT_EQ("", error_collector_.text_);
207 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
208 }
209
TEST_F(ParserTest,StopAfterSyntaxIdentifierWithErrors)210 TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
211 SetupParser(
212 "// blah\n"
213 "syntax = error;\n");
214 parser_->SetStopAfterSyntaxIdentifier(true);
215 EXPECT_FALSE(parser_->Parse(input_.get(), NULL));
216 EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
217 }
218
TEST_F(ParserTest,WarnIfSyntaxIdentifierOmmitted)219 TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
220 SetupParser("message A {}");
221 FileDescriptorProto file;
222 CaptureTestStderr();
223 EXPECT_TRUE(parser_->Parse(input_.get(), &file));
224 EXPECT_TRUE(
225 GetCapturedTestStderr().find("No syntax specified") != string::npos);
226 }
227
228 // ===================================================================
229
230 typedef ParserTest ParseMessageTest;
231
TEST_F(ParseMessageTest,IgnoreBOM)232 TEST_F(ParseMessageTest, IgnoreBOM) {
233 char input[] = " message TestMessage {\n"
234 " required int32 foo = 1;\n"
235 "}\n";
236 // Set UTF-8 BOM.
237 input[0] = (char)0xEF;
238 input[1] = (char)0xBB;
239 input[2] = (char)0xBF;
240 ExpectParsesTo(input,
241 "message_type {"
242 " name: \"TestMessage\""
243 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
244 "}");
245 }
246
TEST_F(ParseMessageTest,BOMError)247 TEST_F(ParseMessageTest, BOMError) {
248 char input[] = " message TestMessage {\n"
249 " required int32 foo = 1;\n"
250 "}\n";
251 input[0] = (char)0xEF;
252 ExpectHasErrors(input,
253 "0:1: Proto file starts with 0xEF but not UTF-8 BOM. "
254 "Only UTF-8 is accepted for proto file.\n"
255 "0:0: Expected top-level statement (e.g. \"message\").\n");
256 }
257
TEST_F(ParseMessageTest,SimpleMessage)258 TEST_F(ParseMessageTest, SimpleMessage) {
259 ExpectParsesTo(
260 "message TestMessage {\n"
261 " required int32 foo = 1;\n"
262 "}\n",
263
264 "message_type {"
265 " name: \"TestMessage\""
266 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
267 "}");
268 }
269
TEST_F(ParseMessageTest,ImplicitSyntaxIdentifier)270 TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
271 require_syntax_identifier_ = false;
272 ExpectParsesTo(
273 "message TestMessage {\n"
274 " required int32 foo = 1;\n"
275 "}\n",
276
277 "message_type {"
278 " name: \"TestMessage\""
279 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
280 "}");
281 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
282 }
283
TEST_F(ParseMessageTest,ExplicitSyntaxIdentifier)284 TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
285 ExpectParsesTo(
286 "syntax = \"proto2\";\n"
287 "message TestMessage {\n"
288 " required int32 foo = 1;\n"
289 "}\n",
290
291 "syntax: 'proto2' "
292 "message_type {"
293 " name: \"TestMessage\""
294 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
295 "}");
296 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
297 }
298
TEST_F(ParseMessageTest,ExplicitRequiredSyntaxIdentifier)299 TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
300 require_syntax_identifier_ = true;
301 ExpectParsesTo(
302 "syntax = \"proto2\";\n"
303 "message TestMessage {\n"
304 " required int32 foo = 1;\n"
305 "}\n",
306
307 "syntax: 'proto2' "
308 "message_type {"
309 " name: \"TestMessage\""
310 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
311 "}");
312 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
313 }
314
TEST_F(ParseMessageTest,SimpleFields)315 TEST_F(ParseMessageTest, SimpleFields) {
316 ExpectParsesTo(
317 "message TestMessage {\n"
318 " required int32 foo = 15;\n"
319 " optional int32 bar = 34;\n"
320 " repeated int32 baz = 3;\n"
321 "}\n",
322
323 "message_type {"
324 " name: \"TestMessage\""
325 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
326 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
327 " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }"
328 "}");
329 }
330
TEST_F(ParseMessageTest,PrimitiveFieldTypes)331 TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
332 ExpectParsesTo(
333 "message TestMessage {\n"
334 " required int32 foo = 1;\n"
335 " required int64 foo = 1;\n"
336 " required uint32 foo = 1;\n"
337 " required uint64 foo = 1;\n"
338 " required sint32 foo = 1;\n"
339 " required sint64 foo = 1;\n"
340 " required fixed32 foo = 1;\n"
341 " required fixed64 foo = 1;\n"
342 " required sfixed32 foo = 1;\n"
343 " required sfixed64 foo = 1;\n"
344 " required float foo = 1;\n"
345 " required double foo = 1;\n"
346 " required string foo = 1;\n"
347 " required bytes foo = 1;\n"
348 " required bool foo = 1;\n"
349 "}\n",
350
351 "message_type {"
352 " name: \"TestMessage\""
353 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
354 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 }"
355 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 }"
356 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 }"
357 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 }"
358 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 }"
359 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 }"
360 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 }"
361 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 }"
362 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 }"
363 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 }"
364 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 }"
365 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 }"
366 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 }"
367 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 }"
368 "}");
369 }
370
TEST_F(ParseMessageTest,FieldDefaults)371 TEST_F(ParseMessageTest, FieldDefaults) {
372 ExpectParsesTo(
373 "message TestMessage {\n"
374 " required int32 foo = 1 [default= 1 ];\n"
375 " required int32 foo = 1 [default= -2 ];\n"
376 " required int64 foo = 1 [default= 3 ];\n"
377 " required int64 foo = 1 [default= -4 ];\n"
378 " required uint32 foo = 1 [default= 5 ];\n"
379 " required uint64 foo = 1 [default= 6 ];\n"
380 " required float foo = 1 [default= 7.5];\n"
381 " required float foo = 1 [default= -8.5];\n"
382 " required float foo = 1 [default= 9 ];\n"
383 " required double foo = 1 [default= 10.5];\n"
384 " required double foo = 1 [default=-11.5];\n"
385 " required double foo = 1 [default= 12 ];\n"
386 " required double foo = 1 [default= inf ];\n"
387 " required double foo = 1 [default=-inf ];\n"
388 " required double foo = 1 [default= nan ];\n"
389 " required string foo = 1 [default='13\\001'];\n"
390 " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
391 " required bytes foo = 1 [default='14\\002'];\n"
392 " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
393 " required bool foo = 1 [default=true ];\n"
394 " required Foo foo = 1 [default=FOO ];\n"
395
396 " required int32 foo = 1 [default= 0x7FFFFFFF];\n"
397 " required int32 foo = 1 [default=-0x80000000];\n"
398 " required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
399 " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
400 " required int64 foo = 1 [default=-0x8000000000000000];\n"
401 " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
402 " required double foo = 1 [default= 0xabcd];\n"
403 "}\n",
404
405 #define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
406 "message_type {"
407 " name: \"TestMessage\""
408 " field { type:TYPE_INT32 default_value:\"1\" " ETC " }"
409 " field { type:TYPE_INT32 default_value:\"-2\" " ETC " }"
410 " field { type:TYPE_INT64 default_value:\"3\" " ETC " }"
411 " field { type:TYPE_INT64 default_value:\"-4\" " ETC " }"
412 " field { type:TYPE_UINT32 default_value:\"5\" " ETC " }"
413 " field { type:TYPE_UINT64 default_value:\"6\" " ETC " }"
414 " field { type:TYPE_FLOAT default_value:\"7.5\" " ETC " }"
415 " field { type:TYPE_FLOAT default_value:\"-8.5\" " ETC " }"
416 " field { type:TYPE_FLOAT default_value:\"9\" " ETC " }"
417 " field { type:TYPE_DOUBLE default_value:\"10.5\" " ETC " }"
418 " field { type:TYPE_DOUBLE default_value:\"-11.5\" " ETC " }"
419 " field { type:TYPE_DOUBLE default_value:\"12\" " ETC " }"
420 " field { type:TYPE_DOUBLE default_value:\"inf\" " ETC " }"
421 " field { type:TYPE_DOUBLE default_value:\"-inf\" " ETC " }"
422 " field { type:TYPE_DOUBLE default_value:\"nan\" " ETC " }"
423 " field { type:TYPE_STRING default_value:\"13\\001\" " ETC " }"
424 " field { type:TYPE_STRING default_value:\"abc\" " ETC " }"
425 " field { type:TYPE_BYTES default_value:\"14\\\\002\" " ETC " }"
426 " field { type:TYPE_BYTES default_value:\"abc\" " ETC " }"
427 " field { type:TYPE_BOOL default_value:\"true\" " ETC " }"
428 " field { type_name:\"Foo\" default_value:\"FOO\" " ETC " }"
429
430 " field {"
431 " type:TYPE_INT32 default_value:\"2147483647\" " ETC
432 " }"
433 " field {"
434 " type:TYPE_INT32 default_value:\"-2147483648\" " ETC
435 " }"
436 " field {"
437 " type:TYPE_UINT32 default_value:\"4294967295\" " ETC
438 " }"
439 " field {"
440 " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC
441 " }"
442 " field {"
443 " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC
444 " }"
445 " field {"
446 " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC
447 " }"
448 " field {"
449 " type:TYPE_DOUBLE default_value:\"43981\" " ETC
450 " }"
451 "}");
452 #undef ETC
453 }
454
TEST_F(ParseMessageTest,FieldJsonName)455 TEST_F(ParseMessageTest, FieldJsonName) {
456 ExpectParsesTo(
457 "message TestMessage {\n"
458 " optional string foo = 1 [json_name = \"@type\"];\n"
459 "}\n",
460 "message_type {"
461 " name: \"TestMessage\""
462 " field {\n"
463 " name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
464 " json_name: \"@type\"\n"
465 " }\n"
466 "}\n");
467 }
468
TEST_F(ParseMessageTest,FieldOptions)469 TEST_F(ParseMessageTest, FieldOptions) {
470 ExpectParsesTo(
471 "message TestMessage {\n"
472 " optional string foo = 1\n"
473 " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
474 " (quux)=\"x\040y\", (baz.qux)=hey];\n"
475 "}\n",
476
477 "message_type {"
478 " name: \"TestMessage\""
479 " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
480 " options { uninterpreted_option: { name { name_part: \"ctype\" "
481 " is_extension: false } "
482 " identifier_value: \"CORD\" }"
483 " uninterpreted_option: { name { name_part: \"foo\" "
484 " is_extension: true } "
485 " positive_int_value: 7 }"
486 " uninterpreted_option: { name { name_part: \"foo\" "
487 " is_extension: false } "
488 " name { name_part: \".bar.baz\""
489 " is_extension: true } "
490 " name { name_part: \"qux\" "
491 " is_extension: false } "
492 " name { name_part: \"quux\" "
493 " is_extension: false } "
494 " name { name_part: \"corge\" "
495 " is_extension: true } "
496 " negative_int_value: -33 }"
497 " uninterpreted_option: { name { name_part: \"quux\" "
498 " is_extension: true } "
499 " string_value: \"x y\" }"
500 " uninterpreted_option: { name { name_part: \"baz.qux\" "
501 " is_extension: true } "
502 " identifier_value: \"hey\" }"
503 " }"
504 " }"
505 "}");
506 }
507
TEST_F(ParseMessageTest,Oneof)508 TEST_F(ParseMessageTest, Oneof) {
509 ExpectParsesTo(
510 "message TestMessage {\n"
511 " oneof foo {\n"
512 " int32 a = 1;\n"
513 " string b = 2;\n"
514 " TestMessage c = 3;\n"
515 " group D = 4 { optional int32 i = 5; }\n"
516 " }\n"
517 "}\n",
518
519 "message_type {"
520 " name: \"TestMessage\""
521 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
522 " oneof_index:0 }"
523 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
524 " oneof_index:0 }"
525 " field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" "
526 " number:3 oneof_index:0 }"
527 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP "
528 " type_name:\"D\" number:4 oneof_index:0 }"
529 " oneof_decl {"
530 " name: \"foo\""
531 " }"
532 " nested_type {"
533 " name: \"D\""
534 " field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }"
535 " }"
536 "}");
537 }
538
TEST_F(ParseMessageTest,MultipleOneofs)539 TEST_F(ParseMessageTest, MultipleOneofs) {
540 ExpectParsesTo(
541 "message TestMessage {\n"
542 " oneof foo {\n"
543 " int32 a = 1;\n"
544 " string b = 2;\n"
545 " }\n"
546 " oneof bar {\n"
547 " int32 c = 3;\n"
548 " string d = 4;\n"
549 " }\n"
550 "}\n",
551
552 "message_type {"
553 " name: \"TestMessage\""
554 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
555 " oneof_index:0 }"
556 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
557 " oneof_index:0 }"
558 " field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 "
559 " oneof_index:1 }"
560 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 "
561 " oneof_index:1 }"
562 " oneof_decl {"
563 " name: \"foo\""
564 " }"
565 " oneof_decl {"
566 " name: \"bar\""
567 " }"
568 "}");
569 }
570
TEST_F(ParseMessageTest,Maps)571 TEST_F(ParseMessageTest, Maps) {
572 ExpectParsesTo(
573 "message TestMessage {\n"
574 " map<int32, string> primitive_type_map = 1;\n"
575 " map<KeyType, ValueType> composite_type_map = 2;\n"
576 "}\n",
577
578 "message_type {"
579 " name: \"TestMessage\""
580 " nested_type {"
581 " name: \"PrimitiveTypeMapEntry\""
582 " field { "
583 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
584 " type:TYPE_INT32"
585 " }"
586 " field { "
587 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
588 " type:TYPE_STRING"
589 " }"
590 " options { map_entry: true }"
591 " }"
592 " nested_type {"
593 " name: \"CompositeTypeMapEntry\""
594 " field { "
595 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
596 " type_name: \"KeyType\""
597 " }"
598 " field { "
599 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
600 " type_name: \"ValueType\""
601 " }"
602 " options { map_entry: true }"
603 " }"
604 " field {"
605 " name: \"primitive_type_map\""
606 " label: LABEL_REPEATED"
607 " type_name: \"PrimitiveTypeMapEntry\""
608 " number: 1"
609 " }"
610 " field {"
611 " name: \"composite_type_map\""
612 " label: LABEL_REPEATED"
613 " type_name: \"CompositeTypeMapEntry\""
614 " number: 2"
615 " }"
616 "}");
617 }
618
TEST_F(ParseMessageTest,Group)619 TEST_F(ParseMessageTest, Group) {
620 ExpectParsesTo(
621 "message TestMessage {\n"
622 " optional group TestGroup = 1 {};\n"
623 "}\n",
624
625 "message_type {"
626 " name: \"TestMessage\""
627 " nested_type { name: \"TestGroup\" }"
628 " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
629 " type:TYPE_GROUP type_name: \"TestGroup\" }"
630 "}");
631 }
632
TEST_F(ParseMessageTest,NestedMessage)633 TEST_F(ParseMessageTest, NestedMessage) {
634 ExpectParsesTo(
635 "message TestMessage {\n"
636 " message Nested {}\n"
637 " optional Nested test_nested = 1;\n"
638 "}\n",
639
640 "message_type {"
641 " name: \"TestMessage\""
642 " nested_type { name: \"Nested\" }"
643 " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
644 " type_name: \"Nested\" }"
645 "}");
646 }
647
TEST_F(ParseMessageTest,NestedEnum)648 TEST_F(ParseMessageTest, NestedEnum) {
649 ExpectParsesTo(
650 "message TestMessage {\n"
651 " enum NestedEnum {}\n"
652 " optional NestedEnum test_enum = 1;\n"
653 "}\n",
654
655 "message_type {"
656 " name: \"TestMessage\""
657 " enum_type { name: \"NestedEnum\" }"
658 " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
659 " type_name: \"NestedEnum\" }"
660 "}");
661 }
662
TEST_F(ParseMessageTest,ReservedRange)663 TEST_F(ParseMessageTest, ReservedRange) {
664 ExpectParsesTo(
665 "message TestMessage {\n"
666 " required int32 foo = 1;\n"
667 " reserved 2, 15, 9 to 11, 3;\n"
668 "}\n",
669
670 "message_type {"
671 " name: \"TestMessage\""
672 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
673 " reserved_range { start:2 end:3 }"
674 " reserved_range { start:15 end:16 }"
675 " reserved_range { start:9 end:12 }"
676 " reserved_range { start:3 end:4 }"
677 "}");
678 }
679
TEST_F(ParseMessageTest,ReservedNames)680 TEST_F(ParseMessageTest, ReservedNames) {
681 ExpectParsesTo(
682 "message TestMessage {\n"
683 " reserved \"foo\", \"bar\";\n"
684 "}\n",
685
686 "message_type {"
687 " name: \"TestMessage\""
688 " reserved_name: \"foo\""
689 " reserved_name: \"bar\""
690 "}");
691 }
692
TEST_F(ParseMessageTest,ExtensionRange)693 TEST_F(ParseMessageTest, ExtensionRange) {
694 ExpectParsesTo(
695 "message TestMessage {\n"
696 " extensions 10 to 19;\n"
697 " extensions 30 to max;\n"
698 "}\n",
699
700 "message_type {"
701 " name: \"TestMessage\""
702 " extension_range { start:10 end:20 }"
703 " extension_range { start:30 end:536870912 }"
704 "}");
705 }
706
TEST_F(ParseMessageTest,CompoundExtensionRange)707 TEST_F(ParseMessageTest, CompoundExtensionRange) {
708 ExpectParsesTo(
709 "message TestMessage {\n"
710 " extensions 2, 15, 9 to 11, 100 to max, 3;\n"
711 "}\n",
712
713 "message_type {"
714 " name: \"TestMessage\""
715 " extension_range { start:2 end:3 }"
716 " extension_range { start:15 end:16 }"
717 " extension_range { start:9 end:12 }"
718 " extension_range { start:100 end:536870912 }"
719 " extension_range { start:3 end:4 }"
720 "}");
721 }
722
TEST_F(ParseMessageTest,LargerMaxForMessageSetWireFormatMessages)723 TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
724 // Messages using the message_set_wire_format option can accept larger
725 // extension numbers, as the numbers are not encoded as int32 field values
726 // rather than tags.
727 ExpectParsesTo(
728 "message TestMessage {\n"
729 " extensions 4 to max;\n"
730 " option message_set_wire_format = true;\n"
731 "}\n",
732
733 "message_type {"
734 " name: \"TestMessage\""
735 " extension_range { start:4 end: 0x7fffffff }"
736 " options {\n"
737 " uninterpreted_option { \n"
738 " name {\n"
739 " name_part: \"message_set_wire_format\"\n"
740 " is_extension: false\n"
741 " }\n"
742 " identifier_value: \"true\"\n"
743 " }\n"
744 " }\n"
745 "}");
746 }
747
TEST_F(ParseMessageTest,Extensions)748 TEST_F(ParseMessageTest, Extensions) {
749 ExpectParsesTo(
750 "extend Extendee1 { optional int32 foo = 12; }\n"
751 "extend Extendee2 { repeated TestMessage bar = 22; }\n",
752
753 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
754 " extendee: \"Extendee1\" } "
755 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
756 " type_name:\"TestMessage\" extendee: \"Extendee2\" }");
757 }
758
TEST_F(ParseMessageTest,ExtensionsInMessageScope)759 TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
760 ExpectParsesTo(
761 "message TestMessage {\n"
762 " extend Extendee1 { optional int32 foo = 12; }\n"
763 " extend Extendee2 { repeated TestMessage bar = 22; }\n"
764 "}\n",
765
766 "message_type {"
767 " name: \"TestMessage\""
768 " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
769 " extendee: \"Extendee1\" }"
770 " extension { name:\"bar\" label:LABEL_REPEATED number:22"
771 " type_name:\"TestMessage\" extendee: \"Extendee2\" }"
772 "}");
773 }
774
TEST_F(ParseMessageTest,MultipleExtensionsOneExtendee)775 TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
776 ExpectParsesTo(
777 "extend Extendee1 {\n"
778 " optional int32 foo = 12;\n"
779 " repeated TestMessage bar = 22;\n"
780 "}\n",
781
782 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
783 " extendee: \"Extendee1\" } "
784 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
785 " type_name:\"TestMessage\" extendee: \"Extendee1\" }");
786 }
787
TEST_F(ParseMessageTest,OptionalLabelProto3)788 TEST_F(ParseMessageTest, OptionalLabelProto3) {
789 ExpectParsesTo(
790 "syntax = \"proto3\";\n"
791 "message TestMessage {\n"
792 " int32 foo = 1;\n"
793 "}\n",
794
795 "syntax: \"proto3\" "
796 "message_type {"
797 " name: \"TestMessage\""
798 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } }");
799 }
800
801 // ===================================================================
802
803 typedef ParserTest ParseEnumTest;
804
TEST_F(ParseEnumTest,SimpleEnum)805 TEST_F(ParseEnumTest, SimpleEnum) {
806 ExpectParsesTo(
807 "enum TestEnum {\n"
808 " FOO = 0;\n"
809 "}\n",
810
811 "enum_type {"
812 " name: \"TestEnum\""
813 " value { name:\"FOO\" number:0 }"
814 "}");
815 }
816
TEST_F(ParseEnumTest,Values)817 TEST_F(ParseEnumTest, Values) {
818 ExpectParsesTo(
819 "enum TestEnum {\n"
820 " FOO = 13;\n"
821 " BAR = -10;\n"
822 " BAZ = 500;\n"
823 " HEX_MAX = 0x7FFFFFFF;\n"
824 " HEX_MIN = -0x80000000;\n"
825 " INT_MAX = 2147483647;\n"
826 " INT_MIN = -2147483648;\n"
827 "}\n",
828
829 "enum_type {"
830 " name: \"TestEnum\""
831 " value { name:\"FOO\" number:13 }"
832 " value { name:\"BAR\" number:-10 }"
833 " value { name:\"BAZ\" number:500 }"
834 " value { name:\"HEX_MAX\" number:2147483647 }"
835 " value { name:\"HEX_MIN\" number:-2147483648 }"
836 " value { name:\"INT_MAX\" number:2147483647 }"
837 " value { name:\"INT_MIN\" number:-2147483648 }"
838 "}");
839 }
840
TEST_F(ParseEnumTest,ValueOptions)841 TEST_F(ParseEnumTest, ValueOptions) {
842 ExpectParsesTo(
843 "enum TestEnum {\n"
844 " FOO = 13;\n"
845 " BAR = -10 [ (something.text) = 'abc' ];\n"
846 " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
847 "}\n",
848
849 "enum_type {"
850 " name: \"TestEnum\""
851 " value { name: \"FOO\" number: 13 }"
852 " value { name: \"BAR\" number: -10 "
853 " options { "
854 " uninterpreted_option { "
855 " name { name_part: \"something.text\" is_extension: true } "
856 " string_value: \"abc\" "
857 " } "
858 " } "
859 " } "
860 " value { name: \"BAZ\" number: 500 "
861 " options { "
862 " uninterpreted_option { "
863 " name { name_part: \"something.text\" is_extension: true } "
864 " string_value: \"def\" "
865 " } "
866 " uninterpreted_option { "
867 " name { name_part: \"other\" is_extension: false } "
868 " positive_int_value: 1 "
869 " } "
870 " } "
871 " } "
872 "}");
873 }
874
875 // ===================================================================
876
877 typedef ParserTest ParseServiceTest;
878
TEST_F(ParseServiceTest,SimpleService)879 TEST_F(ParseServiceTest, SimpleService) {
880 ExpectParsesTo(
881 "service TestService {\n"
882 " rpc Foo(In) returns (Out);\n"
883 "}\n",
884
885 "service {"
886 " name: \"TestService\""
887 " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
888 "}");
889 }
890
TEST_F(ParseServiceTest,MethodsAndStreams)891 TEST_F(ParseServiceTest, MethodsAndStreams) {
892 ExpectParsesTo(
893 "service TestService {\n"
894 " rpc Foo(In1) returns (Out1);\n"
895 " rpc Bar(In2) returns (Out2);\n"
896 " rpc Baz(In3) returns (Out3);\n"
897 "}\n",
898
899 "service {"
900 " name: \"TestService\""
901 " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
902 " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
903 " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
904 "}");
905 }
906
907
908
909 // ===================================================================
910 // imports and packages
911
912 typedef ParserTest ParseMiscTest;
913
TEST_F(ParseMiscTest,ParseImport)914 TEST_F(ParseMiscTest, ParseImport) {
915 ExpectParsesTo(
916 "import \"foo/bar/baz.proto\";\n",
917 "dependency: \"foo/bar/baz.proto\"");
918 }
919
TEST_F(ParseMiscTest,ParseMultipleImports)920 TEST_F(ParseMiscTest, ParseMultipleImports) {
921 ExpectParsesTo(
922 "import \"foo.proto\";\n"
923 "import \"bar.proto\";\n"
924 "import \"baz.proto\";\n",
925 "dependency: \"foo.proto\""
926 "dependency: \"bar.proto\""
927 "dependency: \"baz.proto\"");
928 }
929
TEST_F(ParseMiscTest,ParsePublicImports)930 TEST_F(ParseMiscTest, ParsePublicImports) {
931 ExpectParsesTo(
932 "import \"foo.proto\";\n"
933 "import public \"bar.proto\";\n"
934 "import \"baz.proto\";\n"
935 "import public \"qux.proto\";\n",
936 "dependency: \"foo.proto\""
937 "dependency: \"bar.proto\""
938 "dependency: \"baz.proto\""
939 "dependency: \"qux.proto\""
940 "public_dependency: 1 "
941 "public_dependency: 3 ");
942 }
943
TEST_F(ParseMiscTest,ParsePackage)944 TEST_F(ParseMiscTest, ParsePackage) {
945 ExpectParsesTo(
946 "package foo.bar.baz;\n",
947 "package: \"foo.bar.baz\"");
948 }
949
TEST_F(ParseMiscTest,ParsePackageWithSpaces)950 TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
951 ExpectParsesTo(
952 "package foo . bar. \n"
953 " baz;\n",
954 "package: \"foo.bar.baz\"");
955 }
956
957 // ===================================================================
958 // options
959
TEST_F(ParseMiscTest,ParseFileOptions)960 TEST_F(ParseMiscTest, ParseFileOptions) {
961 ExpectParsesTo(
962 "option java_package = \"com.google.foo\";\n"
963 "option optimize_for = CODE_SIZE;",
964
965 "options {"
966 "uninterpreted_option { name { name_part: \"java_package\" "
967 " is_extension: false }"
968 " string_value: \"com.google.foo\"} "
969 "uninterpreted_option { name { name_part: \"optimize_for\" "
970 " is_extension: false }"
971 " identifier_value: \"CODE_SIZE\" } "
972 "}");
973 }
974
975 // ===================================================================
976 // Error tests
977 //
978 // There are a very large number of possible errors that the parser could
979 // report, so it's infeasible to test every single one of them. Instead,
980 // we test each unique call to AddError() in parser.h. This does not mean
981 // we are testing every possible error that Parser can generate because
982 // each variant of the Consume() helper only counts as one unique call to
983 // AddError().
984
985 typedef ParserTest ParseErrorTest;
986
TEST_F(ParseErrorTest,MissingSyntaxIdentifier)987 TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
988 require_syntax_identifier_ = true;
989 ExpectHasEarlyExitErrors("message TestMessage {}",
990 "0:0: File must begin with a syntax statement, e.g. "
991 "'syntax = \"proto2\";'.\n");
992 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
993 }
994
TEST_F(ParseErrorTest,UnknownSyntaxIdentifier)995 TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
996 ExpectHasEarlyExitErrors(
997 "syntax = \"no_such_syntax\";",
998 "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
999 "only recognizes \"proto2\" and \"proto3\".\n");
1000 EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
1001 }
1002
TEST_F(ParseErrorTest,SimpleSyntaxError)1003 TEST_F(ParseErrorTest, SimpleSyntaxError) {
1004 ExpectHasErrors(
1005 "message TestMessage @#$ { blah }",
1006 "0:20: Expected \"{\".\n");
1007 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
1008 }
1009
TEST_F(ParseErrorTest,ExpectedTopLevel)1010 TEST_F(ParseErrorTest, ExpectedTopLevel) {
1011 ExpectHasErrors(
1012 "blah;",
1013 "0:0: Expected top-level statement (e.g. \"message\").\n");
1014 }
1015
TEST_F(ParseErrorTest,UnmatchedCloseBrace)1016 TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
1017 // This used to cause an infinite loop. Doh.
1018 ExpectHasErrors(
1019 "}",
1020 "0:0: Expected top-level statement (e.g. \"message\").\n"
1021 "0:0: Unmatched \"}\".\n");
1022 }
1023
1024 // -------------------------------------------------------------------
1025 // Message errors
1026
TEST_F(ParseErrorTest,MessageMissingName)1027 TEST_F(ParseErrorTest, MessageMissingName) {
1028 ExpectHasErrors(
1029 "message {}",
1030 "0:8: Expected message name.\n");
1031 }
1032
TEST_F(ParseErrorTest,MessageMissingBody)1033 TEST_F(ParseErrorTest, MessageMissingBody) {
1034 ExpectHasErrors(
1035 "message TestMessage;",
1036 "0:19: Expected \"{\".\n");
1037 }
1038
TEST_F(ParseErrorTest,EofInMessage)1039 TEST_F(ParseErrorTest, EofInMessage) {
1040 ExpectHasErrors(
1041 "message TestMessage {",
1042 "0:21: Reached end of input in message definition (missing '}').\n");
1043 }
1044
TEST_F(ParseErrorTest,MissingFieldNumber)1045 TEST_F(ParseErrorTest, MissingFieldNumber) {
1046 ExpectHasErrors(
1047 "message TestMessage {\n"
1048 " optional int32 foo;\n"
1049 "}\n",
1050 "1:20: Missing field number.\n");
1051 }
1052
TEST_F(ParseErrorTest,ExpectedFieldNumber)1053 TEST_F(ParseErrorTest, ExpectedFieldNumber) {
1054 ExpectHasErrors(
1055 "message TestMessage {\n"
1056 " optional int32 foo = ;\n"
1057 "}\n",
1058 "1:23: Expected field number.\n");
1059 }
1060
TEST_F(ParseErrorTest,FieldNumberOutOfRange)1061 TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
1062 ExpectHasErrors(
1063 "message TestMessage {\n"
1064 " optional int32 foo = 0x100000000;\n"
1065 "}\n",
1066 "1:23: Integer out of range.\n");
1067 }
1068
TEST_F(ParseErrorTest,MissingLabel)1069 TEST_F(ParseErrorTest, MissingLabel) {
1070 ExpectHasErrors(
1071 "message TestMessage {\n"
1072 " int32 foo = 1;\n"
1073 "}\n",
1074 "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
1075 }
1076
TEST_F(ParseErrorTest,ExpectedOptionName)1077 TEST_F(ParseErrorTest, ExpectedOptionName) {
1078 ExpectHasErrors(
1079 "message TestMessage {\n"
1080 " optional uint32 foo = 1 [];\n"
1081 "}\n",
1082 "1:27: Expected identifier.\n");
1083 }
1084
TEST_F(ParseErrorTest,NonExtensionOptionNameBeginningWithDot)1085 TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
1086 ExpectHasErrors(
1087 "message TestMessage {\n"
1088 " optional uint32 foo = 1 [.foo=1];\n"
1089 "}\n",
1090 "1:27: Expected identifier.\n");
1091 }
1092
TEST_F(ParseErrorTest,DefaultValueTypeMismatch)1093 TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
1094 ExpectHasErrors(
1095 "message TestMessage {\n"
1096 " optional uint32 foo = 1 [default=true];\n"
1097 "}\n",
1098 "1:35: Expected integer for field default value.\n");
1099 }
1100
TEST_F(ParseErrorTest,DefaultValueNotBoolean)1101 TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
1102 ExpectHasErrors(
1103 "message TestMessage {\n"
1104 " optional bool foo = 1 [default=blah];\n"
1105 "}\n",
1106 "1:33: Expected \"true\" or \"false\".\n");
1107 }
1108
TEST_F(ParseErrorTest,DefaultValueNotString)1109 TEST_F(ParseErrorTest, DefaultValueNotString) {
1110 ExpectHasErrors(
1111 "message TestMessage {\n"
1112 " optional string foo = 1 [default=1];\n"
1113 "}\n",
1114 "1:35: Expected string for field default value.\n");
1115 }
1116
TEST_F(ParseErrorTest,DefaultValueUnsignedNegative)1117 TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
1118 ExpectHasErrors(
1119 "message TestMessage {\n"
1120 " optional uint32 foo = 1 [default=-1];\n"
1121 "}\n",
1122 "1:36: Unsigned field can't have negative default value.\n");
1123 }
1124
TEST_F(ParseErrorTest,DefaultValueTooLarge)1125 TEST_F(ParseErrorTest, DefaultValueTooLarge) {
1126 ExpectHasErrors(
1127 "message TestMessage {\n"
1128 " optional int32 foo = 1 [default= 0x80000000];\n"
1129 " optional int32 foo = 1 [default=-0x80000001];\n"
1130 " optional uint32 foo = 1 [default= 0x100000000];\n"
1131 " optional int64 foo = 1 [default= 0x80000000000000000];\n"
1132 " optional int64 foo = 1 [default=-0x80000000000000001];\n"
1133 " optional uint64 foo = 1 [default= 0x100000000000000000];\n"
1134 "}\n",
1135 "1:36: Integer out of range.\n"
1136 "2:36: Integer out of range.\n"
1137 "3:36: Integer out of range.\n"
1138 "4:36: Integer out of range.\n"
1139 "5:36: Integer out of range.\n"
1140 "6:36: Integer out of range.\n");
1141 }
1142
TEST_F(ParseErrorTest,JsonNameNotString)1143 TEST_F(ParseErrorTest, JsonNameNotString) {
1144 ExpectHasErrors(
1145 "message TestMessage {\n"
1146 " optional string foo = 1 [json_name=1];\n"
1147 "}\n",
1148 "1:37: Expected string for JSON name.\n");
1149 }
1150
TEST_F(ParseErrorTest,DuplicateJsonName)1151 TEST_F(ParseErrorTest, DuplicateJsonName) {
1152 ExpectHasErrors(
1153 "message TestMessage {\n"
1154 " optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
1155 "}\n",
1156 "1:41: Already set option \"json_name\".\n");
1157 }
1158
TEST_F(ParseErrorTest,EnumValueOutOfRange)1159 TEST_F(ParseErrorTest, EnumValueOutOfRange) {
1160 ExpectHasErrors(
1161 "enum TestEnum {\n"
1162 " HEX_TOO_BIG = 0x80000000;\n"
1163 " HEX_TOO_SMALL = -0x80000001;\n"
1164 " INT_TOO_BIG = 2147483648;\n"
1165 " INT_TOO_SMALL = -2147483649;\n"
1166 "}\n",
1167 "1:19: Integer out of range.\n"
1168 "2:19: Integer out of range.\n"
1169 "3:19: Integer out of range.\n"
1170 "4:19: Integer out of range.\n");
1171 }
1172
TEST_F(ParseErrorTest,EnumAllowAliasFalse)1173 TEST_F(ParseErrorTest, EnumAllowAliasFalse) {
1174 ExpectHasErrors(
1175 "enum Foo {\n"
1176 " option allow_alias = false;\n"
1177 " BAR = 1;\n"
1178 " BAZ = 2;\n"
1179 "}\n",
1180 "5:0: \"Foo\" declares 'option allow_alias = false;' which has no effect. "
1181 "Please remove the declaration.\n");
1182 }
1183
TEST_F(ParseErrorTest,UnnecessaryEnumAllowAlias)1184 TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) {
1185 ExpectHasErrors(
1186 "enum Foo {\n"
1187 " option allow_alias = true;\n"
1188 " BAR = 1;\n"
1189 " BAZ = 2;\n"
1190 "}\n",
1191 "5:0: \"Foo\" declares support for enum aliases but no enum values share "
1192 "field numbers. Please remove the unnecessary 'option allow_alias = true;' "
1193 "declaration.\n");
1194 }
1195
TEST_F(ParseErrorTest,DefaultValueMissing)1196 TEST_F(ParseErrorTest, DefaultValueMissing) {
1197 ExpectHasErrors(
1198 "message TestMessage {\n"
1199 " optional uint32 foo = 1 [default=];\n"
1200 "}\n",
1201 "1:35: Expected integer for field default value.\n");
1202 }
1203
TEST_F(ParseErrorTest,DefaultValueForGroup)1204 TEST_F(ParseErrorTest, DefaultValueForGroup) {
1205 ExpectHasErrors(
1206 "message TestMessage {\n"
1207 " optional group Foo = 1 [default=blah] {}\n"
1208 "}\n",
1209 "1:34: Messages can't have default values.\n");
1210 }
1211
TEST_F(ParseErrorTest,DuplicateDefaultValue)1212 TEST_F(ParseErrorTest, DuplicateDefaultValue) {
1213 ExpectHasErrors(
1214 "message TestMessage {\n"
1215 " optional uint32 foo = 1 [default=1,default=2];\n"
1216 "}\n",
1217 "1:37: Already set option \"default\".\n");
1218 }
1219
TEST_F(ParseErrorTest,MissingOneofName)1220 TEST_F(ParseErrorTest, MissingOneofName) {
1221 ExpectHasErrors(
1222 "message TestMessage {\n"
1223 " oneof {\n"
1224 " int32 bar = 1;\n"
1225 " }\n"
1226 "}\n",
1227 "1:8: Expected oneof name.\n");
1228 }
1229
TEST_F(ParseErrorTest,LabelInOneof)1230 TEST_F(ParseErrorTest, LabelInOneof) {
1231 ExpectHasErrors(
1232 "message TestMessage {\n"
1233 " oneof foo {\n"
1234 " optional int32 bar = 1;\n"
1235 " }\n"
1236 "}\n",
1237 "2:4: Fields in oneofs must not have labels (required / optional "
1238 "/ repeated).\n");
1239 }
1240
TEST_F(ParseErrorTest,MapInOneof)1241 TEST_F(ParseErrorTest, MapInOneof) {
1242 ExpectHasErrors(
1243 "message TestMessage {\n"
1244 " oneof foo {\n"
1245 " map<int32, int32> foo_map = 1;\n"
1246 " map message_field = 2;\n" // a normal message field is OK
1247 " }\n"
1248 "}\n",
1249 "2:7: Map fields are not allowed in oneofs.\n");
1250 }
1251
TEST_F(ParseErrorTest,LabelForMap)1252 TEST_F(ParseErrorTest, LabelForMap) {
1253 ExpectHasErrors(
1254 "message TestMessage {\n"
1255 " optional map<int32, int32> int_map = 1;\n"
1256 " required map<int32, int32> int_map2 = 2;\n"
1257 " repeated map<int32, int32> int_map3 = 3;\n"
1258 " optional map map_message = 4;\n" // a normal message field is OK
1259 "}\n",
1260 "1:14: Field labels (required/optional/repeated) are not allowed on map "
1261 "fields.\n"
1262 "2:14: Field labels (required/optional/repeated) are not allowed on map "
1263 "fields.\n"
1264 "3:14: Field labels (required/optional/repeated) are not allowed on map "
1265 "fields.\n");
1266 }
1267
TEST_F(ParseErrorTest,MalformedMaps)1268 TEST_F(ParseErrorTest, MalformedMaps) {
1269 ExpectHasErrors(
1270 "message TestMessage {\n"
1271 " map map_message = 1;\n" // a normal message field lacking label
1272 " map<string> str_map = 2;\n"
1273 " map<string,> str_map2 = 3;\n"
1274 " map<,string> str_map3 = 4;\n"
1275 " map<> empty_map = 5;\n"
1276 " map<string,string str_map6 = 6;\n"
1277 "}"
1278 "extend SomeMessage {\n"
1279 " map<int32, int32> int_map = 1;\n"
1280 "}",
1281 "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
1282 "2:12: Expected \",\".\n"
1283 "3:13: Expected type name.\n"
1284 "4:6: Expected type name.\n"
1285 "5:6: Expected type name.\n"
1286 "6:20: Expected \">\".\n"
1287 "8:5: Map fields are not allowed to be extensions.\n");
1288 }
1289
TEST_F(ParseErrorTest,GroupNotCapitalized)1290 TEST_F(ParseErrorTest, GroupNotCapitalized) {
1291 ExpectHasErrors(
1292 "message TestMessage {\n"
1293 " optional group foo = 1 {}\n"
1294 "}\n",
1295 "1:17: Group names must start with a capital letter.\n");
1296 }
1297
TEST_F(ParseErrorTest,GroupMissingBody)1298 TEST_F(ParseErrorTest, GroupMissingBody) {
1299 ExpectHasErrors(
1300 "message TestMessage {\n"
1301 " optional group Foo = 1;\n"
1302 "}\n",
1303 "1:24: Missing group body.\n");
1304 }
1305
TEST_F(ParseErrorTest,ExtendingPrimitive)1306 TEST_F(ParseErrorTest, ExtendingPrimitive) {
1307 ExpectHasErrors(
1308 "extend int32 { optional string foo = 4; }\n",
1309 "0:7: Expected message type.\n");
1310 }
1311
TEST_F(ParseErrorTest,ErrorInExtension)1312 TEST_F(ParseErrorTest, ErrorInExtension) {
1313 ExpectHasErrors(
1314 "message Foo { extensions 100 to 199; }\n"
1315 "extend Foo { optional string foo; }\n",
1316 "1:32: Missing field number.\n");
1317 }
1318
TEST_F(ParseErrorTest,MultipleParseErrors)1319 TEST_F(ParseErrorTest, MultipleParseErrors) {
1320 // When a statement has a parse error, the parser should be able to continue
1321 // parsing at the next statement.
1322 ExpectHasErrors(
1323 "message TestMessage {\n"
1324 " optional int32 foo;\n"
1325 " !invalid statement ending in a block { blah blah { blah } blah }\n"
1326 " optional int32 bar = 3 {}\n"
1327 "}\n",
1328 "1:20: Missing field number.\n"
1329 "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
1330 "2:2: Expected type name.\n"
1331 "3:25: Expected \";\".\n");
1332 }
1333
TEST_F(ParseErrorTest,EofInAggregateValue)1334 TEST_F(ParseErrorTest, EofInAggregateValue) {
1335 ExpectHasErrors(
1336 "option (fileopt) = { i:100\n",
1337 "1:0: Unexpected end of stream while parsing aggregate value.\n");
1338 }
1339
TEST_F(ParseErrorTest,ExplicitOptionalLabelProto3)1340 TEST_F(ParseErrorTest, ExplicitOptionalLabelProto3) {
1341 ExpectHasErrors(
1342 "syntax = 'proto3';\n"
1343 "message TestMessage {\n"
1344 " optional int32 foo = 1;\n"
1345 "}\n",
1346 "2:11: Explicit 'optional' labels are disallowed in the Proto3 syntax. "
1347 "To define 'optional' fields in Proto3, simply remove the 'optional' "
1348 "label, as fields are 'optional' by default.\n");
1349 }
1350
1351
1352 // -------------------------------------------------------------------
1353 // Enum errors
1354
TEST_F(ParseErrorTest,EofInEnum)1355 TEST_F(ParseErrorTest, EofInEnum) {
1356 ExpectHasErrors(
1357 "enum TestEnum {",
1358 "0:15: Reached end of input in enum definition (missing '}').\n");
1359 }
1360
TEST_F(ParseErrorTest,EnumValueMissingNumber)1361 TEST_F(ParseErrorTest, EnumValueMissingNumber) {
1362 ExpectHasErrors(
1363 "enum TestEnum {\n"
1364 " FOO;\n"
1365 "}\n",
1366 "1:5: Missing numeric value for enum constant.\n");
1367 }
1368
1369 // -------------------------------------------------------------------
1370 // Reserved field number errors
1371
TEST_F(ParseErrorTest,ReservedMaxNotAllowed)1372 TEST_F(ParseErrorTest, ReservedMaxNotAllowed) {
1373 ExpectHasErrors(
1374 "message Foo {\n"
1375 " reserved 10 to max;\n"
1376 "}\n",
1377 "1:17: Expected integer.\n");
1378 }
1379
TEST_F(ParseErrorTest,ReservedMixNameAndNumber)1380 TEST_F(ParseErrorTest, ReservedMixNameAndNumber) {
1381 ExpectHasErrors(
1382 "message Foo {\n"
1383 " reserved 10, \"foo\";\n"
1384 "}\n",
1385 "1:15: Expected field number range.\n");
1386 }
1387
TEST_F(ParseErrorTest,ReservedMissingQuotes)1388 TEST_F(ParseErrorTest, ReservedMissingQuotes) {
1389 ExpectHasErrors(
1390 "message Foo {\n"
1391 " reserved foo;\n"
1392 "}\n",
1393 "1:11: Expected field name or number range.\n");
1394 }
1395
1396 // -------------------------------------------------------------------
1397 // Service errors
1398
TEST_F(ParseErrorTest,EofInService)1399 TEST_F(ParseErrorTest, EofInService) {
1400 ExpectHasErrors(
1401 "service TestService {",
1402 "0:21: Reached end of input in service definition (missing '}').\n");
1403 }
1404
TEST_F(ParseErrorTest,ServiceMethodPrimitiveParams)1405 TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
1406 ExpectHasErrors(
1407 "service TestService {\n"
1408 " rpc Foo(int32) returns (string);\n"
1409 "}\n",
1410 "1:10: Expected message type.\n"
1411 "1:26: Expected message type.\n");
1412 }
1413
1414
TEST_F(ParseErrorTest,EofInMethodOptions)1415 TEST_F(ParseErrorTest, EofInMethodOptions) {
1416 ExpectHasErrors(
1417 "service TestService {\n"
1418 " rpc Foo(Bar) returns(Bar) {",
1419 "1:29: Reached end of input in method options (missing '}').\n"
1420 "1:29: Reached end of input in service definition (missing '}').\n");
1421 }
1422
1423
TEST_F(ParseErrorTest,PrimitiveMethodInput)1424 TEST_F(ParseErrorTest, PrimitiveMethodInput) {
1425 ExpectHasErrors(
1426 "service TestService {\n"
1427 " rpc Foo(int32) returns(Bar);\n"
1428 "}\n",
1429 "1:10: Expected message type.\n");
1430 }
1431
1432
TEST_F(ParseErrorTest,MethodOptionTypeError)1433 TEST_F(ParseErrorTest, MethodOptionTypeError) {
1434 // This used to cause an infinite loop.
1435 ExpectHasErrors(
1436 "message Baz {}\n"
1437 "service Foo {\n"
1438 " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
1439 "}\n",
1440 "2:45: Expected \"=\".\n");
1441 }
1442
1443
1444 // -------------------------------------------------------------------
1445 // Import and package errors
1446
TEST_F(ParseErrorTest,ImportNotQuoted)1447 TEST_F(ParseErrorTest, ImportNotQuoted) {
1448 ExpectHasErrors(
1449 "import foo;\n",
1450 "0:7: Expected a string naming the file to import.\n");
1451 }
1452
TEST_F(ParseErrorTest,MultiplePackagesInFile)1453 TEST_F(ParseErrorTest, MultiplePackagesInFile) {
1454 ExpectHasErrors(
1455 "package foo;\n"
1456 "package bar;\n",
1457 "1:0: Multiple package definitions.\n");
1458 }
1459
1460 // ===================================================================
1461 // Test that errors detected by DescriptorPool correctly report line and
1462 // column numbers. We have one test for every call to RecordLocation() in
1463 // parser.cc.
1464
1465 typedef ParserTest ParserValidationErrorTest;
1466
TEST_F(ParserValidationErrorTest,PackageNameError)1467 TEST_F(ParserValidationErrorTest, PackageNameError) {
1468 // Create another file which defines symbol "foo".
1469 FileDescriptorProto other_file;
1470 other_file.set_name("bar.proto");
1471 other_file.add_message_type()->set_name("foo");
1472 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1473
1474 // Now try to define it as a package.
1475 ExpectHasValidationErrors(
1476 "package foo.bar;",
1477 "0:8: \"foo\" is already defined (as something other than a package) "
1478 "in file \"bar.proto\".\n");
1479 }
1480
TEST_F(ParserValidationErrorTest,MessageNameError)1481 TEST_F(ParserValidationErrorTest, MessageNameError) {
1482 ExpectHasValidationErrors(
1483 "message Foo {}\n"
1484 "message Foo {}\n",
1485 "1:8: \"Foo\" is already defined.\n");
1486 }
1487
TEST_F(ParserValidationErrorTest,FieldNameError)1488 TEST_F(ParserValidationErrorTest, FieldNameError) {
1489 ExpectHasValidationErrors(
1490 "message Foo {\n"
1491 " optional int32 bar = 1;\n"
1492 " optional int32 bar = 2;\n"
1493 "}\n",
1494 "2:17: \"bar\" is already defined in \"Foo\".\n");
1495 }
1496
TEST_F(ParserValidationErrorTest,FieldTypeError)1497 TEST_F(ParserValidationErrorTest, FieldTypeError) {
1498 ExpectHasValidationErrors(
1499 "message Foo {\n"
1500 " optional Baz bar = 1;\n"
1501 "}\n",
1502 "1:11: \"Baz\" is not defined.\n");
1503 }
1504
TEST_F(ParserValidationErrorTest,FieldNumberError)1505 TEST_F(ParserValidationErrorTest, FieldNumberError) {
1506 ExpectHasValidationErrors(
1507 "message Foo {\n"
1508 " optional int32 bar = 0;\n"
1509 "}\n",
1510 "1:23: Field numbers must be positive integers.\n");
1511 }
1512
TEST_F(ParserValidationErrorTest,FieldExtendeeError)1513 TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
1514 ExpectHasValidationErrors(
1515 "extend Baz { optional int32 bar = 1; }\n",
1516 "0:7: \"Baz\" is not defined.\n");
1517 }
1518
TEST_F(ParserValidationErrorTest,FieldDefaultValueError)1519 TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
1520 ExpectHasValidationErrors(
1521 "enum Baz { QUX = 1; }\n"
1522 "message Foo {\n"
1523 " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
1524 "}\n",
1525 "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
1526 }
1527
TEST_F(ParserValidationErrorTest,FileOptionNameError)1528 TEST_F(ParserValidationErrorTest, FileOptionNameError) {
1529 ExpectHasValidationErrors(
1530 "option foo = 5;",
1531 "0:7: Option \"foo\" unknown.\n");
1532 }
1533
TEST_F(ParserValidationErrorTest,FileOptionValueError)1534 TEST_F(ParserValidationErrorTest, FileOptionValueError) {
1535 ExpectHasValidationErrors(
1536 "option java_outer_classname = 5;",
1537 "0:30: Value must be quoted string for string option "
1538 "\"google.protobuf.FileOptions.java_outer_classname\".\n");
1539 }
1540
TEST_F(ParserValidationErrorTest,FieldOptionNameError)1541 TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
1542 ExpectHasValidationErrors(
1543 "message Foo {\n"
1544 " optional bool bar = 1 [foo=1];\n"
1545 "}\n",
1546 "1:25: Option \"foo\" unknown.\n");
1547 }
1548
TEST_F(ParserValidationErrorTest,FieldOptionValueError)1549 TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
1550 ExpectHasValidationErrors(
1551 "message Foo {\n"
1552 " optional int32 bar = 1 [ctype=1];\n"
1553 "}\n",
1554 "1:32: Value must be identifier for enum-valued option "
1555 "\"google.protobuf.FieldOptions.ctype\".\n");
1556 }
1557
TEST_F(ParserValidationErrorTest,ExtensionRangeNumberError)1558 TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
1559 ExpectHasValidationErrors(
1560 "message Foo {\n"
1561 " extensions 0;\n"
1562 "}\n",
1563 "1:13: Extension numbers must be positive integers.\n");
1564 }
1565
TEST_F(ParserValidationErrorTest,EnumNameError)1566 TEST_F(ParserValidationErrorTest, EnumNameError) {
1567 ExpectHasValidationErrors(
1568 "enum Foo {A = 1;}\n"
1569 "enum Foo {B = 1;}\n",
1570 "1:5: \"Foo\" is already defined.\n");
1571 }
1572
TEST_F(ParserValidationErrorTest,EnumValueNameError)1573 TEST_F(ParserValidationErrorTest, EnumValueNameError) {
1574 ExpectHasValidationErrors(
1575 "enum Foo {\n"
1576 " BAR = 1;\n"
1577 " BAR = 1;\n"
1578 "}\n",
1579 "2:2: \"BAR\" is already defined.\n");
1580 }
1581
TEST_F(ParserValidationErrorTest,ServiceNameError)1582 TEST_F(ParserValidationErrorTest, ServiceNameError) {
1583 ExpectHasValidationErrors(
1584 "service Foo {}\n"
1585 "service Foo {}\n",
1586 "1:8: \"Foo\" is already defined.\n");
1587 }
1588
TEST_F(ParserValidationErrorTest,MethodNameError)1589 TEST_F(ParserValidationErrorTest, MethodNameError) {
1590 ExpectHasValidationErrors(
1591 "message Baz {}\n"
1592 "service Foo {\n"
1593 " rpc Bar(Baz) returns(Baz);\n"
1594 " rpc Bar(Baz) returns(Baz);\n"
1595 "}\n",
1596 "3:6: \"Bar\" is already defined in \"Foo\".\n");
1597 }
1598
1599
TEST_F(ParserValidationErrorTest,MethodInputTypeError)1600 TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
1601 ExpectHasValidationErrors(
1602 "message Baz {}\n"
1603 "service Foo {\n"
1604 " rpc Bar(Qux) returns(Baz);\n"
1605 "}\n",
1606 "2:10: \"Qux\" is not defined.\n");
1607 }
1608
1609
TEST_F(ParserValidationErrorTest,MethodOutputTypeError)1610 TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
1611 ExpectHasValidationErrors(
1612 "message Baz {}\n"
1613 "service Foo {\n"
1614 " rpc Bar(Baz) returns(Qux);\n"
1615 "}\n",
1616 "2:23: \"Qux\" is not defined.\n");
1617 }
1618
1619
TEST_F(ParserValidationErrorTest,ResovledUndefinedError)1620 TEST_F(ParserValidationErrorTest, ResovledUndefinedError) {
1621 // Create another file which defines symbol ".base.bar".
1622 FileDescriptorProto other_file;
1623 other_file.set_name("base.proto");
1624 other_file.set_package("base");
1625 other_file.add_message_type()->set_name("bar");
1626 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1627
1628 // Define "foo.base" and try "base.bar".
1629 // "base.bar" is resolved to "foo.base.bar" which is not defined.
1630 ExpectHasValidationErrors(
1631 "package foo.base;\n"
1632 "import \"base.proto\";\n"
1633 "message qux {\n"
1634 " optional base.bar baz = 1;\n"
1635 " optional .base.bar quz = 2;\n"
1636 "}\n",
1637 "3:11: \"base.bar\" is resolved to \"foo.base.bar\","
1638 " which is not defined. The innermost scope is searched first "
1639 "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")"
1640 " to start from the outermost scope.\n");
1641 }
1642
TEST_F(ParserValidationErrorTest,ResovledUndefinedOptionError)1643 TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) {
1644 // Build descriptor message in test pool
1645 FileDescriptorProto descriptor_proto;
1646 DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto);
1647 ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != NULL);
1648
1649 // base2.proto:
1650 // package baz
1651 // import google/protobuf/descriptor.proto
1652 // message Bar { optional int32 foo = 1; }
1653 // extend FileOptions { optional Bar bar = 7672757; }
1654 FileDescriptorProto other_file;
1655 other_file.set_name("base2.proto");
1656 other_file.set_package("baz");
1657 other_file.add_dependency();
1658 other_file.set_dependency(0, descriptor_proto.name());
1659
1660 DescriptorProto* message(other_file.add_message_type());
1661 message->set_name("Bar");
1662 FieldDescriptorProto* field(message->add_field());
1663 field->set_name("foo");
1664 field->set_number(1);
1665 field->set_label(FieldDescriptorProto_Label_LABEL_OPTIONAL);
1666 field->set_type(FieldDescriptorProto_Type_TYPE_INT32);
1667
1668 FieldDescriptorProto* extension(other_file.add_extension());
1669 extension->set_name("bar");
1670 extension->set_number(7672757);
1671 extension->set_label(FieldDescriptorProto_Label_LABEL_OPTIONAL);
1672 extension->set_type(FieldDescriptorProto_Type_TYPE_MESSAGE);
1673 extension->set_type_name("Bar");
1674 extension->set_extendee("google.protobuf.FileOptions");
1675
1676 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1677
1678 // qux.proto:
1679 // package qux.baz
1680 // option (baz.bar).foo = 1;
1681 //
1682 // Although "baz.bar" is already defined, the lookup code will try
1683 // "qux.baz.bar", since it's the match from the innermost scope,
1684 // which will cause a symbol not defined error.
1685 ExpectHasValidationErrors(
1686 "package qux.baz;\n"
1687 "import \"base2.proto\";\n"
1688 "option (baz.bar).foo = 1;\n",
1689 "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\","
1690 " which is not defined. The innermost scope is searched first "
1691 "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")"
1692 " to start from the outermost scope.\n");
1693 }
1694
1695 // ===================================================================
1696 // Test that the output from FileDescriptor::DebugString() (and all other
1697 // descriptor types) is parseable, and results in the same Descriptor
1698 // definitions again afoter parsing (note, however, that the order of messages
1699 // cannot be guaranteed to be the same)
1700
1701 typedef ParserTest ParseDescriptorDebugTest;
1702
1703 class CompareDescriptorNames {
1704 public:
operator ()(const DescriptorProto * left,const DescriptorProto * right) const1705 bool operator()(const DescriptorProto* left,
1706 const DescriptorProto* right) const {
1707 return left->name() < right->name();
1708 }
1709 };
1710
1711 // Sorts nested DescriptorProtos of a DescriptoProto, by name.
SortMessages(DescriptorProto * descriptor_proto)1712 void SortMessages(DescriptorProto *descriptor_proto) {
1713 int size = descriptor_proto->nested_type_size();
1714 // recursively sort; we can't guarantee the order of nested messages either
1715 for (int i = 0; i < size; ++i) {
1716 SortMessages(descriptor_proto->mutable_nested_type(i));
1717 }
1718 DescriptorProto **data =
1719 descriptor_proto->mutable_nested_type()->mutable_data();
1720 std::sort(data, data + size, CompareDescriptorNames());
1721 }
1722
1723 // Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
SortMessages(FileDescriptorProto * file_descriptor_proto)1724 void SortMessages(FileDescriptorProto *file_descriptor_proto) {
1725 int size = file_descriptor_proto->message_type_size();
1726 // recursively sort; we can't guarantee the order of nested messages either
1727 for (int i = 0; i < size; ++i) {
1728 SortMessages(file_descriptor_proto->mutable_message_type(i));
1729 }
1730 DescriptorProto **data =
1731 file_descriptor_proto->mutable_message_type()->mutable_data();
1732 std::sort(data, data + size, CompareDescriptorNames());
1733 }
1734
1735 // Strips the message and enum field type names for comparison purpose only.
StripFieldTypeName(DescriptorProto * proto)1736 void StripFieldTypeName(DescriptorProto* proto) {
1737 for (int i = 0; i < proto->field_size(); ++i) {
1738 string type_name = proto->field(i).type_name();
1739 string::size_type pos = type_name.find_last_of(".");
1740 if (pos != string::npos) {
1741 proto->mutable_field(i)->mutable_type_name()->assign(
1742 type_name.begin() + pos + 1, type_name.end());
1743 }
1744 }
1745 for (int i = 0; i < proto->nested_type_size(); ++i) {
1746 StripFieldTypeName(proto->mutable_nested_type(i));
1747 }
1748 }
1749
StripFieldTypeName(FileDescriptorProto * file_proto)1750 void StripFieldTypeName(FileDescriptorProto* file_proto) {
1751 for (int i = 0; i < file_proto->message_type_size(); ++i) {
1752 StripFieldTypeName(file_proto->mutable_message_type(i));
1753 }
1754 }
1755
TEST_F(ParseDescriptorDebugTest,TestAllDescriptorTypes)1756 TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) {
1757 const FileDescriptor* original_file =
1758 protobuf_unittest::TestAllTypes::descriptor()->file();
1759 FileDescriptorProto expected;
1760 original_file->CopyTo(&expected);
1761
1762 // Get the DebugString of the unittest.proto FileDecriptor, which includes
1763 // all other descriptor types
1764 string debug_string = original_file->DebugString();
1765
1766 // Parse the debug string
1767 SetupParser(debug_string.c_str());
1768 FileDescriptorProto parsed;
1769 parser_->Parse(input_.get(), &parsed);
1770 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1771 ASSERT_EQ("", error_collector_.text_)
1772 << "Failed to parse:\n" << debug_string;
1773
1774 // We now have a FileDescriptorProto, but to compare with the expected we
1775 // need to link to a FileDecriptor, then output back to a proto. We'll
1776 // also need to give it the same name as the original.
1777 parsed.set_name("google/protobuf/unittest.proto");
1778 // We need the imported dependency before we can build our parsed proto
1779 const FileDescriptor* public_import =
1780 protobuf_unittest_import::PublicImportMessage::descriptor()->file();
1781 FileDescriptorProto public_import_proto;
1782 public_import->CopyTo(&public_import_proto);
1783 ASSERT_TRUE(pool_.BuildFile(public_import_proto) != NULL);
1784 const FileDescriptor* import =
1785 protobuf_unittest_import::ImportMessage::descriptor()->file();
1786 FileDescriptorProto import_proto;
1787 import->CopyTo(&import_proto);
1788 ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
1789 const FileDescriptor* actual = pool_.BuildFile(parsed);
1790 parsed.Clear();
1791 ASSERT_TRUE(actual != NULL)
1792 << "Failed to validate:\n" << debug_string;
1793 actual->CopyTo(&parsed);
1794 ASSERT_TRUE(actual != NULL);
1795
1796 // The messages might be in different orders, making them hard to compare.
1797 // So, sort the messages in the descriptor protos (including nested messages,
1798 // recursively).
1799 SortMessages(&expected);
1800 SortMessages(&parsed);
1801
1802 // I really wanted to use StringDiff here for the debug output on fail,
1803 // but the strings are too long for it, and if I increase its max size,
1804 // we get a memory allocation failure :(
1805 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
1806 }
1807
TEST_F(ParseDescriptorDebugTest,TestCustomOptions)1808 TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
1809 const FileDescriptor* original_file =
1810 protobuf_unittest::AggregateMessage::descriptor()->file();
1811 FileDescriptorProto expected;
1812 original_file->CopyTo(&expected);
1813
1814 string debug_string = original_file->DebugString();
1815
1816 // Parse the debug string
1817 SetupParser(debug_string.c_str());
1818 FileDescriptorProto parsed;
1819 parser_->Parse(input_.get(), &parsed);
1820 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1821 ASSERT_EQ("", error_collector_.text_);
1822
1823 // We now have a FileDescriptorProto, but to compare with the expected we
1824 // need to link to a FileDecriptor, then output back to a proto. We'll
1825 // also need to give it the same name as the original.
1826 parsed.set_name(original_file->name());
1827
1828 // unittest_custom_options.proto depends on descriptor.proto.
1829 const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
1830 FileDescriptorProto import_proto;
1831 import->CopyTo(&import_proto);
1832 ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
1833 const FileDescriptor* actual = pool_.BuildFile(parsed);
1834 ASSERT_TRUE(actual != NULL);
1835 parsed.Clear();
1836 actual->CopyTo(&parsed);
1837
1838 // The messages might be in different orders, making them hard to compare.
1839 // So, sort the messages in the descriptor protos (including nested messages,
1840 // recursively).
1841 SortMessages(&expected);
1842 SortMessages(&parsed);
1843
1844 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
1845 }
1846
1847 // Ensure that DebugStringWithOptions(), with |include_comments| set to true,
1848 // includes comments from the original parser input in all of the appropriate
1849 // places.
TEST_F(ParseDescriptorDebugTest,TestCommentsInDebugString)1850 TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
1851 SetupParser(
1852 "// Detached comment before syntax.\n"
1853 "\n"
1854 "// Syntax comment.\n"
1855 "syntax = \"proto2\";\n"
1856 "\n"
1857 "// Detached comment before package.\n"
1858 "\n"
1859 "// Package comment.\n"
1860 "package comment_test;\n"
1861 "\n"
1862 "// Detached comment before TestMessage1.\n"
1863 "\n"
1864 "// Message comment.\n"
1865 "//\n"
1866 "// More detail in message comment.\n"
1867 "message TestMessage1 {\n"
1868 "\n"
1869 " // Detached comment before foo.\n"
1870 "\n"
1871 " // Field comment.\n"
1872 " optional int32 foo = 1;\n"
1873 "\n"
1874 " // Detached comment before NestedMessage.\n"
1875 "\n"
1876 " // Nested-message comment.\n"
1877 " message NestedMessage {\n"
1878 " optional int32 bar = 1;\n"
1879 " }\n"
1880 "}\n"
1881 "\n"
1882 "// Detached comment before MyEnumType.\n"
1883 "\n"
1884 "// Enum comment.\n"
1885 "enum MyEnumType {\n"
1886 "\n"
1887 " // Detached comment before ASDF.\n"
1888 "\n"
1889 " // Enum-value comment.\n"
1890 " ASDF = 1;\n"
1891 "}\n"
1892 "\n"
1893 "// Detached comment before MyService.\n"
1894 "\n"
1895 "// Service comment.\n"
1896 "service MyService {\n"
1897 "\n"
1898 " // Detached comment before MyRPCCall.\n"
1899 "\n"
1900 " // RPC comment.\n"
1901 " rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
1902 "}\n");
1903
1904 FileDescriptorProto parsed_desc;
1905 parsed_desc.set_name("foo.proto");
1906 SourceLocationTable source_locations;
1907 parser_->RecordSourceLocationsTo(&source_locations);
1908 parser_->Parse(input_.get(), &parsed_desc);
1909 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1910 ASSERT_EQ("", error_collector_.text_);
1911
1912 // We need to import the FileDescriptorProto to get a FileDescriptor.
1913 MockValidationErrorCollector collector(source_locations, &error_collector_);
1914 const FileDescriptor* descriptor =
1915 pool_.BuildFileCollectingErrors(parsed_desc, &collector);
1916 ASSERT_TRUE(descriptor != NULL);
1917
1918 // Ensure that each of the comments appears somewhere in the DebugString().
1919 // We don't test the exact comment placement or formatting, because we do not
1920 // want to be too fragile here.
1921 const char* expected_comments[] = {
1922 "Detached comment before syntax.",
1923 "Syntax comment.",
1924 "Detached comment before package.",
1925 "Package comment.",
1926 "Detached comment before TestMessage1.",
1927 "Message comment.",
1928 "More detail in message comment.",
1929 "Detached comment before foo.",
1930 "Field comment",
1931 "Detached comment before NestedMessage.",
1932 "Nested-message comment",
1933 "Detached comment before MyEnumType.",
1934 "Enum comment",
1935 "Detached comment before ASDF.",
1936 "Enum-value comment",
1937 "Detached comment before MyService.",
1938 "Service comment",
1939 "Detached comment before MyRPCCall.",
1940 "RPC comment",
1941 };
1942
1943 DebugStringOptions debug_string_options;
1944 debug_string_options.include_comments = true;
1945
1946 {
1947 const string debug_string =
1948 descriptor->DebugStringWithOptions(debug_string_options);
1949
1950 for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
1951 string::size_type found_pos = debug_string.find(expected_comments[i]);
1952 EXPECT_TRUE(found_pos != string::npos)
1953 << "\"" << expected_comments[i] << "\" not found.";
1954 }
1955
1956 // Result of DebugStringWithOptions should be parseable.
1957 SetupParser(debug_string.c_str());
1958 FileDescriptorProto parsed;
1959 parser_->Parse(input_.get(), &parsed);
1960 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1961 ASSERT_EQ("", error_collector_.text_)
1962 << "Failed to parse:\n" << debug_string;
1963 }
1964
1965 }
1966
TEST_F(ParseDescriptorDebugTest,TestMaps)1967 TEST_F(ParseDescriptorDebugTest, TestMaps) {
1968 SetupParser(
1969 "syntax = \"proto3\"; "
1970 "message Foo { "
1971 " message Bar { } "
1972 " map<int32, Bar> enum_message_map = 1; "
1973 " map<string, float> primitive_map = 2; "
1974 "} ");
1975 FileDescriptorProto original;
1976 EXPECT_TRUE(parser_->Parse(input_.get(), &original));
1977 original.set_name("foo.proto");
1978 const FileDescriptor* file = pool_.BuildFile(original);
1979 ASSERT_TRUE(file != NULL);
1980
1981 // Make sure the debug string uses map syntax and does not have the auto
1982 // generated entry.
1983 string debug_string = file->DebugString();
1984 EXPECT_TRUE(debug_string.find("map<") != string::npos);
1985 EXPECT_TRUE(debug_string.find("option map_entry") == string::npos);
1986 EXPECT_TRUE(debug_string.find("MapEntry") == string::npos);
1987
1988 // Make sure the descriptor debug string is parsable.
1989 FileDescriptorProto parsed;
1990 SetupParser(debug_string.c_str());
1991 parsed.set_name("foo.proto");
1992 ASSERT_TRUE(parser_->Parse(input_.get(), &parsed));
1993
1994 original.clear_source_code_info();
1995 parsed.clear_source_code_info();
1996 StripFieldTypeName(&original);
1997 StripFieldTypeName(&parsed);
1998 EXPECT_EQ(original.DebugString(), parsed.DebugString());
1999 }
2000
2001 // ===================================================================
2002 // SourceCodeInfo tests.
2003
2004 // Follows a path -- as defined by SourceCodeInfo.Location.path -- from a
2005 // message to a particular sub-field.
2006 // * If the target is itself a message, sets *output_message to point at it,
2007 // *output_field to NULL, and *output_index to -1.
2008 // * Otherwise, if the target is an element of a repeated field, sets
2009 // *output_message to the containing message, *output_field to the descriptor
2010 // of the field, and *output_index to the index of the element.
2011 // * Otherwise, the target is a field (possibly a repeated field, but not any
2012 // one element). Sets *output_message to the containing message,
2013 // *output_field to the descriptor of the field, and *output_index to -1.
2014 // Returns true if the path was valid, false otherwise. A gTest failure is
2015 // recorded before returning false.
FollowPath(const Message & root,const int * path_begin,const int * path_end,const Message ** output_message,const FieldDescriptor ** output_field,int * output_index)2016 bool FollowPath(const Message& root,
2017 const int* path_begin, const int* path_end,
2018 const Message** output_message,
2019 const FieldDescriptor** output_field,
2020 int* output_index) {
2021 if (path_begin == path_end) {
2022 // Path refers to this whole message.
2023 *output_message = &root;
2024 *output_field = NULL;
2025 *output_index = -1;
2026 return true;
2027 }
2028
2029 const Descriptor* descriptor = root.GetDescriptor();
2030 const Reflection* reflection = root.GetReflection();
2031
2032 const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
2033
2034 if (field == NULL) {
2035 ADD_FAILURE() << descriptor->name() << " has no field number: "
2036 << *path_begin;
2037 return false;
2038 }
2039
2040 ++path_begin;
2041
2042 if (field->is_repeated()) {
2043 if (path_begin == path_end) {
2044 // Path refers to the whole repeated field.
2045 *output_message = &root;
2046 *output_field = field;
2047 *output_index = -1;
2048 return true;
2049 }
2050
2051 int index = *path_begin++;
2052 int size = reflection->FieldSize(root, field);
2053
2054 if (index >= size) {
2055 ADD_FAILURE() << descriptor->name() << "." << field->name()
2056 << " has size " << size << ", but path contained index: "
2057 << index;
2058 return false;
2059 }
2060
2061 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2062 // Descend into child message.
2063 const Message& child = reflection->GetRepeatedMessage(root, field, index);
2064 return FollowPath(child, path_begin, path_end,
2065 output_message, output_field, output_index);
2066 } else if (path_begin == path_end) {
2067 // Path refers to this element.
2068 *output_message = &root;
2069 *output_field = field;
2070 *output_index = index;
2071 return true;
2072 } else {
2073 ADD_FAILURE() << descriptor->name() << "." << field->name()
2074 << " is not a message; cannot descend into it.";
2075 return false;
2076 }
2077 } else {
2078 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2079 const Message& child = reflection->GetMessage(root, field);
2080 return FollowPath(child, path_begin, path_end,
2081 output_message, output_field, output_index);
2082 } else if (path_begin == path_end) {
2083 // Path refers to this field.
2084 *output_message = &root;
2085 *output_field = field;
2086 *output_index = -1;
2087 return true;
2088 } else {
2089 ADD_FAILURE() << descriptor->name() << "." << field->name()
2090 << " is not a message; cannot descend into it.";
2091 return false;
2092 }
2093 }
2094 }
2095
2096 // Check if two spans are equal.
CompareSpans(const RepeatedField<int> & span1,const RepeatedField<int> & span2)2097 bool CompareSpans(const RepeatedField<int>& span1,
2098 const RepeatedField<int>& span2) {
2099 if (span1.size() != span2.size()) return false;
2100 for (int i = 0; i < span1.size(); i++) {
2101 if (span1.Get(i) != span2.Get(i)) return false;
2102 }
2103 return true;
2104 }
2105
2106 // Test fixture for source info tests, which check that source locations are
2107 // recorded correctly in FileDescriptorProto.source_code_info.location.
2108 class SourceInfoTest : public ParserTest {
2109 protected:
2110 // The parsed file (initialized by Parse()).
2111 FileDescriptorProto file_;
2112
2113 // Parse the given text as a .proto file and populate the spans_ map with
2114 // all the source location spans in its SourceCodeInfo table.
Parse(const char * text)2115 bool Parse(const char* text) {
2116 ExtractMarkers(text);
2117 SetupParser(text_without_markers_.c_str());
2118 if (!parser_->Parse(input_.get(), &file_)) {
2119 return false;
2120 }
2121
2122 const SourceCodeInfo& source_info = file_.source_code_info();
2123 for (int i = 0; i < source_info.location_size(); i++) {
2124 const SourceCodeInfo::Location& location = source_info.location(i);
2125 const Message* descriptor_proto = NULL;
2126 const FieldDescriptor* field = NULL;
2127 int index = 0;
2128 if (!FollowPath(file_, location.path().begin(), location.path().end(),
2129 &descriptor_proto, &field, &index)) {
2130 return false;
2131 }
2132
2133 spans_.insert(
2134 std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
2135 }
2136
2137 return true;
2138 }
2139
TearDown()2140 virtual void TearDown() {
2141 EXPECT_TRUE(spans_.empty())
2142 << "Forgot to call HasSpan() for:\n"
2143 << spans_.begin()->second->DebugString();
2144 }
2145
2146 // -----------------------------------------------------------------
2147 // HasSpan() checks that the span of source code delimited by the given
2148 // tags (comments) correspond via the SourceCodeInfo table to the given
2149 // part of the FileDescriptorProto. (If unclear, look at the actual tests;
2150 // it should quickly become obvious.)
2151
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto)2152 bool HasSpan(char start_marker, char end_marker,
2153 const Message& descriptor_proto) {
2154 return HasSpanWithComment(
2155 start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL, NULL);
2156 }
2157
HasSpanWithComment(char start_marker,char end_marker,const Message & descriptor_proto,const char * expected_leading_comments,const char * expected_trailing_comments,const char * expected_leading_detached_comments)2158 bool HasSpanWithComment(char start_marker, char end_marker,
2159 const Message& descriptor_proto,
2160 const char* expected_leading_comments,
2161 const char* expected_trailing_comments,
2162 const char* expected_leading_detached_comments) {
2163 return HasSpanWithComment(
2164 start_marker, end_marker, descriptor_proto, NULL, -1,
2165 expected_leading_comments, expected_trailing_comments,
2166 expected_leading_detached_comments);
2167 }
2168
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto,const string & field_name)2169 bool HasSpan(char start_marker, char end_marker,
2170 const Message& descriptor_proto, const string& field_name) {
2171 return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1);
2172 }
2173
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto,const string & field_name,int index)2174 bool HasSpan(char start_marker, char end_marker,
2175 const Message& descriptor_proto, const string& field_name,
2176 int index) {
2177 return HasSpan(start_marker, end_marker, descriptor_proto,
2178 field_name, index, NULL, NULL, NULL);
2179 }
2180
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto,const string & field_name,int index,const char * expected_leading_comments,const char * expected_trailing_comments,const char * expected_leading_detached_comments)2181 bool HasSpan(char start_marker, char end_marker,
2182 const Message& descriptor_proto,
2183 const string& field_name, int index,
2184 const char* expected_leading_comments,
2185 const char* expected_trailing_comments,
2186 const char* expected_leading_detached_comments) {
2187 const FieldDescriptor* field =
2188 descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
2189 if (field == NULL) {
2190 ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
2191 << " has no such field: " << field_name;
2192 return false;
2193 }
2194
2195 return HasSpanWithComment(
2196 start_marker, end_marker, descriptor_proto, field, index,
2197 expected_leading_comments, expected_trailing_comments,
2198 expected_leading_detached_comments);
2199 }
2200
HasSpan(const Message & descriptor_proto)2201 bool HasSpan(const Message& descriptor_proto) {
2202 return HasSpanWithComment(
2203 '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL, NULL);
2204 }
2205
HasSpan(const Message & descriptor_proto,const string & field_name)2206 bool HasSpan(const Message& descriptor_proto, const string& field_name) {
2207 return HasSpan('\0', '\0', descriptor_proto, field_name, -1);
2208 }
2209
HasSpan(const Message & descriptor_proto,const string & field_name,int index)2210 bool HasSpan(const Message& descriptor_proto, const string& field_name,
2211 int index) {
2212 return HasSpan('\0', '\0', descriptor_proto, field_name, index);
2213 }
2214
HasSpanWithComment(char start_marker,char end_marker,const Message & descriptor_proto,const FieldDescriptor * field,int index,const char * expected_leading_comments,const char * expected_trailing_comments,const char * expected_leading_detached_comments)2215 bool HasSpanWithComment(
2216 char start_marker, char end_marker, const Message& descriptor_proto,
2217 const FieldDescriptor* field, int index,
2218 const char* expected_leading_comments,
2219 const char* expected_trailing_comments,
2220 const char* expected_leading_detached_comments) {
2221 pair<SpanMap::iterator, SpanMap::iterator> range =
2222 spans_.equal_range(SpanKey(descriptor_proto, field, index));
2223
2224 if (start_marker == '\0') {
2225 if (range.first == range.second) {
2226 return false;
2227 } else {
2228 spans_.erase(range.first);
2229 return true;
2230 }
2231 } else {
2232 pair<int, int> start_pos = FindOrDie(markers_, start_marker);
2233 pair<int, int> end_pos = FindOrDie(markers_, end_marker);
2234
2235 RepeatedField<int> expected_span;
2236 expected_span.Add(start_pos.first);
2237 expected_span.Add(start_pos.second);
2238 if (end_pos.first != start_pos.first) {
2239 expected_span.Add(end_pos.first);
2240 }
2241 expected_span.Add(end_pos.second);
2242
2243 for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
2244 if (CompareSpans(expected_span, iter->second->span())) {
2245 if (expected_leading_comments == NULL) {
2246 EXPECT_FALSE(iter->second->has_leading_comments());
2247 } else {
2248 EXPECT_TRUE(iter->second->has_leading_comments());
2249 EXPECT_EQ(expected_leading_comments,
2250 iter->second->leading_comments());
2251 }
2252 if (expected_trailing_comments == NULL) {
2253 EXPECT_FALSE(iter->second->has_trailing_comments());
2254 } else {
2255 EXPECT_TRUE(iter->second->has_trailing_comments());
2256 EXPECT_EQ(expected_trailing_comments,
2257 iter->second->trailing_comments());
2258 }
2259 if (expected_leading_detached_comments == NULL) {
2260 EXPECT_EQ(0, iter->second->leading_detached_comments_size());
2261 } else {
2262 EXPECT_EQ(
2263 expected_leading_detached_comments,
2264 Join(iter->second->leading_detached_comments(), "\n"));
2265 }
2266
2267 spans_.erase(iter);
2268 return true;
2269 }
2270 }
2271
2272 return false;
2273 }
2274 }
2275
2276 private:
2277 struct SpanKey {
2278 const Message* descriptor_proto;
2279 const FieldDescriptor* field;
2280 int index;
2281
SpanKeygoogle::protobuf::compiler::__anona16890470111::SourceInfoTest::SpanKey2282 inline SpanKey() {}
SpanKeygoogle::protobuf::compiler::__anona16890470111::SourceInfoTest::SpanKey2283 inline SpanKey(const Message& descriptor_proto_param,
2284 const FieldDescriptor* field_param,
2285 int index_param)
2286 : descriptor_proto(&descriptor_proto_param), field(field_param),
2287 index(index_param) {}
2288
operator <google::protobuf::compiler::__anona16890470111::SourceInfoTest::SpanKey2289 inline bool operator<(const SpanKey& other) const {
2290 if (descriptor_proto < other.descriptor_proto) return true;
2291 if (descriptor_proto > other.descriptor_proto) return false;
2292 if (field < other.field) return true;
2293 if (field > other.field) return false;
2294 return index < other.index;
2295 }
2296 };
2297
2298 typedef multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
2299 SpanMap spans_;
2300 map<char, pair<int, int> > markers_;
2301 string text_without_markers_;
2302
ExtractMarkers(const char * text)2303 void ExtractMarkers(const char* text) {
2304 markers_.clear();
2305 text_without_markers_.clear();
2306 int line = 0;
2307 int column = 0;
2308 while (*text != '\0') {
2309 if (*text == '$') {
2310 ++text;
2311 GOOGLE_CHECK_NE('\0', *text);
2312 if (*text == '$') {
2313 text_without_markers_ += '$';
2314 ++column;
2315 } else {
2316 markers_[*text] = std::make_pair(line, column);
2317 ++text;
2318 GOOGLE_CHECK_EQ('$', *text);
2319 }
2320 } else if (*text == '\n') {
2321 ++line;
2322 column = 0;
2323 text_without_markers_ += *text;
2324 } else {
2325 text_without_markers_ += *text;
2326 ++column;
2327 }
2328 ++text;
2329 }
2330 }
2331 };
2332
TEST_F(SourceInfoTest,BasicFileDecls)2333 TEST_F(SourceInfoTest, BasicFileDecls) {
2334 EXPECT_TRUE(Parse(
2335 "$a$syntax = \"proto2\";$i$\n"
2336 "package $b$foo.bar$c$;\n"
2337 "import $d$\"baz.proto\"$e$;\n"
2338 "import $f$\"qux.proto\"$g$;$h$\n"
2339 "\n"
2340 "// comment ignored\n"));
2341
2342 EXPECT_TRUE(HasSpan('a', 'h', file_));
2343 EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
2344 EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
2345 EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
2346 EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
2347 }
2348
TEST_F(SourceInfoTest,Messages)2349 TEST_F(SourceInfoTest, Messages) {
2350 EXPECT_TRUE(Parse(
2351 "$a$message $b$Foo$c$ {}$d$\n"
2352 "$e$message $f$Bar$g$ {}$h$\n"));
2353
2354 EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0)));
2355 EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name"));
2356 EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1)));
2357 EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name"));
2358
2359 // Ignore these.
2360 EXPECT_TRUE(HasSpan(file_));
2361 }
2362
TEST_F(SourceInfoTest,Fields)2363 TEST_F(SourceInfoTest, Fields) {
2364 EXPECT_TRUE(Parse(
2365 "message Foo {\n"
2366 " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
2367 " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
2368 "}\n"));
2369
2370 const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
2371 const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
2372
2373 EXPECT_TRUE(HasSpan('a', 'i', field1));
2374 EXPECT_TRUE(HasSpan('a', 'b', field1, "label"));
2375 EXPECT_TRUE(HasSpan('c', 'd', field1, "type"));
2376 EXPECT_TRUE(HasSpan('e', 'f', field1, "name"));
2377 EXPECT_TRUE(HasSpan('g', 'h', field1, "number"));
2378
2379 EXPECT_TRUE(HasSpan('j', 'r', field2));
2380 EXPECT_TRUE(HasSpan('j', 'k', field2, "label"));
2381 EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name"));
2382 EXPECT_TRUE(HasSpan('n', 'o', field2, "name"));
2383 EXPECT_TRUE(HasSpan('p', 'q', field2, "number"));
2384
2385 // Ignore these.
2386 EXPECT_TRUE(HasSpan(file_));
2387 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2388 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2389 }
2390
TEST_F(SourceInfoTest,Extensions)2391 TEST_F(SourceInfoTest, Extensions) {
2392 EXPECT_TRUE(Parse(
2393 "$a$extend $b$Foo$c$ {\n"
2394 " $d$optional$e$ int32 bar = 1;$f$\n"
2395 " $g$repeated$h$ X.Y baz = 2;$i$\n"
2396 "}$j$\n"
2397 "$k$extend $l$Bar$m$ {\n"
2398 " $n$optional int32 qux = 1;$o$\n"
2399 "}$p$\n"));
2400
2401 const FieldDescriptorProto& field1 = file_.extension(0);
2402 const FieldDescriptorProto& field2 = file_.extension(1);
2403 const FieldDescriptorProto& field3 = file_.extension(2);
2404
2405 EXPECT_TRUE(HasSpan('a', 'j', file_, "extension"));
2406 EXPECT_TRUE(HasSpan('k', 'p', file_, "extension"));
2407
2408 EXPECT_TRUE(HasSpan('d', 'f', field1));
2409 EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
2410 EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
2411
2412 EXPECT_TRUE(HasSpan('g', 'i', field2));
2413 EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
2414 EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
2415
2416 EXPECT_TRUE(HasSpan('n', 'o', field3));
2417 EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
2418
2419 // Ignore these.
2420 EXPECT_TRUE(HasSpan(file_));
2421 EXPECT_TRUE(HasSpan(field1, "type"));
2422 EXPECT_TRUE(HasSpan(field1, "name"));
2423 EXPECT_TRUE(HasSpan(field1, "number"));
2424 EXPECT_TRUE(HasSpan(field2, "type_name"));
2425 EXPECT_TRUE(HasSpan(field2, "name"));
2426 EXPECT_TRUE(HasSpan(field2, "number"));
2427 EXPECT_TRUE(HasSpan(field3, "label"));
2428 EXPECT_TRUE(HasSpan(field3, "type"));
2429 EXPECT_TRUE(HasSpan(field3, "name"));
2430 EXPECT_TRUE(HasSpan(field3, "number"));
2431 }
2432
TEST_F(SourceInfoTest,NestedExtensions)2433 TEST_F(SourceInfoTest, NestedExtensions) {
2434 EXPECT_TRUE(Parse(
2435 "message Message {\n"
2436 " $a$extend $b$Foo$c$ {\n"
2437 " $d$optional$e$ int32 bar = 1;$f$\n"
2438 " $g$repeated$h$ X.Y baz = 2;$i$\n"
2439 " }$j$\n"
2440 " $k$extend $l$Bar$m$ {\n"
2441 " $n$optional int32 qux = 1;$o$\n"
2442 " }$p$\n"
2443 "}\n"));
2444
2445 const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
2446 const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
2447 const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
2448
2449 EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension"));
2450 EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension"));
2451
2452 EXPECT_TRUE(HasSpan('d', 'f', field1));
2453 EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
2454 EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
2455
2456 EXPECT_TRUE(HasSpan('g', 'i', field2));
2457 EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
2458 EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
2459
2460 EXPECT_TRUE(HasSpan('n', 'o', field3));
2461 EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
2462
2463 // Ignore these.
2464 EXPECT_TRUE(HasSpan(file_));
2465 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2466 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2467 EXPECT_TRUE(HasSpan(field1, "type"));
2468 EXPECT_TRUE(HasSpan(field1, "name"));
2469 EXPECT_TRUE(HasSpan(field1, "number"));
2470 EXPECT_TRUE(HasSpan(field2, "type_name"));
2471 EXPECT_TRUE(HasSpan(field2, "name"));
2472 EXPECT_TRUE(HasSpan(field2, "number"));
2473 EXPECT_TRUE(HasSpan(field3, "label"));
2474 EXPECT_TRUE(HasSpan(field3, "type"));
2475 EXPECT_TRUE(HasSpan(field3, "name"));
2476 EXPECT_TRUE(HasSpan(field3, "number"));
2477 }
2478
TEST_F(SourceInfoTest,ExtensionRanges)2479 TEST_F(SourceInfoTest, ExtensionRanges) {
2480 EXPECT_TRUE(Parse(
2481 "message Message {\n"
2482 " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
2483 " $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
2484 "}\n"));
2485
2486 const DescriptorProto::ExtensionRange& range1 =
2487 file_.message_type(0).extension_range(0);
2488 const DescriptorProto::ExtensionRange& range2 =
2489 file_.message_type(0).extension_range(1);
2490 const DescriptorProto::ExtensionRange& range3 =
2491 file_.message_type(0).extension_range(2);
2492
2493 EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range"));
2494 EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range"));
2495
2496 EXPECT_TRUE(HasSpan('b', 'e', range1));
2497 EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
2498 EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
2499
2500 EXPECT_TRUE(HasSpan('f', 'g', range2));
2501 EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
2502 EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
2503
2504 EXPECT_TRUE(HasSpan('j', 'm', range3));
2505 EXPECT_TRUE(HasSpan('j', 'k', range3, "start"));
2506 EXPECT_TRUE(HasSpan('l', 'm', range3, "end"));
2507
2508 // Ignore these.
2509 EXPECT_TRUE(HasSpan(file_));
2510 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2511 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2512 }
2513
TEST_F(SourceInfoTest,Oneofs)2514 TEST_F(SourceInfoTest, Oneofs) {
2515 EXPECT_TRUE(Parse(
2516 "message Foo {\n"
2517 " $a$oneof $c$foo$d$ {\n"
2518 " $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n"
2519 " }$r$\n"
2520 "}\n"));
2521
2522 const OneofDescriptorProto& oneof_decl = file_.message_type(0).oneof_decl(0);
2523 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2524
2525 EXPECT_TRUE(HasSpan('a', 'r', oneof_decl));
2526 EXPECT_TRUE(HasSpan('c', 'd', oneof_decl, "name"));
2527
2528 EXPECT_TRUE(HasSpan('e', 'k', field));
2529 EXPECT_TRUE(HasSpan('e', 'f', field, "type"));
2530 EXPECT_TRUE(HasSpan('g', 'h', field, "name"));
2531 EXPECT_TRUE(HasSpan('i', 'j', field, "number"));
2532
2533 // Ignore these.
2534 EXPECT_TRUE(HasSpan(file_));
2535 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2536 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2537 }
2538
TEST_F(SourceInfoTest,NestedMessages)2539 TEST_F(SourceInfoTest, NestedMessages) {
2540 EXPECT_TRUE(Parse(
2541 "message Foo {\n"
2542 " $a$message $b$Bar$c$ {\n"
2543 " $d$message $e$Baz$f$ {}$g$\n"
2544 " }$h$\n"
2545 " $i$message $j$Qux$k$ {}$l$\n"
2546 "}\n"));
2547
2548 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
2549 const DescriptorProto& baz = bar.nested_type(0);
2550 const DescriptorProto& qux = file_.message_type(0).nested_type(1);
2551
2552 EXPECT_TRUE(HasSpan('a', 'h', bar));
2553 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
2554 EXPECT_TRUE(HasSpan('d', 'g', baz));
2555 EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
2556 EXPECT_TRUE(HasSpan('i', 'l', qux));
2557 EXPECT_TRUE(HasSpan('j', 'k', qux, "name"));
2558
2559 // Ignore these.
2560 EXPECT_TRUE(HasSpan(file_));
2561 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2562 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2563 }
2564
TEST_F(SourceInfoTest,Groups)2565 TEST_F(SourceInfoTest, Groups) {
2566 EXPECT_TRUE(Parse(
2567 "message Foo {\n"
2568 " message Bar {}\n"
2569 " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
2570 " $i$message Qux {}$j$\n"
2571 " }$k$\n"
2572 "}\n"));
2573
2574 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
2575 const DescriptorProto& baz = file_.message_type(0).nested_type(1);
2576 const DescriptorProto& qux = baz.nested_type(0);
2577 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2578
2579 EXPECT_TRUE(HasSpan('a', 'k', field));
2580 EXPECT_TRUE(HasSpan('a', 'b', field, "label"));
2581 EXPECT_TRUE(HasSpan('c', 'd', field, "type"));
2582 EXPECT_TRUE(HasSpan('e', 'f', field, "name"));
2583 EXPECT_TRUE(HasSpan('e', 'f', field, "type_name"));
2584 EXPECT_TRUE(HasSpan('g', 'h', field, "number"));
2585
2586 EXPECT_TRUE(HasSpan('a', 'k', baz));
2587 EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
2588 EXPECT_TRUE(HasSpan('i', 'j', qux));
2589
2590 // Ignore these.
2591 EXPECT_TRUE(HasSpan(file_));
2592 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2593 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2594 EXPECT_TRUE(HasSpan(bar));
2595 EXPECT_TRUE(HasSpan(bar, "name"));
2596 EXPECT_TRUE(HasSpan(qux, "name"));
2597 }
2598
TEST_F(SourceInfoTest,Enums)2599 TEST_F(SourceInfoTest, Enums) {
2600 EXPECT_TRUE(Parse(
2601 "$a$enum $b$Foo$c$ {}$d$\n"
2602 "$e$enum $f$Bar$g$ {}$h$\n"));
2603
2604 EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0)));
2605 EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name"));
2606 EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1)));
2607 EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name"));
2608
2609 // Ignore these.
2610 EXPECT_TRUE(HasSpan(file_));
2611 }
2612
TEST_F(SourceInfoTest,EnumValues)2613 TEST_F(SourceInfoTest, EnumValues) {
2614 EXPECT_TRUE(Parse(
2615 "enum Foo {\n"
2616 " $a$BAR$b$ = $c$1$d$;$e$\n"
2617 " $f$BAZ$g$ = $h$2$i$;$j$\n"
2618 "}"));
2619
2620 const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
2621 const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
2622
2623 EXPECT_TRUE(HasSpan('a', 'e', bar));
2624 EXPECT_TRUE(HasSpan('a', 'b', bar, "name"));
2625 EXPECT_TRUE(HasSpan('c', 'd', bar, "number"));
2626 EXPECT_TRUE(HasSpan('f', 'j', baz));
2627 EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
2628 EXPECT_TRUE(HasSpan('h', 'i', baz, "number"));
2629
2630 // Ignore these.
2631 EXPECT_TRUE(HasSpan(file_));
2632 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2633 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2634 }
2635
TEST_F(SourceInfoTest,NestedEnums)2636 TEST_F(SourceInfoTest, NestedEnums) {
2637 EXPECT_TRUE(Parse(
2638 "message Foo {\n"
2639 " $a$enum $b$Bar$c$ {}$d$\n"
2640 " $e$enum $f$Baz$g$ {}$h$\n"
2641 "}\n"));
2642
2643 const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
2644 const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
2645
2646 EXPECT_TRUE(HasSpan('a', 'd', bar));
2647 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
2648 EXPECT_TRUE(HasSpan('e', 'h', baz));
2649 EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
2650
2651 // Ignore these.
2652 EXPECT_TRUE(HasSpan(file_));
2653 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2654 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2655 }
2656
TEST_F(SourceInfoTest,Services)2657 TEST_F(SourceInfoTest, Services) {
2658 EXPECT_TRUE(Parse(
2659 "$a$service $b$Foo$c$ {}$d$\n"
2660 "$e$service $f$Bar$g$ {}$h$\n"));
2661
2662 EXPECT_TRUE(HasSpan('a', 'd', file_.service(0)));
2663 EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name"));
2664 EXPECT_TRUE(HasSpan('e', 'h', file_.service(1)));
2665 EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name"));
2666
2667 // Ignore these.
2668 EXPECT_TRUE(HasSpan(file_));
2669 }
2670
TEST_F(SourceInfoTest,MethodsAndStreams)2671 TEST_F(SourceInfoTest, MethodsAndStreams) {
2672 EXPECT_TRUE(Parse(
2673 "service Foo {\n"
2674 " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
2675 " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
2676 "}"));
2677
2678 const MethodDescriptorProto& bar = file_.service(0).method(0);
2679 const MethodDescriptorProto& baz = file_.service(0).method(1);
2680
2681 EXPECT_TRUE(HasSpan('a', 'h', bar));
2682 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
2683 EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type"));
2684 EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type"));
2685
2686 EXPECT_TRUE(HasSpan('i', 'p', baz));
2687 EXPECT_TRUE(HasSpan('j', 'k', baz, "name"));
2688 EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type"));
2689 EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type"));
2690
2691 // Ignore these.
2692 EXPECT_TRUE(HasSpan(file_));
2693 EXPECT_TRUE(HasSpan(file_.service(0)));
2694 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
2695 }
2696
2697
TEST_F(SourceInfoTest,Options)2698 TEST_F(SourceInfoTest, Options) {
2699 EXPECT_TRUE(Parse(
2700 "$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
2701 "$h$123$i$;$j$\n"
2702 "$k$option qux = $l$-123$m$;$n$\n"
2703 "$o$option corge = $p$abc$q$;$r$\n"
2704 "$s$option grault = $t$'blah'$u$;$v$\n"
2705 "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
2706 "$0$option waldo = $1$123.0$2$;$3$\n"
2707 ));
2708
2709 const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
2710 const UninterpretedOption& option2 = file_.options().uninterpreted_option(1);
2711 const UninterpretedOption& option3 = file_.options().uninterpreted_option(2);
2712 const UninterpretedOption& option4 = file_.options().uninterpreted_option(3);
2713 const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
2714 const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
2715
2716 EXPECT_TRUE(HasSpan('a', 'j', file_.options()));
2717 EXPECT_TRUE(HasSpan('a', 'j', option1));
2718 EXPECT_TRUE(HasSpan('b', 'g', option1, "name"));
2719 EXPECT_TRUE(HasSpan('b', 'c', option1.name(0)));
2720 EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part"));
2721 EXPECT_TRUE(HasSpan('d', 'g', option1.name(1)));
2722 EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part"));
2723 EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value"));
2724
2725 EXPECT_TRUE(HasSpan('k', 'n', file_.options()));
2726 EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value"));
2727
2728 EXPECT_TRUE(HasSpan('o', 'r', file_.options()));
2729 EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value"));
2730
2731 EXPECT_TRUE(HasSpan('s', 'v', file_.options()));
2732 EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value"));
2733
2734 EXPECT_TRUE(HasSpan('w', 'z', file_.options()));
2735 EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value"));
2736
2737 EXPECT_TRUE(HasSpan('0', '3', file_.options()));
2738 EXPECT_TRUE(HasSpan('1', '2', option6, "double_value"));
2739
2740 // Ignore these.
2741 EXPECT_TRUE(HasSpan(file_));
2742 EXPECT_TRUE(HasSpan(option2));
2743 EXPECT_TRUE(HasSpan(option3));
2744 EXPECT_TRUE(HasSpan(option4));
2745 EXPECT_TRUE(HasSpan(option5));
2746 EXPECT_TRUE(HasSpan(option6));
2747 EXPECT_TRUE(HasSpan(option2, "name"));
2748 EXPECT_TRUE(HasSpan(option3, "name"));
2749 EXPECT_TRUE(HasSpan(option4, "name"));
2750 EXPECT_TRUE(HasSpan(option5, "name"));
2751 EXPECT_TRUE(HasSpan(option6, "name"));
2752 EXPECT_TRUE(HasSpan(option2.name(0)));
2753 EXPECT_TRUE(HasSpan(option3.name(0)));
2754 EXPECT_TRUE(HasSpan(option4.name(0)));
2755 EXPECT_TRUE(HasSpan(option5.name(0)));
2756 EXPECT_TRUE(HasSpan(option6.name(0)));
2757 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2758 EXPECT_TRUE(HasSpan(option3.name(0), "name_part"));
2759 EXPECT_TRUE(HasSpan(option4.name(0), "name_part"));
2760 EXPECT_TRUE(HasSpan(option5.name(0), "name_part"));
2761 EXPECT_TRUE(HasSpan(option6.name(0), "name_part"));
2762 }
2763
TEST_F(SourceInfoTest,ScopedOptions)2764 TEST_F(SourceInfoTest, ScopedOptions) {
2765 EXPECT_TRUE(Parse(
2766 "message Foo {\n"
2767 " $a$option mopt = 1;$b$\n"
2768 "}\n"
2769 "enum Bar {\n"
2770 " $c$option eopt = 1;$d$\n"
2771 "}\n"
2772 "service Baz {\n"
2773 " $e$option sopt = 1;$f$\n"
2774 " rpc M(X) returns(Y) {\n"
2775 " $g$option mopt = 1;$h$\n"
2776 " }\n"
2777 " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
2778 " $k$option mopt = 1;$l$\n"
2779 " }\n"
2780 "}\n"));
2781
2782 EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
2783 EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options()));
2784 EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options()));
2785 EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options()));
2786
2787 // Ignore these.
2788 EXPECT_TRUE(HasSpan(file_));
2789 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2790 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2791 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2792 .uninterpreted_option(0)));
2793 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2794 .uninterpreted_option(0), "name"));
2795 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2796 .uninterpreted_option(0).name(0)));
2797 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2798 .uninterpreted_option(0).name(0), "name_part"));
2799 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2800 .uninterpreted_option(0), "positive_int_value"));
2801 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2802 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2803 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2804 .uninterpreted_option(0)));
2805 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2806 .uninterpreted_option(0), "name"));
2807 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2808 .uninterpreted_option(0).name(0)));
2809 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2810 .uninterpreted_option(0).name(0), "name_part"));
2811 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2812 .uninterpreted_option(0), "positive_int_value"));
2813 EXPECT_TRUE(HasSpan(file_.service(0)));
2814 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
2815 EXPECT_TRUE(HasSpan(file_.service(0).method(0)));
2816 EXPECT_TRUE(HasSpan(file_.service(0).options()
2817 .uninterpreted_option(0)));
2818 EXPECT_TRUE(HasSpan(file_.service(0).options()
2819 .uninterpreted_option(0), "name"));
2820 EXPECT_TRUE(HasSpan(file_.service(0).options()
2821 .uninterpreted_option(0).name(0)));
2822 EXPECT_TRUE(HasSpan(file_.service(0).options()
2823 .uninterpreted_option(0).name(0), "name_part"));
2824 EXPECT_TRUE(HasSpan(file_.service(0).options()
2825 .uninterpreted_option(0), "positive_int_value"));
2826 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name"));
2827 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type"));
2828 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type"));
2829 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2830 .uninterpreted_option(0)));
2831 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2832 .uninterpreted_option(0), "name"));
2833 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2834 .uninterpreted_option(0).name(0)));
2835 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2836 .uninterpreted_option(0).name(0), "name_part"));
2837 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2838 .uninterpreted_option(0), "positive_int_value"));
2839
2840 EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
2841 EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
2842 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
2843 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
2844 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
2845 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2846 .uninterpreted_option(0)));
2847 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2848 .uninterpreted_option(0), "name"));
2849 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2850 .uninterpreted_option(0).name(0)));
2851 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2852 .uninterpreted_option(0).name(0), "name_part"));
2853 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2854 .uninterpreted_option(0), "positive_int_value"));
2855 EXPECT_TRUE(HasSpan('1', '2', file_.service(0).method(1),
2856 "client_streaming"));
2857 EXPECT_TRUE(HasSpan('3', '4', file_.service(0).method(1),
2858 "server_streaming"));
2859 }
2860
TEST_F(SourceInfoTest,FieldOptions)2861 TEST_F(SourceInfoTest, FieldOptions) {
2862 // The actual "name = value" pairs are parsed by the same code as for
2863 // top-level options so we won't re-test that -- just make sure that the
2864 // syntax used for field options is understood.
2865 EXPECT_TRUE(Parse(
2866 "message Foo {"
2867 " optional int32 bar = 1 "
2868 "$a$[default=$b$123$c$,$d$opt1=123$e$,"
2869 "$f$opt2='hi'$g$]$h$;"
2870 "}\n"
2871 ));
2872
2873 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2874 const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
2875 const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
2876
2877 EXPECT_TRUE(HasSpan('a', 'h', field.options()));
2878 EXPECT_TRUE(HasSpan('b', 'c', field, "default_value"));
2879 EXPECT_TRUE(HasSpan('d', 'e', option1));
2880 EXPECT_TRUE(HasSpan('f', 'g', option2));
2881
2882 // Ignore these.
2883 EXPECT_TRUE(HasSpan(file_));
2884 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2885 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2886 EXPECT_TRUE(HasSpan(field));
2887 EXPECT_TRUE(HasSpan(field, "label"));
2888 EXPECT_TRUE(HasSpan(field, "type"));
2889 EXPECT_TRUE(HasSpan(field, "name"));
2890 EXPECT_TRUE(HasSpan(field, "number"));
2891 EXPECT_TRUE(HasSpan(option1, "name"));
2892 EXPECT_TRUE(HasSpan(option2, "name"));
2893 EXPECT_TRUE(HasSpan(option1.name(0)));
2894 EXPECT_TRUE(HasSpan(option2.name(0)));
2895 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
2896 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2897 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
2898 EXPECT_TRUE(HasSpan(option2, "string_value"));
2899 }
2900
TEST_F(SourceInfoTest,EnumValueOptions)2901 TEST_F(SourceInfoTest, EnumValueOptions) {
2902 // The actual "name = value" pairs are parsed by the same code as for
2903 // top-level options so we won't re-test that -- just make sure that the
2904 // syntax used for enum options is understood.
2905 EXPECT_TRUE(Parse(
2906 "enum Foo {"
2907 " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
2908 "}\n"
2909 ));
2910
2911 const EnumValueDescriptorProto& value = file_.enum_type(0).value(0);
2912 const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
2913 const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
2914
2915 EXPECT_TRUE(HasSpan('a', 'f', value.options()));
2916 EXPECT_TRUE(HasSpan('b', 'c', option1));
2917 EXPECT_TRUE(HasSpan('d', 'e', option2));
2918
2919 // Ignore these.
2920 EXPECT_TRUE(HasSpan(file_));
2921 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2922 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2923 EXPECT_TRUE(HasSpan(value));
2924 EXPECT_TRUE(HasSpan(value, "name"));
2925 EXPECT_TRUE(HasSpan(value, "number"));
2926 EXPECT_TRUE(HasSpan(option1, "name"));
2927 EXPECT_TRUE(HasSpan(option2, "name"));
2928 EXPECT_TRUE(HasSpan(option1.name(0)));
2929 EXPECT_TRUE(HasSpan(option2.name(0)));
2930 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
2931 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2932 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
2933 EXPECT_TRUE(HasSpan(option2, "string_value"));
2934 }
2935
TEST_F(SourceInfoTest,DocComments)2936 TEST_F(SourceInfoTest, DocComments) {
2937 EXPECT_TRUE(Parse(
2938 "// Foo leading\n"
2939 "// line 2\n"
2940 "$a$message Foo {\n"
2941 " // Foo trailing\n"
2942 " // line 2\n"
2943 "\n"
2944 " // detached\n"
2945 "\n"
2946 " // bar leading\n"
2947 " $b$optional int32 bar = 1;$c$\n"
2948 " // bar trailing\n"
2949 "}$d$\n"
2950 "// ignored\n"
2951 ));
2952
2953 const DescriptorProto& foo = file_.message_type(0);
2954 const FieldDescriptorProto& bar = foo.field(0);
2955
2956 EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
2957 " Foo leading\n line 2\n",
2958 " Foo trailing\n line 2\n",
2959 NULL));
2960 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
2961 " bar leading\n",
2962 " bar trailing\n",
2963 " detached\n"));
2964
2965 // Ignore these.
2966 EXPECT_TRUE(HasSpan(file_));
2967 EXPECT_TRUE(HasSpan(foo, "name"));
2968 EXPECT_TRUE(HasSpan(bar, "label"));
2969 EXPECT_TRUE(HasSpan(bar, "type"));
2970 EXPECT_TRUE(HasSpan(bar, "name"));
2971 EXPECT_TRUE(HasSpan(bar, "number"));
2972 }
2973
TEST_F(SourceInfoTest,DocComments2)2974 TEST_F(SourceInfoTest, DocComments2) {
2975 EXPECT_TRUE(Parse(
2976 "// detached before message.\n"
2977 "\n"
2978 "// Foo leading\n"
2979 "// line 2\n"
2980 "$a$message Foo {\n"
2981 " /* Foo trailing\n"
2982 " * line 2 */\n"
2983 " // detached\n"
2984 " /* bar leading\n"
2985 " */"
2986 " $b$optional int32 bar = 1;$c$ // bar trailing\n"
2987 " // ignored detached\n"
2988 "}$d$\n"
2989 "// ignored\n"
2990 "\n"
2991 "// detached before option\n"
2992 "\n"
2993 "// option leading\n"
2994 "$e$option baz = 123;$f$\n"
2995 "// option trailing\n"
2996 ));
2997
2998 const DescriptorProto& foo = file_.message_type(0);
2999 const FieldDescriptorProto& bar = foo.field(0);
3000 const UninterpretedOption& baz = file_.options().uninterpreted_option(0);
3001
3002 EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
3003 " Foo leading\n line 2\n",
3004 " Foo trailing\n line 2 ",
3005 " detached before message.\n"));
3006 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
3007 " bar leading\n",
3008 " bar trailing\n",
3009 " detached\n"));
3010 EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
3011 " option leading\n",
3012 " option trailing\n",
3013 " detached before option\n"));
3014
3015 // Ignore these.
3016 EXPECT_TRUE(HasSpan(file_));
3017 EXPECT_TRUE(HasSpan(foo, "name"));
3018 EXPECT_TRUE(HasSpan(bar, "label"));
3019 EXPECT_TRUE(HasSpan(bar, "type"));
3020 EXPECT_TRUE(HasSpan(bar, "name"));
3021 EXPECT_TRUE(HasSpan(bar, "number"));
3022 EXPECT_TRUE(HasSpan(file_.options()));
3023 EXPECT_TRUE(HasSpan(baz, "name"));
3024 EXPECT_TRUE(HasSpan(baz.name(0)));
3025 EXPECT_TRUE(HasSpan(baz.name(0), "name_part"));
3026 EXPECT_TRUE(HasSpan(baz, "positive_int_value"));
3027 }
3028
TEST_F(SourceInfoTest,DocComments3)3029 TEST_F(SourceInfoTest, DocComments3) {
3030 EXPECT_TRUE(Parse(
3031 "$a$message Foo {\n"
3032 " // bar leading\n"
3033 " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
3034 " // bar trailing\n"
3035 "}$d$\n"
3036 "// ignored\n"
3037 ));
3038
3039 const DescriptorProto& foo = file_.message_type(0);
3040 const FieldDescriptorProto& bar = foo.field(0);
3041
3042 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
3043 " bar leading\n",
3044 " bar trailing\n",
3045 NULL));
3046
3047 // Ignore these.
3048 EXPECT_TRUE(HasSpan(file_));
3049 EXPECT_TRUE(HasSpan(foo));
3050 EXPECT_TRUE(HasSpan(foo, "name"));
3051 EXPECT_TRUE(HasSpan(bar, "label"));
3052 EXPECT_TRUE(HasSpan(bar, "type"));
3053 EXPECT_TRUE(HasSpan(bar, "name"));
3054 EXPECT_TRUE(HasSpan(bar, "number"));
3055 EXPECT_TRUE(HasSpan(bar.options()));
3056 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0)));
3057 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name"));
3058 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0)));
3059 EXPECT_TRUE(HasSpan(
3060 bar.options().uninterpreted_option(0).name(0), "name_part"));
3061 EXPECT_TRUE(HasSpan(
3062 bar.options().uninterpreted_option(0), "aggregate_value"));
3063 }
3064
TEST_F(SourceInfoTest,DocCommentsTopLevel)3065 TEST_F(SourceInfoTest, DocCommentsTopLevel) {
3066 EXPECT_TRUE(Parse(
3067 "// detached before syntax paragraph 1\n"
3068 "\n"
3069 "// detached before syntax paragraph 2\n"
3070 "\n"
3071 "// syntax leading\n"
3072 "$a$syntax = \"proto2\";$b$\n"
3073 "// syntax trailing\n"
3074 "\n"
3075 "// syntax-package detached comments\n"
3076 "\n"
3077 ";\n"
3078 "\n"
3079 "// detached after empty before package\n"
3080 "\n"
3081 "// package leading\n"
3082 "package $c$foo$d$;\n"
3083 "// package trailing\n"
3084 "\n"
3085 "// ignored detach\n"
3086 "\n"));
3087
3088 EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1,
3089 " syntax leading\n",
3090 " syntax trailing\n",
3091 " detached before syntax paragraph 1\n"
3092 "\n"
3093 " detached before syntax paragraph 2\n"));
3094 EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1,
3095 " package leading\n",
3096 " package trailing\n",
3097 " syntax-package detached comments\n"
3098 "\n"
3099 " detached after empty before package\n"));
3100
3101 // ignore these.
3102 EXPECT_TRUE(HasSpan(file_));
3103 }
3104
TEST_F(SourceInfoTest,DocCommentsOneof)3105 TEST_F(SourceInfoTest, DocCommentsOneof) {
3106 EXPECT_TRUE(Parse(
3107 "// Foo leading\n"
3108 "$a$message Foo {\n"
3109 " /* Foo trailing\n"
3110 " */\n"
3111 " // detached before oneof\n"
3112 " /* bar leading\n"
3113 " * line 2 */\n"
3114 " $b$oneof bar {\n"
3115 " /* bar trailing\n"
3116 " * line 2 */\n"
3117 " // detached before bar_int\n"
3118 " /* bar_int leading\n"
3119 " */\n"
3120 " $c$int32 bar_int = 1;$d$ // bar_int trailing\n"
3121 " // detach comment ignored\n"
3122 " }$e$\n"
3123 "}$f$\n"));
3124
3125 const DescriptorProto& foo = file_.message_type(0);
3126 const OneofDescriptorProto& bar = foo.oneof_decl(0);
3127 const FieldDescriptorProto& bar_int = foo.field(0);
3128
3129 EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
3130 " Foo leading\n",
3131 " Foo trailing\n",
3132 NULL));
3133 EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
3134 " bar leading\n line 2 ",
3135 " bar trailing\n line 2 ",
3136 " detached before oneof\n"));
3137 EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
3138 " bar_int leading\n",
3139 " bar_int trailing\n",
3140 " detached before bar_int\n"));
3141
3142 // Ignore these.
3143 EXPECT_TRUE(HasSpan(file_));
3144 EXPECT_TRUE(HasSpan(foo, "name"));
3145 EXPECT_TRUE(HasSpan(bar, "name"));
3146 EXPECT_TRUE(HasSpan(bar_int, "type"));
3147 EXPECT_TRUE(HasSpan(bar_int, "name"));
3148 EXPECT_TRUE(HasSpan(bar_int, "number"));
3149 }
3150
3151 // ===================================================================
3152
3153 } // anonymous namespace
3154
3155 } // namespace compiler
3156 } // namespace protobuf
3157 } // namespace google
3158