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