blob: 1684bebed979e8819efb7ae21ef1695b0f78f5de [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
jieluo@google.com4de8f552014-07-18 00:47:59 +000035#include <memory>
Feng Xiao6ef984a2014-11-10 17:34:54 -080036#ifndef _SHARED_PTR_H
37#include <google/protobuf/stubs/shared_ptr.h>
38#endif
temporal40ee5512008-07-10 02:12:20 +000039#include <vector>
40#include <algorithm>
liujisi@google.com33165fe2010-11-02 13:14:58 +000041#include <map>
temporal40ee5512008-07-10 02:12:20 +000042
43#include <google/protobuf/compiler/parser.h>
44
45#include <google/protobuf/io/tokenizer.h>
46#include <google/protobuf/io/zero_copy_stream_impl.h>
47#include <google/protobuf/descriptor.pb.h>
48#include <google/protobuf/wire_format.h>
49#include <google/protobuf/text_format.h>
50#include <google/protobuf/unittest.pb.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000051#include <google/protobuf/unittest_custom_options.pb.h>
temporal40ee5512008-07-10 02:12:20 +000052#include <google/protobuf/stubs/strutil.h>
53#include <google/protobuf/stubs/substitute.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000054#include <google/protobuf/stubs/map_util.h>
temporal40ee5512008-07-10 02:12:20 +000055
56#include <google/protobuf/testing/googletest.h>
57#include <gtest/gtest.h>
58
59namespace google {
60namespace protobuf {
61namespace compiler {
62
63namespace {
64
65class MockErrorCollector : public io::ErrorCollector {
66 public:
67 MockErrorCollector() {}
68 ~MockErrorCollector() {}
69
70 string text_;
71
72 // implements ErrorCollector ---------------------------------------
73 void AddError(int line, int column, const string& message) {
74 strings::SubstituteAndAppend(&text_, "$0:$1: $2\n",
75 line, column, message);
76 }
77};
78
79class MockValidationErrorCollector : public DescriptorPool::ErrorCollector {
80 public:
81 MockValidationErrorCollector(const SourceLocationTable& source_locations,
82 io::ErrorCollector* wrapped_collector)
83 : source_locations_(source_locations),
84 wrapped_collector_(wrapped_collector) {}
85 ~MockValidationErrorCollector() {}
86
87 // implements ErrorCollector ---------------------------------------
88 void AddError(const string& filename,
89 const string& element_name,
90 const Message* descriptor,
91 ErrorLocation location,
92 const string& message) {
93 int line, column;
94 source_locations_.Find(descriptor, location, &line, &column);
95 wrapped_collector_->AddError(line, column, message);
96 }
97
98 private:
99 const SourceLocationTable& source_locations_;
100 io::ErrorCollector* wrapped_collector_;
101};
102
103class ParserTest : public testing::Test {
104 protected:
105 ParserTest()
106 : require_syntax_identifier_(false) {}
107
108 // Set up the parser to parse the given text.
109 void SetupParser(const char* text) {
110 raw_input_.reset(new io::ArrayInputStream(text, strlen(text)));
111 input_.reset(new io::Tokenizer(raw_input_.get(), &error_collector_));
112 parser_.reset(new Parser());
113 parser_->RecordErrorsTo(&error_collector_);
114 parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_);
115 }
116
117 // Parse the input and expect that the resulting FileDescriptorProto matches
118 // the given output. The output is a FileDescriptorProto in protocol buffer
119 // text format.
120 void ExpectParsesTo(const char* input, const char* output) {
121 SetupParser(input);
122 FileDescriptorProto actual, expected;
123
124 parser_->Parse(input_.get(), &actual);
125 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
126 ASSERT_EQ("", error_collector_.text_);
127
liujisi@google.com33165fe2010-11-02 13:14:58 +0000128 // We don't cover SourceCodeInfo in these tests.
129 actual.clear_source_code_info();
130
temporal40ee5512008-07-10 02:12:20 +0000131 // Parse the ASCII representation in order to canonicalize it. We could
132 // just compare directly to actual.DebugString(), but that would require
133 // that the caller precisely match the formatting that DebugString()
134 // produces.
135 ASSERT_TRUE(TextFormat::ParseFromString(output, &expected));
136
137 // Compare by comparing debug strings.
138 // TODO(kenton): Use differencer, once it is available.
139 EXPECT_EQ(expected.DebugString(), actual.DebugString());
140 }
141
142 // Parse the text and expect that the given errors are reported.
143 void ExpectHasErrors(const char* text, const char* expected_errors) {
144 ExpectHasEarlyExitErrors(text, expected_errors);
145 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
146 }
147
148 // Same as above but does not expect that the parser parses the complete
149 // input.
150 void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) {
151 SetupParser(text);
152 FileDescriptorProto file;
153 parser_->Parse(input_.get(), &file);
154 EXPECT_EQ(expected_errors, error_collector_.text_);
155 }
156
157 // Parse the text as a file and validate it (with a DescriptorPool), and
158 // expect that the validation step reports the given errors.
159 void ExpectHasValidationErrors(const char* text,
160 const char* expected_errors) {
161 SetupParser(text);
162 SourceLocationTable source_locations;
163 parser_->RecordSourceLocationsTo(&source_locations);
164
165 FileDescriptorProto file;
166 file.set_name("foo.proto");
167 parser_->Parse(input_.get(), &file);
168 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
169 ASSERT_EQ("", error_collector_.text_);
170
171 MockValidationErrorCollector validation_error_collector(
172 source_locations, &error_collector_);
173 EXPECT_TRUE(pool_.BuildFileCollectingErrors(
174 file, &validation_error_collector) == NULL);
175 EXPECT_EQ(expected_errors, error_collector_.text_);
176 }
177
178 MockErrorCollector error_collector_;
179 DescriptorPool pool_;
180
Feng Xiaof157a562014-11-14 11:50:31 -0800181 google::protobuf::scoped_ptr<io::ZeroCopyInputStream> raw_input_;
182 google::protobuf::scoped_ptr<io::Tokenizer> input_;
183 google::protobuf::scoped_ptr<Parser> parser_;
temporal40ee5512008-07-10 02:12:20 +0000184 bool require_syntax_identifier_;
185};
186
187// ===================================================================
188
kenton@google.comd37d46d2009-04-25 02:53:47 +0000189TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
190 SetupParser(
191 "// blah\n"
192 "syntax = \"foobar\";\n"
193 "this line will not be parsed\n");
194 parser_->SetStopAfterSyntaxIdentifier(true);
195 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
196 EXPECT_EQ("", error_collector_.text_);
197 EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
198}
199
200TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
201 SetupParser(
202 "// blah\n"
203 "this line will not be parsed\n");
204 parser_->SetStopAfterSyntaxIdentifier(true);
205 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
206 EXPECT_EQ("", error_collector_.text_);
207 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
208}
209
210TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
211 SetupParser(
212 "// blah\n"
213 "syntax = error;\n");
214 parser_->SetStopAfterSyntaxIdentifier(true);
215 EXPECT_FALSE(parser_->Parse(input_.get(), NULL));
216 EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
217}
218
Feng Xiao3eb55df2014-11-14 12:41:10 -0800219TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
220 SetupParser("message A {}");
221 FileDescriptorProto file;
222 CaptureTestStderr();
223 EXPECT_TRUE(parser_->Parse(input_.get(), &file));
224 EXPECT_TRUE(
225 GetCapturedTestStderr().find("No syntax specified") != string::npos);
226}
227
kenton@google.comd37d46d2009-04-25 02:53:47 +0000228// ===================================================================
229
temporal40ee5512008-07-10 02:12:20 +0000230typedef ParserTest ParseMessageTest;
231
232TEST_F(ParseMessageTest, SimpleMessage) {
233 ExpectParsesTo(
234 "message TestMessage {\n"
235 " required int32 foo = 1;\n"
236 "}\n",
237
238 "message_type {"
239 " name: \"TestMessage\""
240 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
241 "}");
242}
243
244TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
245 require_syntax_identifier_ = false;
246 ExpectParsesTo(
247 "message TestMessage {\n"
248 " required int32 foo = 1;\n"
249 "}\n",
250
251 "message_type {"
252 " name: \"TestMessage\""
253 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
254 "}");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000255 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000256}
257
258TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
259 ExpectParsesTo(
260 "syntax = \"proto2\";\n"
261 "message TestMessage {\n"
262 " required int32 foo = 1;\n"
263 "}\n",
264
Feng Xiao6ef984a2014-11-10 17:34:54 -0800265 "syntax: 'proto2' "
temporal40ee5512008-07-10 02:12:20 +0000266 "message_type {"
267 " name: \"TestMessage\""
268 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
269 "}");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000270 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000271}
272
273TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
274 require_syntax_identifier_ = true;
275 ExpectParsesTo(
276 "syntax = \"proto2\";\n"
277 "message TestMessage {\n"
278 " required int32 foo = 1;\n"
279 "}\n",
280
Feng Xiao6ef984a2014-11-10 17:34:54 -0800281 "syntax: 'proto2' "
temporal40ee5512008-07-10 02:12:20 +0000282 "message_type {"
283 " name: \"TestMessage\""
284 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
285 "}");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000286 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000287}
288
289TEST_F(ParseMessageTest, SimpleFields) {
290 ExpectParsesTo(
291 "message TestMessage {\n"
292 " required int32 foo = 15;\n"
293 " optional int32 bar = 34;\n"
294 " repeated int32 baz = 3;\n"
295 "}\n",
296
297 "message_type {"
298 " name: \"TestMessage\""
299 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
300 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
301 " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }"
302 "}");
303}
304
305TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
306 ExpectParsesTo(
307 "message TestMessage {\n"
308 " required int32 foo = 1;\n"
309 " required int64 foo = 1;\n"
310 " required uint32 foo = 1;\n"
311 " required uint64 foo = 1;\n"
312 " required sint32 foo = 1;\n"
313 " required sint64 foo = 1;\n"
314 " required fixed32 foo = 1;\n"
315 " required fixed64 foo = 1;\n"
316 " required sfixed32 foo = 1;\n"
317 " required sfixed64 foo = 1;\n"
318 " required float foo = 1;\n"
319 " required double foo = 1;\n"
320 " required string foo = 1;\n"
321 " required bytes foo = 1;\n"
322 " required bool foo = 1;\n"
323 "}\n",
324
325 "message_type {"
326 " name: \"TestMessage\""
327 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
328 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 }"
329 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 }"
330 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 }"
331 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 }"
332 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 }"
333 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 }"
334 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 }"
335 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 }"
336 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 }"
337 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 }"
338 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 }"
339 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 }"
340 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 }"
341 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 }"
342 "}");
343}
344
345TEST_F(ParseMessageTest, FieldDefaults) {
346 ExpectParsesTo(
347 "message TestMessage {\n"
348 " required int32 foo = 1 [default= 1 ];\n"
349 " required int32 foo = 1 [default= -2 ];\n"
350 " required int64 foo = 1 [default= 3 ];\n"
351 " required int64 foo = 1 [default= -4 ];\n"
352 " required uint32 foo = 1 [default= 5 ];\n"
353 " required uint64 foo = 1 [default= 6 ];\n"
354 " required float foo = 1 [default= 7.5];\n"
355 " required float foo = 1 [default= -8.5];\n"
356 " required float foo = 1 [default= 9 ];\n"
357 " required double foo = 1 [default= 10.5];\n"
358 " required double foo = 1 [default=-11.5];\n"
359 " required double foo = 1 [default= 12 ];\n"
kenton@google.comfccb1462009-12-18 02:11:36 +0000360 " required double foo = 1 [default= inf ];\n"
361 " required double foo = 1 [default=-inf ];\n"
362 " required double foo = 1 [default= nan ];\n"
temporal40ee5512008-07-10 02:12:20 +0000363 " required string foo = 1 [default='13\\001'];\n"
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000364 " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
temporal40ee5512008-07-10 02:12:20 +0000365 " required bytes foo = 1 [default='14\\002'];\n"
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000366 " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
temporal40ee5512008-07-10 02:12:20 +0000367 " required bool foo = 1 [default=true ];\n"
368 " required Foo foo = 1 [default=FOO ];\n"
369
370 " required int32 foo = 1 [default= 0x7FFFFFFF];\n"
371 " required int32 foo = 1 [default=-0x80000000];\n"
372 " required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
373 " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
374 " required int64 foo = 1 [default=-0x8000000000000000];\n"
375 " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
376 " required double foo = 1 [default= 0xabcd];\n"
377 "}\n",
378
379#define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
380 "message_type {"
381 " name: \"TestMessage\""
Nobuaki Sukegawa8ba0e352014-11-30 19:42:51 +0900382 " field { type:TYPE_INT32 default_value:\"1\" " ETC " }"
383 " field { type:TYPE_INT32 default_value:\"-2\" " ETC " }"
384 " field { type:TYPE_INT64 default_value:\"3\" " ETC " }"
385 " field { type:TYPE_INT64 default_value:\"-4\" " ETC " }"
386 " field { type:TYPE_UINT32 default_value:\"5\" " ETC " }"
387 " field { type:TYPE_UINT64 default_value:\"6\" " ETC " }"
388 " field { type:TYPE_FLOAT default_value:\"7.5\" " ETC " }"
389 " field { type:TYPE_FLOAT default_value:\"-8.5\" " ETC " }"
390 " field { type:TYPE_FLOAT default_value:\"9\" " ETC " }"
391 " field { type:TYPE_DOUBLE default_value:\"10.5\" " ETC " }"
392 " field { type:TYPE_DOUBLE default_value:\"-11.5\" " ETC " }"
393 " field { type:TYPE_DOUBLE default_value:\"12\" " ETC " }"
394 " field { type:TYPE_DOUBLE default_value:\"inf\" " ETC " }"
395 " field { type:TYPE_DOUBLE default_value:\"-inf\" " ETC " }"
396 " field { type:TYPE_DOUBLE default_value:\"nan\" " ETC " }"
397 " field { type:TYPE_STRING default_value:\"13\\001\" " ETC " }"
398 " field { type:TYPE_STRING default_value:\"abc\" " ETC " }"
399 " field { type:TYPE_BYTES default_value:\"14\\\\002\" " ETC " }"
400 " field { type:TYPE_BYTES default_value:\"abc\" " ETC " }"
401 " field { type:TYPE_BOOL default_value:\"true\" " ETC " }"
402 " field { type_name:\"Foo\" default_value:\"FOO\" " ETC " }"
temporal40ee5512008-07-10 02:12:20 +0000403
Josh Habermancb3caf12015-02-17 18:23:41 -0800404 " field {"
405 " type:TYPE_INT32 default_value:\"2147483647\" " ETC
406 " }"
407 " field {"
408 " type:TYPE_INT32 default_value:\"-2147483648\" " ETC
409 " }"
410 " field {"
411 " type:TYPE_UINT32 default_value:\"4294967295\" " ETC
412 " }"
413 " field {"
414 " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC
415 " }"
416 " field {"
417 " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC
418 " }"
419 " field {"
420 " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC
421 " }"
422 " field {"
423 " type:TYPE_DOUBLE default_value:\"43981\" " ETC
424 " }"
temporal40ee5512008-07-10 02:12:20 +0000425 "}");
426#undef ETC
427}
428
429TEST_F(ParseMessageTest, FieldOptions) {
430 ExpectParsesTo(
431 "message TestMessage {\n"
kenton@google.com24bf56f2008-09-24 20:31:01 +0000432 " optional string foo = 1\n"
433 " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
434 " (quux)=\"x\040y\", (baz.qux)=hey];\n"
temporal40ee5512008-07-10 02:12:20 +0000435 "}\n",
436
437 "message_type {"
438 " name: \"TestMessage\""
kenton@google.com24bf56f2008-09-24 20:31:01 +0000439 " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
440 " options { uninterpreted_option: { name { name_part: \"ctype\" "
441 " is_extension: false } "
442 " identifier_value: \"CORD\" }"
443 " uninterpreted_option: { name { name_part: \"foo\" "
444 " is_extension: true } "
445 " positive_int_value: 7 }"
446 " uninterpreted_option: { name { name_part: \"foo\" "
447 " is_extension: false } "
448 " name { name_part: \".bar.baz\""
449 " is_extension: true } "
450 " name { name_part: \"qux\" "
451 " is_extension: false } "
452 " name { name_part: \"quux\" "
453 " is_extension: false } "
454 " name { name_part: \"corge\" "
455 " is_extension: true } "
456 " negative_int_value: -33 }"
457 " uninterpreted_option: { name { name_part: \"quux\" "
458 " is_extension: true } "
459 " string_value: \"x y\" }"
460 " uninterpreted_option: { name { name_part: \"baz.qux\" "
461 " is_extension: true } "
462 " identifier_value: \"hey\" }"
463 " }"
464 " }"
temporal40ee5512008-07-10 02:12:20 +0000465 "}");
466}
467
jieluo@google.com4de8f552014-07-18 00:47:59 +0000468TEST_F(ParseMessageTest, Oneof) {
469 ExpectParsesTo(
470 "message TestMessage {\n"
471 " oneof foo {\n"
472 " int32 a = 1;\n"
473 " string b = 2;\n"
474 " TestMessage c = 3;\n"
475 " group D = 4 { optional int32 i = 5; }\n"
476 " }\n"
477 "}\n",
478
479 "message_type {"
480 " name: \"TestMessage\""
481 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
482 " oneof_index:0 }"
483 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
484 " oneof_index:0 }"
485 " field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" "
486 " number:3 oneof_index:0 }"
487 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP "
488 " type_name:\"D\" number:4 oneof_index:0 }"
489 " oneof_decl {"
490 " name: \"foo\""
491 " }"
492 " nested_type {"
493 " name: \"D\""
494 " field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }"
495 " }"
496 "}");
497}
498
499TEST_F(ParseMessageTest, MultipleOneofs) {
500 ExpectParsesTo(
501 "message TestMessage {\n"
502 " oneof foo {\n"
503 " int32 a = 1;\n"
504 " string b = 2;\n"
505 " }\n"
506 " oneof bar {\n"
507 " int32 c = 3;\n"
508 " string d = 4;\n"
509 " }\n"
510 "}\n",
511
512 "message_type {"
513 " name: \"TestMessage\""
514 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
515 " oneof_index:0 }"
516 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
517 " oneof_index:0 }"
518 " field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 "
519 " oneof_index:1 }"
520 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 "
521 " oneof_index:1 }"
522 " oneof_decl {"
523 " name: \"foo\""
524 " }"
525 " oneof_decl {"
526 " name: \"bar\""
527 " }"
528 "}");
529}
530
Feng Xiao6ef984a2014-11-10 17:34:54 -0800531TEST_F(ParseMessageTest, Maps) {
532 ExpectParsesTo(
533 "message TestMessage {\n"
534 " map<int32, string> primitive_type_map = 1;\n"
535 " map<KeyType, ValueType> composite_type_map = 2;\n"
536 "}\n",
537
538 "message_type {"
539 " name: \"TestMessage\""
540 " nested_type {"
541 " name: \"PrimitiveTypeMapEntry\""
542 " field { "
543 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
544 " type:TYPE_INT32"
545 " }"
546 " field { "
547 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
548 " type:TYPE_STRING"
549 " }"
550 " options { map_entry: true }"
551 " }"
552 " nested_type {"
553 " name: \"CompositeTypeMapEntry\""
554 " field { "
555 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
556 " type_name: \"KeyType\""
557 " }"
558 " field { "
559 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
560 " type_name: \"ValueType\""
561 " }"
562 " options { map_entry: true }"
563 " }"
564 " field {"
565 " name: \"primitive_type_map\""
566 " label: LABEL_REPEATED"
567 " type_name: \"PrimitiveTypeMapEntry\""
568 " number: 1"
569 " }"
570 " field {"
571 " name: \"composite_type_map\""
572 " label: LABEL_REPEATED"
573 " type_name: \"CompositeTypeMapEntry\""
574 " number: 2"
575 " }"
576 "}");
577}
578
temporal40ee5512008-07-10 02:12:20 +0000579TEST_F(ParseMessageTest, Group) {
580 ExpectParsesTo(
581 "message TestMessage {\n"
582 " optional group TestGroup = 1 {};\n"
583 "}\n",
584
585 "message_type {"
586 " name: \"TestMessage\""
587 " nested_type { name: \"TestGroup\" }"
588 " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
589 " type:TYPE_GROUP type_name: \"TestGroup\" }"
590 "}");
591}
592
593TEST_F(ParseMessageTest, NestedMessage) {
594 ExpectParsesTo(
595 "message TestMessage {\n"
596 " message Nested {}\n"
597 " optional Nested test_nested = 1;\n"
598 "}\n",
599
600 "message_type {"
601 " name: \"TestMessage\""
602 " nested_type { name: \"Nested\" }"
603 " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
604 " type_name: \"Nested\" }"
605 "}");
606}
607
608TEST_F(ParseMessageTest, NestedEnum) {
609 ExpectParsesTo(
610 "message TestMessage {\n"
611 " enum NestedEnum {}\n"
612 " optional NestedEnum test_enum = 1;\n"
613 "}\n",
614
615 "message_type {"
616 " name: \"TestMessage\""
617 " enum_type { name: \"NestedEnum\" }"
618 " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
619 " type_name: \"NestedEnum\" }"
620 "}");
621}
622
623TEST_F(ParseMessageTest, ExtensionRange) {
624 ExpectParsesTo(
625 "message TestMessage {\n"
626 " extensions 10 to 19;\n"
627 " extensions 30 to max;\n"
628 "}\n",
629
630 "message_type {"
631 " name: \"TestMessage\""
632 " extension_range { start:10 end:20 }"
633 " extension_range { start:30 end:536870912 }"
634 "}");
635}
636
637TEST_F(ParseMessageTest, CompoundExtensionRange) {
638 ExpectParsesTo(
639 "message TestMessage {\n"
640 " extensions 2, 15, 9 to 11, 100 to max, 3;\n"
641 "}\n",
642
643 "message_type {"
644 " name: \"TestMessage\""
645 " extension_range { start:2 end:3 }"
646 " extension_range { start:15 end:16 }"
647 " extension_range { start:9 end:12 }"
648 " extension_range { start:100 end:536870912 }"
649 " extension_range { start:3 end:4 }"
650 "}");
651}
652
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000653TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
654 // Messages using the message_set_wire_format option can accept larger
655 // extension numbers, as the numbers are not encoded as int32 field values
656 // rather than tags.
657 ExpectParsesTo(
658 "message TestMessage {\n"
659 " extensions 4 to max;\n"
660 " option message_set_wire_format = true;\n"
661 "}\n",
662
663 "message_type {"
664 " name: \"TestMessage\""
665 " extension_range { start:4 end: 0x7fffffff }"
666 " options {\n"
667 " uninterpreted_option { \n"
668 " name {\n"
669 " name_part: \"message_set_wire_format\"\n"
670 " is_extension: false\n"
671 " }\n"
672 " identifier_value: \"true\"\n"
673 " }\n"
674 " }\n"
675 "}");
676}
677
temporal40ee5512008-07-10 02:12:20 +0000678TEST_F(ParseMessageTest, Extensions) {
679 ExpectParsesTo(
680 "extend Extendee1 { optional int32 foo = 12; }\n"
681 "extend Extendee2 { repeated TestMessage bar = 22; }\n",
682
683 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
684 " extendee: \"Extendee1\" } "
685 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
686 " type_name:\"TestMessage\" extendee: \"Extendee2\" }");
687}
688
689TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
690 ExpectParsesTo(
691 "message TestMessage {\n"
692 " extend Extendee1 { optional int32 foo = 12; }\n"
693 " extend Extendee2 { repeated TestMessage bar = 22; }\n"
694 "}\n",
695
696 "message_type {"
697 " name: \"TestMessage\""
698 " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
699 " extendee: \"Extendee1\" }"
700 " extension { name:\"bar\" label:LABEL_REPEATED number:22"
701 " type_name:\"TestMessage\" extendee: \"Extendee2\" }"
702 "}");
703}
704
705TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
706 ExpectParsesTo(
707 "extend Extendee1 {\n"
708 " optional int32 foo = 12;\n"
709 " repeated TestMessage bar = 22;\n"
710 "}\n",
711
712 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
713 " extendee: \"Extendee1\" } "
714 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
715 " type_name:\"TestMessage\" extendee: \"Extendee1\" }");
716}
717
Feng Xiao6ef984a2014-11-10 17:34:54 -0800718TEST_F(ParseMessageTest, OptionalOptionalLabelProto3) {
719 ExpectParsesTo(
720 "syntax = \"proto3\";\n"
721 "message TestMessage {\n"
722 " int32 foo = 1;\n"
723 " optional int32 bar = 2;\n"
724 "}\n",
725
726 "syntax: \"proto3\" "
727 "message_type {"
728 " name: \"TestMessage\""
729 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
730 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 } }");
731}
jieluo@google.com4de8f552014-07-18 00:47:59 +0000732
temporal40ee5512008-07-10 02:12:20 +0000733// ===================================================================
734
735typedef ParserTest ParseEnumTest;
736
737TEST_F(ParseEnumTest, SimpleEnum) {
738 ExpectParsesTo(
739 "enum TestEnum {\n"
740 " FOO = 0;\n"
741 "}\n",
742
743 "enum_type {"
744 " name: \"TestEnum\""
745 " value { name:\"FOO\" number:0 }"
746 "}");
747}
748
749TEST_F(ParseEnumTest, Values) {
750 ExpectParsesTo(
751 "enum TestEnum {\n"
752 " FOO = 13;\n"
753 " BAR = -10;\n"
754 " BAZ = 500;\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000755 " HEX_MAX = 0x7FFFFFFF;\n"
756 " HEX_MIN = -0x80000000;\n"
757 " INT_MAX = 2147483647;\n"
758 " INT_MIN = -2147483648;\n"
temporal40ee5512008-07-10 02:12:20 +0000759 "}\n",
760
761 "enum_type {"
762 " name: \"TestEnum\""
763 " value { name:\"FOO\" number:13 }"
764 " value { name:\"BAR\" number:-10 }"
765 " value { name:\"BAZ\" number:500 }"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000766 " value { name:\"HEX_MAX\" number:2147483647 }"
767 " value { name:\"HEX_MIN\" number:-2147483648 }"
768 " value { name:\"INT_MAX\" number:2147483647 }"
769 " value { name:\"INT_MIN\" number:-2147483648 }"
temporal40ee5512008-07-10 02:12:20 +0000770 "}");
771}
772
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000773TEST_F(ParseEnumTest, ValueOptions) {
774 ExpectParsesTo(
775 "enum TestEnum {\n"
776 " FOO = 13;\n"
777 " BAR = -10 [ (something.text) = 'abc' ];\n"
778 " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
779 "}\n",
780
781 "enum_type {"
782 " name: \"TestEnum\""
783 " value { name: \"FOO\" number: 13 }"
784 " value { name: \"BAR\" number: -10 "
785 " options { "
786 " uninterpreted_option { "
787 " name { name_part: \"something.text\" is_extension: true } "
788 " string_value: \"abc\" "
789 " } "
790 " } "
791 " } "
792 " value { name: \"BAZ\" number: 500 "
793 " options { "
794 " uninterpreted_option { "
795 " name { name_part: \"something.text\" is_extension: true } "
796 " string_value: \"def\" "
797 " } "
798 " uninterpreted_option { "
799 " name { name_part: \"other\" is_extension: false } "
800 " positive_int_value: 1 "
801 " } "
802 " } "
803 " } "
804 "}");
805}
806
temporal40ee5512008-07-10 02:12:20 +0000807// ===================================================================
808
809typedef ParserTest ParseServiceTest;
810
811TEST_F(ParseServiceTest, SimpleService) {
812 ExpectParsesTo(
813 "service TestService {\n"
814 " rpc Foo(In) returns (Out);\n"
815 "}\n",
816
817 "service {"
818 " name: \"TestService\""
819 " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
820 "}");
821}
822
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000823TEST_F(ParseServiceTest, MethodsAndStreams) {
temporal40ee5512008-07-10 02:12:20 +0000824 ExpectParsesTo(
825 "service TestService {\n"
826 " rpc Foo(In1) returns (Out1);\n"
827 " rpc Bar(In2) returns (Out2);\n"
828 " rpc Baz(In3) returns (Out3);\n"
829 "}\n",
830
831 "service {"
832 " name: \"TestService\""
833 " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
834 " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
835 " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
836 "}");
837}
838
jieluo@google.com4de8f552014-07-18 00:47:59 +0000839
840
temporal40ee5512008-07-10 02:12:20 +0000841// ===================================================================
842// imports and packages
843
844typedef ParserTest ParseMiscTest;
845
846TEST_F(ParseMiscTest, ParseImport) {
847 ExpectParsesTo(
848 "import \"foo/bar/baz.proto\";\n",
849 "dependency: \"foo/bar/baz.proto\"");
850}
851
852TEST_F(ParseMiscTest, ParseMultipleImports) {
853 ExpectParsesTo(
854 "import \"foo.proto\";\n"
855 "import \"bar.proto\";\n"
856 "import \"baz.proto\";\n",
857 "dependency: \"foo.proto\""
858 "dependency: \"bar.proto\""
859 "dependency: \"baz.proto\"");
860}
861
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000862TEST_F(ParseMiscTest, ParsePublicImports) {
863 ExpectParsesTo(
864 "import \"foo.proto\";\n"
865 "import public \"bar.proto\";\n"
866 "import \"baz.proto\";\n"
867 "import public \"qux.proto\";\n",
868 "dependency: \"foo.proto\""
869 "dependency: \"bar.proto\""
870 "dependency: \"baz.proto\""
871 "dependency: \"qux.proto\""
872 "public_dependency: 1 "
873 "public_dependency: 3 ");
874}
875
temporal40ee5512008-07-10 02:12:20 +0000876TEST_F(ParseMiscTest, ParsePackage) {
877 ExpectParsesTo(
878 "package foo.bar.baz;\n",
879 "package: \"foo.bar.baz\"");
880}
881
882TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
883 ExpectParsesTo(
884 "package foo . bar. \n"
885 " baz;\n",
886 "package: \"foo.bar.baz\"");
887}
888
889// ===================================================================
890// options
891
892TEST_F(ParseMiscTest, ParseFileOptions) {
893 ExpectParsesTo(
894 "option java_package = \"com.google.foo\";\n"
895 "option optimize_for = CODE_SIZE;",
896
897 "options {"
kenton@google.com24bf56f2008-09-24 20:31:01 +0000898 "uninterpreted_option { name { name_part: \"java_package\" "
899 " is_extension: false }"
900 " string_value: \"com.google.foo\"} "
901 "uninterpreted_option { name { name_part: \"optimize_for\" "
902 " is_extension: false }"
903 " identifier_value: \"CODE_SIZE\" } "
temporal40ee5512008-07-10 02:12:20 +0000904 "}");
905}
906
temporal40ee5512008-07-10 02:12:20 +0000907// ===================================================================
908// Error tests
909//
910// There are a very large number of possible errors that the parser could
911// report, so it's infeasible to test every single one of them. Instead,
912// we test each unique call to AddError() in parser.h. This does not mean
913// we are testing every possible error that Parser can generate because
914// each variant of the Consume() helper only counts as one unique call to
915// AddError().
916
917typedef ParserTest ParseErrorTest;
918
919TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
920 require_syntax_identifier_ = true;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800921 ExpectHasEarlyExitErrors("message TestMessage {}",
922 "0:0: File must begin with a syntax statement, e.g. "
923 "'syntax = \"proto2\";'.\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000924 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000925}
926
927TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
928 ExpectHasEarlyExitErrors(
929 "syntax = \"no_such_syntax\";",
930 "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
Feng Xiao6ef984a2014-11-10 17:34:54 -0800931 "only recognizes \"proto2\" and \"proto3\".\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000932 EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000933}
934
935TEST_F(ParseErrorTest, SimpleSyntaxError) {
936 ExpectHasErrors(
937 "message TestMessage @#$ { blah }",
938 "0:20: Expected \"{\".\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000939 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000940}
941
942TEST_F(ParseErrorTest, ExpectedTopLevel) {
943 ExpectHasErrors(
944 "blah;",
945 "0:0: Expected top-level statement (e.g. \"message\").\n");
946}
947
948TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
949 // This used to cause an infinite loop. Doh.
950 ExpectHasErrors(
951 "}",
952 "0:0: Expected top-level statement (e.g. \"message\").\n"
953 "0:0: Unmatched \"}\".\n");
954}
955
956// -------------------------------------------------------------------
957// Message errors
958
959TEST_F(ParseErrorTest, MessageMissingName) {
960 ExpectHasErrors(
961 "message {}",
962 "0:8: Expected message name.\n");
963}
964
965TEST_F(ParseErrorTest, MessageMissingBody) {
966 ExpectHasErrors(
967 "message TestMessage;",
968 "0:19: Expected \"{\".\n");
969}
970
971TEST_F(ParseErrorTest, EofInMessage) {
972 ExpectHasErrors(
973 "message TestMessage {",
974 "0:21: Reached end of input in message definition (missing '}').\n");
975}
976
977TEST_F(ParseErrorTest, MissingFieldNumber) {
978 ExpectHasErrors(
979 "message TestMessage {\n"
980 " optional int32 foo;\n"
981 "}\n",
982 "1:20: Missing field number.\n");
983}
984
985TEST_F(ParseErrorTest, ExpectedFieldNumber) {
986 ExpectHasErrors(
987 "message TestMessage {\n"
988 " optional int32 foo = ;\n"
989 "}\n",
990 "1:23: Expected field number.\n");
991}
992
993TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
994 ExpectHasErrors(
995 "message TestMessage {\n"
996 " optional int32 foo = 0x100000000;\n"
997 "}\n",
998 "1:23: Integer out of range.\n");
999}
1000
1001TEST_F(ParseErrorTest, MissingLabel) {
1002 ExpectHasErrors(
1003 "message TestMessage {\n"
1004 " int32 foo = 1;\n"
1005 "}\n",
1006 "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
1007}
1008
1009TEST_F(ParseErrorTest, ExpectedOptionName) {
1010 ExpectHasErrors(
1011 "message TestMessage {\n"
1012 " optional uint32 foo = 1 [];\n"
1013 "}\n",
kenton@google.com24bf56f2008-09-24 20:31:01 +00001014 "1:27: Expected identifier.\n");
temporal40ee5512008-07-10 02:12:20 +00001015}
1016
kenton@google.com24bf56f2008-09-24 20:31:01 +00001017TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
temporal40ee5512008-07-10 02:12:20 +00001018 ExpectHasErrors(
1019 "message TestMessage {\n"
kenton@google.com24bf56f2008-09-24 20:31:01 +00001020 " optional uint32 foo = 1 [.foo=1];\n"
temporal40ee5512008-07-10 02:12:20 +00001021 "}\n",
kenton@google.com24bf56f2008-09-24 20:31:01 +00001022 "1:27: Expected identifier.\n");
temporal40ee5512008-07-10 02:12:20 +00001023}
1024
1025TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
1026 ExpectHasErrors(
1027 "message TestMessage {\n"
1028 " optional uint32 foo = 1 [default=true];\n"
1029 "}\n",
jieluo@google.com4de8f552014-07-18 00:47:59 +00001030 "1:35: Expected integer for field default value.\n");
temporal40ee5512008-07-10 02:12:20 +00001031}
1032
1033TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
1034 ExpectHasErrors(
1035 "message TestMessage {\n"
1036 " optional bool foo = 1 [default=blah];\n"
1037 "}\n",
1038 "1:33: Expected \"true\" or \"false\".\n");
1039}
1040
1041TEST_F(ParseErrorTest, DefaultValueNotString) {
1042 ExpectHasErrors(
1043 "message TestMessage {\n"
1044 " optional string foo = 1 [default=1];\n"
1045 "}\n",
jieluo@google.com4de8f552014-07-18 00:47:59 +00001046 "1:35: Expected string for field default value.\n");
temporal40ee5512008-07-10 02:12:20 +00001047}
1048
1049TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
1050 ExpectHasErrors(
1051 "message TestMessage {\n"
1052 " optional uint32 foo = 1 [default=-1];\n"
1053 "}\n",
1054 "1:36: Unsigned field can't have negative default value.\n");
1055}
1056
1057TEST_F(ParseErrorTest, DefaultValueTooLarge) {
1058 ExpectHasErrors(
1059 "message TestMessage {\n"
1060 " optional int32 foo = 1 [default= 0x80000000];\n"
1061 " optional int32 foo = 1 [default=-0x80000001];\n"
1062 " optional uint32 foo = 1 [default= 0x100000000];\n"
1063 " optional int64 foo = 1 [default= 0x80000000000000000];\n"
1064 " optional int64 foo = 1 [default=-0x80000000000000001];\n"
1065 " optional uint64 foo = 1 [default= 0x100000000000000000];\n"
1066 "}\n",
1067 "1:36: Integer out of range.\n"
1068 "2:36: Integer out of range.\n"
1069 "3:36: Integer out of range.\n"
1070 "4:36: Integer out of range.\n"
1071 "5:36: Integer out of range.\n"
1072 "6:36: Integer out of range.\n");
1073}
1074
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001075TEST_F(ParseErrorTest, EnumValueOutOfRange) {
1076 ExpectHasErrors(
1077 "enum TestEnum {\n"
1078 " HEX_TOO_BIG = 0x80000000;\n"
1079 " HEX_TOO_SMALL = -0x80000001;\n"
1080 " INT_TOO_BIG = 2147483648;\n"
1081 " INT_TOO_SMALL = -2147483649;\n"
1082 "}\n",
1083 "1:19: Integer out of range.\n"
1084 "2:19: Integer out of range.\n"
1085 "3:19: Integer out of range.\n"
1086 "4:19: Integer out of range.\n");
1087}
1088
temporal40ee5512008-07-10 02:12:20 +00001089TEST_F(ParseErrorTest, DefaultValueMissing) {
1090 ExpectHasErrors(
1091 "message TestMessage {\n"
1092 " optional uint32 foo = 1 [default=];\n"
1093 "}\n",
jieluo@google.com4de8f552014-07-18 00:47:59 +00001094 "1:35: Expected integer for field default value.\n");
temporal40ee5512008-07-10 02:12:20 +00001095}
1096
1097TEST_F(ParseErrorTest, DefaultValueForGroup) {
1098 ExpectHasErrors(
1099 "message TestMessage {\n"
1100 " optional group Foo = 1 [default=blah] {}\n"
1101 "}\n",
1102 "1:34: Messages can't have default values.\n");
1103}
1104
1105TEST_F(ParseErrorTest, DuplicateDefaultValue) {
1106 ExpectHasErrors(
1107 "message TestMessage {\n"
1108 " optional uint32 foo = 1 [default=1,default=2];\n"
1109 "}\n",
1110 "1:37: Already set option \"default\".\n");
1111}
1112
jieluo@google.com4de8f552014-07-18 00:47:59 +00001113TEST_F(ParseErrorTest, MissingOneofName) {
1114 ExpectHasErrors(
1115 "message TestMessage {\n"
1116 " oneof {\n"
1117 " int32 bar = 1;\n"
1118 " }\n"
1119 "}\n",
1120 "1:8: Expected oneof name.\n");
1121}
1122
1123TEST_F(ParseErrorTest, LabelInOneof) {
1124 ExpectHasErrors(
1125 "message TestMessage {\n"
1126 " oneof foo {\n"
1127 " optional int32 bar = 1;\n"
1128 " }\n"
1129 "}\n",
1130 "2:4: Fields in oneofs must not have labels (required / optional "
1131 "/ repeated).\n");
1132}
1133
Feng Xiao6ef984a2014-11-10 17:34:54 -08001134TEST_F(ParseErrorTest, MapInOneof) {
1135 ExpectHasErrors(
1136 "message TestMessage {\n"
1137 " oneof foo {\n"
1138 " map<int32, int32> foo_map = 1;\n"
1139 " map message_field = 2;\n" // a normal message field is OK
1140 " }\n"
1141 "}\n",
1142 "2:7: Map fields are not allowed in oneofs.\n");
1143}
1144
1145TEST_F(ParseErrorTest, LabelForMap) {
1146 ExpectHasErrors(
1147 "message TestMessage {\n"
1148 " optional map<int32, int32> int_map = 1;\n"
1149 " required map<int32, int32> int_map2 = 2;\n"
1150 " repeated map<int32, int32> int_map3 = 3;\n"
1151 " optional map map_message = 4;\n" // a normal message field is OK
1152 "}\n",
1153 "1:14: Field labels (required/optional/repeated) are not allowed on map "
1154 "fields.\n"
1155 "2:14: Field labels (required/optional/repeated) are not allowed on map "
1156 "fields.\n"
1157 "3:14: Field labels (required/optional/repeated) are not allowed on map "
1158 "fields.\n");
1159}
1160
1161TEST_F(ParseErrorTest, MalformedMaps) {
1162 ExpectHasErrors(
1163 "message TestMessage {\n"
1164 " map map_message = 1;\n" // a normal message field lacking label
1165 " map<string> str_map = 2;\n"
1166 " map<string,> str_map2 = 3;\n"
1167 " map<,string> str_map3 = 4;\n"
1168 " map<> empty_map = 5;\n"
1169 " map<string,string str_map6 = 6;\n"
1170 "}"
1171 "extend SomeMessage {\n"
1172 " map<int32, int32> int_map = 1;\n"
1173 "}",
1174 "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
1175 "2:12: Expected \",\".\n"
1176 "3:13: Expected type name.\n"
1177 "4:6: Expected type name.\n"
1178 "5:6: Expected type name.\n"
1179 "6:20: Expected \">\".\n"
1180 "8:5: Map fields are not allowed to be extensions.\n");
1181}
1182
temporal40ee5512008-07-10 02:12:20 +00001183TEST_F(ParseErrorTest, GroupNotCapitalized) {
1184 ExpectHasErrors(
1185 "message TestMessage {\n"
1186 " optional group foo = 1 {}\n"
1187 "}\n",
1188 "1:17: Group names must start with a capital letter.\n");
1189}
1190
1191TEST_F(ParseErrorTest, GroupMissingBody) {
1192 ExpectHasErrors(
1193 "message TestMessage {\n"
1194 " optional group Foo = 1;\n"
1195 "}\n",
1196 "1:24: Missing group body.\n");
1197}
1198
1199TEST_F(ParseErrorTest, ExtendingPrimitive) {
1200 ExpectHasErrors(
1201 "extend int32 { optional string foo = 4; }\n",
1202 "0:7: Expected message type.\n");
1203}
1204
1205TEST_F(ParseErrorTest, ErrorInExtension) {
1206 ExpectHasErrors(
1207 "message Foo { extensions 100 to 199; }\n"
1208 "extend Foo { optional string foo; }\n",
1209 "1:32: Missing field number.\n");
1210}
1211
1212TEST_F(ParseErrorTest, MultipleParseErrors) {
1213 // When a statement has a parse error, the parser should be able to continue
1214 // parsing at the next statement.
1215 ExpectHasErrors(
1216 "message TestMessage {\n"
1217 " optional int32 foo;\n"
1218 " !invalid statement ending in a block { blah blah { blah } blah }\n"
1219 " optional int32 bar = 3 {}\n"
1220 "}\n",
1221 "1:20: Missing field number.\n"
1222 "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
1223 "2:2: Expected type name.\n"
1224 "3:25: Expected \";\".\n");
1225}
1226
liujisi@google.com33165fe2010-11-02 13:14:58 +00001227TEST_F(ParseErrorTest, EofInAggregateValue) {
1228 ExpectHasErrors(
1229 "option (fileopt) = { i:100\n",
1230 "1:0: Unexpected end of stream while parsing aggregate value.\n");
1231}
1232
temporal40ee5512008-07-10 02:12:20 +00001233// -------------------------------------------------------------------
1234// Enum errors
1235
1236TEST_F(ParseErrorTest, EofInEnum) {
1237 ExpectHasErrors(
1238 "enum TestEnum {",
1239 "0:15: Reached end of input in enum definition (missing '}').\n");
1240}
1241
1242TEST_F(ParseErrorTest, EnumValueMissingNumber) {
1243 ExpectHasErrors(
1244 "enum TestEnum {\n"
1245 " FOO;\n"
1246 "}\n",
1247 "1:5: Missing numeric value for enum constant.\n");
1248}
1249
1250// -------------------------------------------------------------------
1251// Service errors
1252
1253TEST_F(ParseErrorTest, EofInService) {
1254 ExpectHasErrors(
1255 "service TestService {",
1256 "0:21: Reached end of input in service definition (missing '}').\n");
1257}
1258
1259TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
1260 ExpectHasErrors(
1261 "service TestService {\n"
1262 " rpc Foo(int32) returns (string);\n"
1263 "}\n",
1264 "1:10: Expected message type.\n"
1265 "1:26: Expected message type.\n");
1266}
1267
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001268
temporal40ee5512008-07-10 02:12:20 +00001269TEST_F(ParseErrorTest, EofInMethodOptions) {
1270 ExpectHasErrors(
1271 "service TestService {\n"
1272 " rpc Foo(Bar) returns(Bar) {",
1273 "1:29: Reached end of input in method options (missing '}').\n"
1274 "1:29: Reached end of input in service definition (missing '}').\n");
1275}
1276
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001277
temporal40ee5512008-07-10 02:12:20 +00001278TEST_F(ParseErrorTest, PrimitiveMethodInput) {
1279 ExpectHasErrors(
1280 "service TestService {\n"
1281 " rpc Foo(int32) returns(Bar);\n"
1282 "}\n",
1283 "1:10: Expected message type.\n");
1284}
1285
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001286
temporal40ee5512008-07-10 02:12:20 +00001287TEST_F(ParseErrorTest, MethodOptionTypeError) {
1288 // This used to cause an infinite loop.
1289 ExpectHasErrors(
1290 "message Baz {}\n"
1291 "service Foo {\n"
1292 " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
1293 "}\n",
kenton@google.com24bf56f2008-09-24 20:31:01 +00001294 "2:45: Expected \"=\".\n");
temporal40ee5512008-07-10 02:12:20 +00001295}
1296
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001297
temporal40ee5512008-07-10 02:12:20 +00001298// -------------------------------------------------------------------
1299// Import and package errors
1300
1301TEST_F(ParseErrorTest, ImportNotQuoted) {
1302 ExpectHasErrors(
1303 "import foo;\n",
1304 "0:7: Expected a string naming the file to import.\n");
1305}
1306
1307TEST_F(ParseErrorTest, MultiplePackagesInFile) {
1308 ExpectHasErrors(
1309 "package foo;\n"
1310 "package bar;\n",
1311 "1:0: Multiple package definitions.\n");
1312}
1313
temporal40ee5512008-07-10 02:12:20 +00001314// ===================================================================
1315// Test that errors detected by DescriptorPool correctly report line and
1316// column numbers. We have one test for every call to RecordLocation() in
1317// parser.cc.
1318
1319typedef ParserTest ParserValidationErrorTest;
1320
1321TEST_F(ParserValidationErrorTest, PackageNameError) {
1322 // Create another file which defines symbol "foo".
1323 FileDescriptorProto other_file;
1324 other_file.set_name("bar.proto");
1325 other_file.add_message_type()->set_name("foo");
1326 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1327
1328 // Now try to define it as a package.
1329 ExpectHasValidationErrors(
1330 "package foo.bar;",
1331 "0:8: \"foo\" is already defined (as something other than a package) "
1332 "in file \"bar.proto\".\n");
1333}
1334
1335TEST_F(ParserValidationErrorTest, MessageNameError) {
1336 ExpectHasValidationErrors(
1337 "message Foo {}\n"
1338 "message Foo {}\n",
1339 "1:8: \"Foo\" is already defined.\n");
1340}
1341
1342TEST_F(ParserValidationErrorTest, FieldNameError) {
1343 ExpectHasValidationErrors(
1344 "message Foo {\n"
1345 " optional int32 bar = 1;\n"
1346 " optional int32 bar = 2;\n"
1347 "}\n",
1348 "2:17: \"bar\" is already defined in \"Foo\".\n");
1349}
1350
1351TEST_F(ParserValidationErrorTest, FieldTypeError) {
1352 ExpectHasValidationErrors(
1353 "message Foo {\n"
1354 " optional Baz bar = 1;\n"
1355 "}\n",
1356 "1:11: \"Baz\" is not defined.\n");
1357}
1358
1359TEST_F(ParserValidationErrorTest, FieldNumberError) {
1360 ExpectHasValidationErrors(
1361 "message Foo {\n"
1362 " optional int32 bar = 0;\n"
1363 "}\n",
1364 "1:23: Field numbers must be positive integers.\n");
1365}
1366
1367TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
1368 ExpectHasValidationErrors(
1369 "extend Baz { optional int32 bar = 1; }\n",
1370 "0:7: \"Baz\" is not defined.\n");
1371}
1372
1373TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
1374 ExpectHasValidationErrors(
1375 "enum Baz { QUX = 1; }\n"
1376 "message Foo {\n"
1377 " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
1378 "}\n",
1379 "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
1380}
1381
kenton@google.com24bf56f2008-09-24 20:31:01 +00001382TEST_F(ParserValidationErrorTest, FileOptionNameError) {
1383 ExpectHasValidationErrors(
1384 "option foo = 5;",
1385 "0:7: Option \"foo\" unknown.\n");
1386}
1387
1388TEST_F(ParserValidationErrorTest, FileOptionValueError) {
1389 ExpectHasValidationErrors(
1390 "option java_outer_classname = 5;",
1391 "0:30: Value must be quoted string for string option "
1392 "\"google.protobuf.FileOptions.java_outer_classname\".\n");
1393}
1394
1395TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
1396 ExpectHasValidationErrors(
1397 "message Foo {\n"
1398 " optional bool bar = 1 [foo=1];\n"
1399 "}\n",
1400 "1:25: Option \"foo\" unknown.\n");
1401}
1402
1403TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
1404 ExpectHasValidationErrors(
1405 "message Foo {\n"
1406 " optional int32 bar = 1 [ctype=1];\n"
1407 "}\n",
1408 "1:32: Value must be identifier for enum-valued option "
1409 "\"google.protobuf.FieldOptions.ctype\".\n");
1410}
1411
temporal40ee5512008-07-10 02:12:20 +00001412TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
1413 ExpectHasValidationErrors(
1414 "message Foo {\n"
1415 " extensions 0;\n"
1416 "}\n",
1417 "1:13: Extension numbers must be positive integers.\n");
1418}
1419
1420TEST_F(ParserValidationErrorTest, EnumNameError) {
1421 ExpectHasValidationErrors(
1422 "enum Foo {A = 1;}\n"
1423 "enum Foo {B = 1;}\n",
1424 "1:5: \"Foo\" is already defined.\n");
1425}
1426
1427TEST_F(ParserValidationErrorTest, EnumValueNameError) {
1428 ExpectHasValidationErrors(
1429 "enum Foo {\n"
1430 " BAR = 1;\n"
1431 " BAR = 1;\n"
1432 "}\n",
1433 "2:2: \"BAR\" is already defined.\n");
1434}
1435
1436TEST_F(ParserValidationErrorTest, ServiceNameError) {
1437 ExpectHasValidationErrors(
1438 "service Foo {}\n"
1439 "service Foo {}\n",
1440 "1:8: \"Foo\" is already defined.\n");
1441}
1442
1443TEST_F(ParserValidationErrorTest, MethodNameError) {
1444 ExpectHasValidationErrors(
1445 "message Baz {}\n"
1446 "service Foo {\n"
1447 " rpc Bar(Baz) returns(Baz);\n"
1448 " rpc Bar(Baz) returns(Baz);\n"
1449 "}\n",
1450 "3:6: \"Bar\" is already defined in \"Foo\".\n");
1451}
1452
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001453
temporal40ee5512008-07-10 02:12:20 +00001454TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
1455 ExpectHasValidationErrors(
1456 "message Baz {}\n"
1457 "service Foo {\n"
1458 " rpc Bar(Qux) returns(Baz);\n"
1459 "}\n",
1460 "2:10: \"Qux\" is not defined.\n");
1461}
1462
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001463
temporal40ee5512008-07-10 02:12:20 +00001464TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
1465 ExpectHasValidationErrors(
1466 "message Baz {}\n"
1467 "service Foo {\n"
1468 " rpc Bar(Baz) returns(Qux);\n"
1469 "}\n",
1470 "2:23: \"Qux\" is not defined.\n");
1471}
1472
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001473
jieluo@google.com4de8f552014-07-18 00:47:59 +00001474TEST_F(ParserValidationErrorTest, ResovledUndefinedError) {
1475 // Create another file which defines symbol ".base.bar".
1476 FileDescriptorProto other_file;
1477 other_file.set_name("base.proto");
1478 other_file.set_package("base");
1479 other_file.add_message_type()->set_name("bar");
1480 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1481
1482 // Define "foo.base" and try "base.bar".
1483 // "base.bar" is resolved to "foo.base.bar" which is not defined.
1484 ExpectHasValidationErrors(
1485 "package foo.base;\n"
1486 "import \"base.proto\";\n"
1487 "message qux {\n"
1488 " optional base.bar baz = 1;\n"
1489 " optional .base.bar quz = 2;\n"
1490 "}\n",
1491 "3:11: \"base.bar\" is resolved to \"foo.base.bar\","
1492 " which is not defined. The innermost scope is searched first "
1493 "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")"
1494 " to start from the outermost scope.\n");
1495}
1496
1497TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) {
1498 // Build descriptor message in test pool
1499 FileDescriptorProto descriptor_proto;
1500 DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto);
1501 ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != NULL);
1502
1503 // base2.proto:
1504 // package baz
1505 // import google/protobuf/descriptor.proto
1506 // message Bar { optional int32 foo = 1; }
1507 // extend FileOptions { optional Bar bar = 7672757; }
1508 FileDescriptorProto other_file;
1509 other_file.set_name("base2.proto");
1510 other_file.set_package("baz");
1511 other_file.add_dependency();
1512 other_file.set_dependency(0, descriptor_proto.name());
1513
1514 DescriptorProto* message(other_file.add_message_type());
1515 message->set_name("Bar");
1516 FieldDescriptorProto* field(message->add_field());
1517 field->set_name("foo");
1518 field->set_number(1);
1519 field->set_label(FieldDescriptorProto_Label_LABEL_OPTIONAL);
1520 field->set_type(FieldDescriptorProto_Type_TYPE_INT32);
1521
1522 FieldDescriptorProto* extension(other_file.add_extension());
1523 extension->set_name("bar");
1524 extension->set_number(7672757);
1525 extension->set_label(FieldDescriptorProto_Label_LABEL_OPTIONAL);
1526 extension->set_type(FieldDescriptorProto_Type_TYPE_MESSAGE);
1527 extension->set_type_name("Bar");
1528 extension->set_extendee("google.protobuf.FileOptions");
1529
1530 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1531
1532 // qux.proto:
1533 // package qux.baz
1534 // option (baz.bar).foo = 1;
1535 //
1536 // Although "baz.bar" is already defined, the lookup code will try
1537 // "qux.baz.bar", since it's the match from the innermost scope,
1538 // which will cause a symbol not defined error.
1539 ExpectHasValidationErrors(
1540 "package qux.baz;\n"
1541 "import \"base2.proto\";\n"
1542 "option (baz.bar).foo = 1;\n",
1543 "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\","
1544 " which is not defined. The innermost scope is searched first "
1545 "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")"
1546 " to start from the outermost scope.\n");
1547}
1548
temporal40ee5512008-07-10 02:12:20 +00001549// ===================================================================
1550// Test that the output from FileDescriptor::DebugString() (and all other
1551// descriptor types) is parseable, and results in the same Descriptor
jieluo@google.com4de8f552014-07-18 00:47:59 +00001552// definitions again afoter parsing (note, however, that the order of messages
temporal40ee5512008-07-10 02:12:20 +00001553// cannot be guaranteed to be the same)
1554
Feng Xiao6ef984a2014-11-10 17:34:54 -08001555typedef ParserTest ParseDescriptorDebugTest;
temporal40ee5512008-07-10 02:12:20 +00001556
1557class CompareDescriptorNames {
1558 public:
jieluo@google.com4de8f552014-07-18 00:47:59 +00001559 bool operator()(const DescriptorProto* left,
1560 const DescriptorProto* right) const {
temporal40ee5512008-07-10 02:12:20 +00001561 return left->name() < right->name();
1562 }
1563};
1564
1565// Sorts nested DescriptorProtos of a DescriptoProto, by name.
1566void SortMessages(DescriptorProto *descriptor_proto) {
1567 int size = descriptor_proto->nested_type_size();
1568 // recursively sort; we can't guarantee the order of nested messages either
1569 for (int i = 0; i < size; ++i) {
1570 SortMessages(descriptor_proto->mutable_nested_type(i));
1571 }
1572 DescriptorProto **data =
1573 descriptor_proto->mutable_nested_type()->mutable_data();
Jisi Liu885b6122015-02-28 14:51:22 -08001574 std::sort(data, data + size, CompareDescriptorNames());
temporal40ee5512008-07-10 02:12:20 +00001575}
1576
1577// Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
1578void SortMessages(FileDescriptorProto *file_descriptor_proto) {
1579 int size = file_descriptor_proto->message_type_size();
1580 // recursively sort; we can't guarantee the order of nested messages either
1581 for (int i = 0; i < size; ++i) {
1582 SortMessages(file_descriptor_proto->mutable_message_type(i));
1583 }
1584 DescriptorProto **data =
1585 file_descriptor_proto->mutable_message_type()->mutable_data();
Jisi Liu885b6122015-02-28 14:51:22 -08001586 std::sort(data, data + size, CompareDescriptorNames());
temporal40ee5512008-07-10 02:12:20 +00001587}
1588
Feng Xiao6ef984a2014-11-10 17:34:54 -08001589// Strips the message and enum field type names for comparison purpose only.
1590void StripFieldTypeName(DescriptorProto* proto) {
1591 for (int i = 0; i < proto->field_size(); ++i) {
1592 string type_name = proto->field(i).type_name();
1593 string::size_type pos = type_name.find_last_of(".");
1594 if (pos != string::npos) {
1595 proto->mutable_field(i)->mutable_type_name()->assign(
1596 type_name.begin() + pos + 1, type_name.end());
1597 }
1598 }
1599 for (int i = 0; i < proto->nested_type_size(); ++i) {
1600 StripFieldTypeName(proto->mutable_nested_type(i));
1601 }
1602}
1603
1604void StripFieldTypeName(FileDescriptorProto* file_proto) {
1605 for (int i = 0; i < file_proto->message_type_size(); ++i) {
1606 StripFieldTypeName(file_proto->mutable_message_type(i));
1607 }
1608}
1609
1610TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) {
temporal40ee5512008-07-10 02:12:20 +00001611 const FileDescriptor* original_file =
1612 protobuf_unittest::TestAllTypes::descriptor()->file();
1613 FileDescriptorProto expected;
1614 original_file->CopyTo(&expected);
1615
1616 // Get the DebugString of the unittest.proto FileDecriptor, which includes
1617 // all other descriptor types
1618 string debug_string = original_file->DebugString();
1619
1620 // Parse the debug string
1621 SetupParser(debug_string.c_str());
1622 FileDescriptorProto parsed;
1623 parser_->Parse(input_.get(), &parsed);
1624 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
jieluo@google.com4de8f552014-07-18 00:47:59 +00001625 ASSERT_EQ("", error_collector_.text_)
1626 << "Failed to parse:\n" << debug_string;
temporal40ee5512008-07-10 02:12:20 +00001627
1628 // We now have a FileDescriptorProto, but to compare with the expected we
1629 // need to link to a FileDecriptor, then output back to a proto. We'll
1630 // also need to give it the same name as the original.
1631 parsed.set_name("google/protobuf/unittest.proto");
1632 // We need the imported dependency before we can build our parsed proto
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001633 const FileDescriptor* public_import =
1634 protobuf_unittest_import::PublicImportMessage::descriptor()->file();
1635 FileDescriptorProto public_import_proto;
1636 public_import->CopyTo(&public_import_proto);
1637 ASSERT_TRUE(pool_.BuildFile(public_import_proto) != NULL);
temporal40ee5512008-07-10 02:12:20 +00001638 const FileDescriptor* import =
1639 protobuf_unittest_import::ImportMessage::descriptor()->file();
1640 FileDescriptorProto import_proto;
1641 import->CopyTo(&import_proto);
1642 ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
1643 const FileDescriptor* actual = pool_.BuildFile(parsed);
1644 parsed.Clear();
jieluo@google.com4de8f552014-07-18 00:47:59 +00001645 ASSERT_TRUE(actual != NULL)
1646 << "Failed to validate:\n" << debug_string;
temporal40ee5512008-07-10 02:12:20 +00001647 actual->CopyTo(&parsed);
1648 ASSERT_TRUE(actual != NULL);
1649
1650 // The messages might be in different orders, making them hard to compare.
1651 // So, sort the messages in the descriptor protos (including nested messages,
1652 // recursively).
1653 SortMessages(&expected);
1654 SortMessages(&parsed);
1655
1656 // I really wanted to use StringDiff here for the debug output on fail,
1657 // but the strings are too long for it, and if I increase its max size,
1658 // we get a memory allocation failure :(
1659 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
1660}
1661
Feng Xiao6ef984a2014-11-10 17:34:54 -08001662TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001663 const FileDescriptor* original_file =
1664 protobuf_unittest::AggregateMessage::descriptor()->file();
1665 FileDescriptorProto expected;
1666 original_file->CopyTo(&expected);
1667
1668 string debug_string = original_file->DebugString();
1669
1670 // Parse the debug string
1671 SetupParser(debug_string.c_str());
1672 FileDescriptorProto parsed;
1673 parser_->Parse(input_.get(), &parsed);
1674 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1675 ASSERT_EQ("", error_collector_.text_);
1676
1677 // We now have a FileDescriptorProto, but to compare with the expected we
1678 // need to link to a FileDecriptor, then output back to a proto. We'll
1679 // also need to give it the same name as the original.
1680 parsed.set_name(original_file->name());
1681
1682 // unittest_custom_options.proto depends on descriptor.proto.
1683 const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
1684 FileDescriptorProto import_proto;
1685 import->CopyTo(&import_proto);
1686 ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
1687 const FileDescriptor* actual = pool_.BuildFile(parsed);
1688 ASSERT_TRUE(actual != NULL);
1689 parsed.Clear();
1690 actual->CopyTo(&parsed);
1691
1692 // The messages might be in different orders, making them hard to compare.
1693 // So, sort the messages in the descriptor protos (including nested messages,
1694 // recursively).
1695 SortMessages(&expected);
1696 SortMessages(&parsed);
1697
1698 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
1699}
1700
Feng Xiao6ef984a2014-11-10 17:34:54 -08001701// Ensure that DebugStringWithOptions(), with |include_comments| set to true,
1702// includes comments from the original parser input in all of the appropriate
1703// places.
1704TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
1705 SetupParser(
Jisi Liu885b6122015-02-28 14:51:22 -08001706 "// Detached comment before syntax.\n"
1707 "\n"
1708 "// Syntax comment.\n"
1709 "syntax = \"proto2\";\n"
1710 "\n"
1711 "// Detached comment before package.\n"
1712 "\n"
1713 "// Package comment.\n"
1714 "package comment_test;\n"
1715 "\n"
1716 "// Detached comment before TestMessage1.\n"
1717 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001718 "// Message comment.\n"
1719 "message TestMessage1 {\n"
Jisi Liu885b6122015-02-28 14:51:22 -08001720 "\n"
1721 " // Detached comment before foo.\n"
1722 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001723 " // Field comment.\n"
1724 " optional int32 foo = 1;\n"
1725 "\n"
Jisi Liu885b6122015-02-28 14:51:22 -08001726 " // Detached comment before NestedMessage.\n"
1727 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001728 " // Nested-message comment.\n"
1729 " message NestedMessage {\n"
1730 " optional int32 bar = 1;\n"
1731 " }\n"
1732 "}\n"
1733 "\n"
Jisi Liu885b6122015-02-28 14:51:22 -08001734 "// Detached comment before MyEnumType.\n"
1735 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001736 "// Enum comment.\n"
1737 "enum MyEnumType {\n"
Jisi Liu885b6122015-02-28 14:51:22 -08001738 "\n"
1739 " // Detached comment before ASDF.\n"
1740 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001741 " // Enum-value comment.\n"
1742 " ASDF = 1;\n"
1743 "}\n"
1744 "\n"
Jisi Liu885b6122015-02-28 14:51:22 -08001745 "// Detached comment before MyService.\n"
1746 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001747 "// Service comment.\n"
1748 "service MyService {\n"
Jisi Liu885b6122015-02-28 14:51:22 -08001749 "\n"
1750 " // Detached comment before MyRPCCall.\n"
1751 "\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -08001752 " // RPC comment.\n"
1753 " rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
1754 "}\n");
1755
1756 FileDescriptorProto parsed_desc;
1757 parsed_desc.set_name("foo.proto");
1758 SourceLocationTable source_locations;
1759 parser_->RecordSourceLocationsTo(&source_locations);
1760 parser_->Parse(input_.get(), &parsed_desc);
1761 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1762 ASSERT_EQ("", error_collector_.text_);
1763
1764 // We need to import the FileDescriptorProto to get a FileDescriptor.
1765 MockValidationErrorCollector collector(source_locations, &error_collector_);
1766 const FileDescriptor* descriptor =
1767 pool_.BuildFileCollectingErrors(parsed_desc, &collector);
1768 ASSERT_TRUE(descriptor != NULL);
1769
1770 DebugStringOptions debug_string_options;
1771 debug_string_options.include_comments = true;
1772 const string debug_string =
1773 descriptor->DebugStringWithOptions(debug_string_options);
1774
Jisi Liu885b6122015-02-28 14:51:22 -08001775 // Ensure that each of the comments appears somewhere in the DebugString().
1776 // We don't test the exact comment placement or formatting, because we do not
1777 // want to be too fragile here.
Feng Xiao6ef984a2014-11-10 17:34:54 -08001778 const char* expected_comments[] = {
Jisi Liu885b6122015-02-28 14:51:22 -08001779 "Detached comment before syntax.",
1780 "Syntax comment.",
1781 "Detached comment before package.",
1782 "Package comment.",
1783 "Detached comment before TestMessage1.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001784 "Message comment.",
Jisi Liu885b6122015-02-28 14:51:22 -08001785 "Detached comment before foo.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001786 "Field comment",
Jisi Liu885b6122015-02-28 14:51:22 -08001787 "Detached comment before NestedMessage.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001788 "Nested-message comment",
Jisi Liu885b6122015-02-28 14:51:22 -08001789 "Detached comment before MyEnumType.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001790 "Enum comment",
Jisi Liu885b6122015-02-28 14:51:22 -08001791 "Detached comment before ASDF.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001792 "Enum-value comment",
Jisi Liu885b6122015-02-28 14:51:22 -08001793 "Detached comment before MyService.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001794 "Service comment",
Jisi Liu885b6122015-02-28 14:51:22 -08001795 "Detached comment before MyRPCCall.",
Feng Xiao6ef984a2014-11-10 17:34:54 -08001796 "RPC comment",
1797 };
1798
1799 for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
1800 string::size_type found_pos = debug_string.find(expected_comments[i]);
Jisi Liu885b6122015-02-28 14:51:22 -08001801 EXPECT_TRUE(found_pos != string::npos)
1802 << "\"" << expected_comments[i] << "\" not found.";
Feng Xiao6ef984a2014-11-10 17:34:54 -08001803 }
1804}
1805
1806TEST_F(ParseDescriptorDebugTest, TestMaps) {
1807 SetupParser(
1808 "syntax = \"proto3\"; "
1809 "message Foo { "
1810 " message Bar { } "
1811 " map<int32, Bar> enum_message_map = 1; "
1812 " map<string, float> primitive_map = 2; "
1813 "} ");
1814 FileDescriptorProto original;
1815 EXPECT_TRUE(parser_->Parse(input_.get(), &original));
1816 original.set_name("foo.proto");
1817 const FileDescriptor* file = pool_.BuildFile(original);
1818 ASSERT_TRUE(file != NULL);
1819
1820 // Make sure the debug string uses map syntax and does not have the auto
1821 // generated entry.
1822 string debug_string = file->DebugString();
1823 EXPECT_TRUE(debug_string.find("map<") != string::npos);
1824 EXPECT_TRUE(debug_string.find("option map_entry") == string::npos);
1825 EXPECT_TRUE(debug_string.find("MapEntry") == string::npos);
1826
1827 // Make sure the descriptor debug string is parsable.
1828 FileDescriptorProto parsed;
1829 SetupParser(debug_string.c_str());
1830 parsed.set_name("foo.proto");
1831 ASSERT_TRUE(parser_->Parse(input_.get(), &parsed));
1832
1833 original.clear_source_code_info();
1834 parsed.clear_source_code_info();
1835 StripFieldTypeName(&original);
1836 StripFieldTypeName(&parsed);
1837 EXPECT_EQ(original.DebugString(), parsed.DebugString());
1838}
1839
temporal40ee5512008-07-10 02:12:20 +00001840// ===================================================================
liujisi@google.com33165fe2010-11-02 13:14:58 +00001841// SourceCodeInfo tests.
1842
1843// Follows a path -- as defined by SourceCodeInfo.Location.path -- from a
1844// message to a particular sub-field.
1845// * If the target is itself a message, sets *output_message to point at it,
1846// *output_field to NULL, and *output_index to -1.
1847// * Otherwise, if the target is an element of a repeated field, sets
1848// *output_message to the containing message, *output_field to the descriptor
1849// of the field, and *output_index to the index of the element.
1850// * Otherwise, the target is a field (possibly a repeated field, but not any
1851// one element). Sets *output_message to the containing message,
1852// *output_field to the descriptor of the field, and *output_index to -1.
1853// Returns true if the path was valid, false otherwise. A gTest failure is
1854// recorded before returning false.
1855bool FollowPath(const Message& root,
1856 const int* path_begin, const int* path_end,
1857 const Message** output_message,
1858 const FieldDescriptor** output_field,
1859 int* output_index) {
1860 if (path_begin == path_end) {
1861 // Path refers to this whole message.
1862 *output_message = &root;
1863 *output_field = NULL;
1864 *output_index = -1;
1865 return true;
1866 }
1867
1868 const Descriptor* descriptor = root.GetDescriptor();
1869 const Reflection* reflection = root.GetReflection();
1870
1871 const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
1872
1873 if (field == NULL) {
1874 ADD_FAILURE() << descriptor->name() << " has no field number: "
1875 << *path_begin;
1876 return false;
1877 }
1878
1879 ++path_begin;
1880
1881 if (field->is_repeated()) {
1882 if (path_begin == path_end) {
1883 // Path refers to the whole repeated field.
1884 *output_message = &root;
1885 *output_field = field;
1886 *output_index = -1;
1887 return true;
1888 }
1889
1890 int index = *path_begin++;
1891 int size = reflection->FieldSize(root, field);
1892
1893 if (index >= size) {
1894 ADD_FAILURE() << descriptor->name() << "." << field->name()
1895 << " has size " << size << ", but path contained index: "
1896 << index;
1897 return false;
1898 }
1899
1900 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1901 // Descend into child message.
1902 const Message& child = reflection->GetRepeatedMessage(root, field, index);
1903 return FollowPath(child, path_begin, path_end,
1904 output_message, output_field, output_index);
1905 } else if (path_begin == path_end) {
1906 // Path refers to this element.
1907 *output_message = &root;
1908 *output_field = field;
1909 *output_index = index;
1910 return true;
1911 } else {
1912 ADD_FAILURE() << descriptor->name() << "." << field->name()
1913 << " is not a message; cannot descend into it.";
1914 return false;
1915 }
1916 } else {
1917 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1918 const Message& child = reflection->GetMessage(root, field);
1919 return FollowPath(child, path_begin, path_end,
1920 output_message, output_field, output_index);
1921 } else if (path_begin == path_end) {
1922 // Path refers to this field.
1923 *output_message = &root;
1924 *output_field = field;
1925 *output_index = -1;
1926 return true;
1927 } else {
1928 ADD_FAILURE() << descriptor->name() << "." << field->name()
1929 << " is not a message; cannot descend into it.";
1930 return false;
1931 }
1932 }
1933}
1934
liujisi@google.com33165fe2010-11-02 13:14:58 +00001935// Check if two spans are equal.
1936bool CompareSpans(const RepeatedField<int>& span1,
1937 const RepeatedField<int>& span2) {
1938 if (span1.size() != span2.size()) return false;
1939 for (int i = 0; i < span1.size(); i++) {
1940 if (span1.Get(i) != span2.Get(i)) return false;
1941 }
1942 return true;
1943}
1944
1945// Test fixture for source info tests, which check that source locations are
1946// recorded correctly in FileDescriptorProto.source_code_info.location.
1947class SourceInfoTest : public ParserTest {
1948 protected:
1949 // The parsed file (initialized by Parse()).
1950 FileDescriptorProto file_;
1951
1952 // Parse the given text as a .proto file and populate the spans_ map with
1953 // all the source location spans in its SourceCodeInfo table.
1954 bool Parse(const char* text) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001955 ExtractMarkers(text);
1956 SetupParser(text_without_markers_.c_str());
liujisi@google.com33165fe2010-11-02 13:14:58 +00001957 if (!parser_->Parse(input_.get(), &file_)) {
1958 return false;
1959 }
1960
1961 const SourceCodeInfo& source_info = file_.source_code_info();
1962 for (int i = 0; i < source_info.location_size(); i++) {
1963 const SourceCodeInfo::Location& location = source_info.location(i);
1964 const Message* descriptor_proto = NULL;
1965 const FieldDescriptor* field = NULL;
1966 int index = 0;
1967 if (!FollowPath(file_, location.path().begin(), location.path().end(),
1968 &descriptor_proto, &field, &index)) {
1969 return false;
1970 }
1971
Jisi Liu885b6122015-02-28 14:51:22 -08001972 spans_.insert(
1973 std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001974 }
1975
1976 return true;
1977 }
1978
1979 virtual void TearDown() {
1980 EXPECT_TRUE(spans_.empty())
1981 << "Forgot to call HasSpan() for:\n"
1982 << spans_.begin()->second->DebugString();
1983 }
1984
1985 // -----------------------------------------------------------------
1986 // HasSpan() checks that the span of source code delimited by the given
1987 // tags (comments) correspond via the SourceCodeInfo table to the given
1988 // part of the FileDescriptorProto. (If unclear, look at the actual tests;
1989 // it should quickly become obvious.)
1990
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001991 bool HasSpan(char start_marker, char end_marker,
liujisi@google.com33165fe2010-11-02 13:14:58 +00001992 const Message& descriptor_proto) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001993 return HasSpanWithComment(
Jisi Liu885b6122015-02-28 14:51:22 -08001994 start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL, NULL);
liujisi@google.com33165fe2010-11-02 13:14:58 +00001995 }
1996
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001997 bool HasSpanWithComment(char start_marker, char end_marker,
1998 const Message& descriptor_proto,
1999 const char* expected_leading_comments,
Jisi Liu885b6122015-02-28 14:51:22 -08002000 const char* expected_trailing_comments,
2001 const char* expected_leading_detached_comments) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002002 return HasSpanWithComment(
2003 start_marker, end_marker, descriptor_proto, NULL, -1,
Jisi Liu885b6122015-02-28 14:51:22 -08002004 expected_leading_comments, expected_trailing_comments,
2005 expected_leading_detached_comments);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002006 }
2007
2008 bool HasSpan(char start_marker, char end_marker,
liujisi@google.com33165fe2010-11-02 13:14:58 +00002009 const Message& descriptor_proto, const string& field_name) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002010 return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1);
liujisi@google.com33165fe2010-11-02 13:14:58 +00002011 }
2012
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002013 bool HasSpan(char start_marker, char end_marker,
liujisi@google.com33165fe2010-11-02 13:14:58 +00002014 const Message& descriptor_proto, const string& field_name,
2015 int index) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002016 return HasSpan(start_marker, end_marker, descriptor_proto,
Jisi Liu885b6122015-02-28 14:51:22 -08002017 field_name, index, NULL, NULL, NULL);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002018 }
2019
2020 bool HasSpan(char start_marker, char end_marker,
2021 const Message& descriptor_proto,
2022 const string& field_name, int index,
2023 const char* expected_leading_comments,
Jisi Liu885b6122015-02-28 14:51:22 -08002024 const char* expected_trailing_comments,
2025 const char* expected_leading_detached_comments) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00002026 const FieldDescriptor* field =
2027 descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
2028 if (field == NULL) {
2029 ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
2030 << " has no such field: " << field_name;
2031 return false;
2032 }
2033
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002034 return HasSpanWithComment(
2035 start_marker, end_marker, descriptor_proto, field, index,
Jisi Liu885b6122015-02-28 14:51:22 -08002036 expected_leading_comments, expected_trailing_comments,
2037 expected_leading_detached_comments);
liujisi@google.com33165fe2010-11-02 13:14:58 +00002038 }
2039
2040 bool HasSpan(const Message& descriptor_proto) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002041 return HasSpanWithComment(
Jisi Liu885b6122015-02-28 14:51:22 -08002042 '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL, NULL);
liujisi@google.com33165fe2010-11-02 13:14:58 +00002043 }
2044
2045 bool HasSpan(const Message& descriptor_proto, const string& field_name) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002046 return HasSpan('\0', '\0', descriptor_proto, field_name, -1);
liujisi@google.com33165fe2010-11-02 13:14:58 +00002047 }
2048
2049 bool HasSpan(const Message& descriptor_proto, const string& field_name,
2050 int index) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002051 return HasSpan('\0', '\0', descriptor_proto, field_name, index);
liujisi@google.com33165fe2010-11-02 13:14:58 +00002052 }
2053
Jisi Liu885b6122015-02-28 14:51:22 -08002054 bool HasSpanWithComment(
2055 char start_marker, char end_marker, const Message& descriptor_proto,
2056 const FieldDescriptor* field, int index,
2057 const char* expected_leading_comments,
2058 const char* expected_trailing_comments,
2059 const char* expected_leading_detached_comments) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00002060 pair<SpanMap::iterator, SpanMap::iterator> range =
2061 spans_.equal_range(SpanKey(descriptor_proto, field, index));
2062
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002063 if (start_marker == '\0') {
liujisi@google.com33165fe2010-11-02 13:14:58 +00002064 if (range.first == range.second) {
2065 return false;
2066 } else {
2067 spans_.erase(range.first);
2068 return true;
2069 }
2070 } else {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002071 pair<int, int> start_pos = FindOrDie(markers_, start_marker);
2072 pair<int, int> end_pos = FindOrDie(markers_, end_marker);
2073
liujisi@google.com33165fe2010-11-02 13:14:58 +00002074 RepeatedField<int> expected_span;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002075 expected_span.Add(start_pos.first);
2076 expected_span.Add(start_pos.second);
2077 if (end_pos.first != start_pos.first) {
2078 expected_span.Add(end_pos.first);
2079 }
2080 expected_span.Add(end_pos.second);
liujisi@google.com33165fe2010-11-02 13:14:58 +00002081
2082 for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
2083 if (CompareSpans(expected_span, iter->second->span())) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002084 if (expected_leading_comments == NULL) {
2085 EXPECT_FALSE(iter->second->has_leading_comments());
2086 } else {
2087 EXPECT_TRUE(iter->second->has_leading_comments());
2088 EXPECT_EQ(expected_leading_comments,
2089 iter->second->leading_comments());
2090 }
2091 if (expected_trailing_comments == NULL) {
2092 EXPECT_FALSE(iter->second->has_trailing_comments());
2093 } else {
2094 EXPECT_TRUE(iter->second->has_trailing_comments());
2095 EXPECT_EQ(expected_trailing_comments,
2096 iter->second->trailing_comments());
2097 }
Jisi Liu885b6122015-02-28 14:51:22 -08002098 if (expected_leading_detached_comments == NULL) {
2099 EXPECT_EQ(0, iter->second->leading_detached_comments_size());
2100 } else {
2101 EXPECT_EQ(
2102 expected_leading_detached_comments,
2103 Join(iter->second->leading_detached_comments(), "\n"));
2104 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002105
liujisi@google.com33165fe2010-11-02 13:14:58 +00002106 spans_.erase(iter);
2107 return true;
2108 }
2109 }
2110
2111 return false;
2112 }
2113 }
2114
2115 private:
2116 struct SpanKey {
2117 const Message* descriptor_proto;
2118 const FieldDescriptor* field;
2119 int index;
2120
2121 inline SpanKey() {}
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002122 inline SpanKey(const Message& descriptor_proto_param,
2123 const FieldDescriptor* field_param,
2124 int index_param)
2125 : descriptor_proto(&descriptor_proto_param), field(field_param),
2126 index(index_param) {}
liujisi@google.com33165fe2010-11-02 13:14:58 +00002127
2128 inline bool operator<(const SpanKey& other) const {
2129 if (descriptor_proto < other.descriptor_proto) return true;
2130 if (descriptor_proto > other.descriptor_proto) return false;
2131 if (field < other.field) return true;
2132 if (field > other.field) return false;
2133 return index < other.index;
2134 }
2135 };
2136
2137 typedef multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
2138 SpanMap spans_;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002139 map<char, pair<int, int> > markers_;
2140 string text_without_markers_;
2141
2142 void ExtractMarkers(const char* text) {
2143 markers_.clear();
2144 text_without_markers_.clear();
2145 int line = 0;
2146 int column = 0;
2147 while (*text != '\0') {
2148 if (*text == '$') {
2149 ++text;
2150 GOOGLE_CHECK_NE('\0', *text);
2151 if (*text == '$') {
2152 text_without_markers_ += '$';
2153 ++column;
2154 } else {
Jisi Liu885b6122015-02-28 14:51:22 -08002155 markers_[*text] = std::make_pair(line, column);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002156 ++text;
2157 GOOGLE_CHECK_EQ('$', *text);
2158 }
2159 } else if (*text == '\n') {
2160 ++line;
2161 column = 0;
2162 text_without_markers_ += *text;
2163 } else {
2164 text_without_markers_ += *text;
2165 ++column;
2166 }
2167 ++text;
2168 }
2169 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00002170};
2171
2172TEST_F(SourceInfoTest, BasicFileDecls) {
2173 EXPECT_TRUE(Parse(
Jisi Liu885b6122015-02-28 14:51:22 -08002174 "$a$syntax = \"proto2\";$i$\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002175 "package $b$foo.bar$c$;\n"
2176 "import $d$\"baz.proto\"$e$;\n"
2177 "import $f$\"qux.proto\"$g$;$h$\n"
2178 "\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002179 "// comment ignored\n"));
2180
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002181 EXPECT_TRUE(HasSpan('a', 'h', file_));
2182 EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
2183 EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
2184 EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
Jisi Liu885b6122015-02-28 14:51:22 -08002185 EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002186}
2187
2188TEST_F(SourceInfoTest, Messages) {
2189 EXPECT_TRUE(Parse(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002190 "$a$message $b$Foo$c$ {}$d$\n"
2191 "$e$message $f$Bar$g$ {}$h$\n"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002192
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002193 EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0)));
2194 EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name"));
2195 EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1)));
2196 EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002197
2198 // Ignore these.
2199 EXPECT_TRUE(HasSpan(file_));
2200}
2201
2202TEST_F(SourceInfoTest, Fields) {
2203 EXPECT_TRUE(Parse(
2204 "message Foo {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002205 " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
2206 " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002207 "}\n"));
2208
2209 const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
2210 const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
2211
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002212 EXPECT_TRUE(HasSpan('a', 'i', field1));
2213 EXPECT_TRUE(HasSpan('a', 'b', field1, "label"));
2214 EXPECT_TRUE(HasSpan('c', 'd', field1, "type"));
2215 EXPECT_TRUE(HasSpan('e', 'f', field1, "name"));
2216 EXPECT_TRUE(HasSpan('g', 'h', field1, "number"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002217
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002218 EXPECT_TRUE(HasSpan('j', 'r', field2));
2219 EXPECT_TRUE(HasSpan('j', 'k', field2, "label"));
2220 EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name"));
2221 EXPECT_TRUE(HasSpan('n', 'o', field2, "name"));
2222 EXPECT_TRUE(HasSpan('p', 'q', field2, "number"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002223
2224 // Ignore these.
2225 EXPECT_TRUE(HasSpan(file_));
2226 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2227 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2228}
2229
2230TEST_F(SourceInfoTest, Extensions) {
2231 EXPECT_TRUE(Parse(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002232 "$a$extend $b$Foo$c$ {\n"
2233 " $d$optional$e$ int32 bar = 1;$f$\n"
2234 " $g$repeated$h$ X.Y baz = 2;$i$\n"
2235 "}$j$\n"
2236 "$k$extend $l$Bar$m$ {\n"
2237 " $n$optional int32 qux = 1;$o$\n"
2238 "}$p$\n"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002239
2240 const FieldDescriptorProto& field1 = file_.extension(0);
2241 const FieldDescriptorProto& field2 = file_.extension(1);
2242 const FieldDescriptorProto& field3 = file_.extension(2);
2243
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002244 EXPECT_TRUE(HasSpan('a', 'j', file_, "extension"));
2245 EXPECT_TRUE(HasSpan('k', 'p', file_, "extension"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002246
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002247 EXPECT_TRUE(HasSpan('d', 'f', field1));
2248 EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
2249 EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002250
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002251 EXPECT_TRUE(HasSpan('g', 'i', field2));
2252 EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
2253 EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002254
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002255 EXPECT_TRUE(HasSpan('n', 'o', field3));
2256 EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002257
2258 // Ignore these.
2259 EXPECT_TRUE(HasSpan(file_));
2260 EXPECT_TRUE(HasSpan(field1, "type"));
2261 EXPECT_TRUE(HasSpan(field1, "name"));
2262 EXPECT_TRUE(HasSpan(field1, "number"));
2263 EXPECT_TRUE(HasSpan(field2, "type_name"));
2264 EXPECT_TRUE(HasSpan(field2, "name"));
2265 EXPECT_TRUE(HasSpan(field2, "number"));
2266 EXPECT_TRUE(HasSpan(field3, "label"));
2267 EXPECT_TRUE(HasSpan(field3, "type"));
2268 EXPECT_TRUE(HasSpan(field3, "name"));
2269 EXPECT_TRUE(HasSpan(field3, "number"));
2270}
2271
2272TEST_F(SourceInfoTest, NestedExtensions) {
2273 EXPECT_TRUE(Parse(
2274 "message Message {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002275 " $a$extend $b$Foo$c$ {\n"
2276 " $d$optional$e$ int32 bar = 1;$f$\n"
2277 " $g$repeated$h$ X.Y baz = 2;$i$\n"
2278 " }$j$\n"
2279 " $k$extend $l$Bar$m$ {\n"
2280 " $n$optional int32 qux = 1;$o$\n"
2281 " }$p$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002282 "}\n"));
2283
2284 const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
2285 const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
2286 const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
2287
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002288 EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension"));
2289 EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002290
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002291 EXPECT_TRUE(HasSpan('d', 'f', field1));
2292 EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
2293 EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002294
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002295 EXPECT_TRUE(HasSpan('g', 'i', field2));
2296 EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
2297 EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002298
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002299 EXPECT_TRUE(HasSpan('n', 'o', field3));
2300 EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002301
2302 // Ignore these.
2303 EXPECT_TRUE(HasSpan(file_));
2304 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2305 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2306 EXPECT_TRUE(HasSpan(field1, "type"));
2307 EXPECT_TRUE(HasSpan(field1, "name"));
2308 EXPECT_TRUE(HasSpan(field1, "number"));
2309 EXPECT_TRUE(HasSpan(field2, "type_name"));
2310 EXPECT_TRUE(HasSpan(field2, "name"));
2311 EXPECT_TRUE(HasSpan(field2, "number"));
2312 EXPECT_TRUE(HasSpan(field3, "label"));
2313 EXPECT_TRUE(HasSpan(field3, "type"));
2314 EXPECT_TRUE(HasSpan(field3, "name"));
2315 EXPECT_TRUE(HasSpan(field3, "number"));
2316}
2317
2318TEST_F(SourceInfoTest, ExtensionRanges) {
2319 EXPECT_TRUE(Parse(
2320 "message Message {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002321 " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
2322 " $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002323 "}\n"));
2324
2325 const DescriptorProto::ExtensionRange& range1 =
2326 file_.message_type(0).extension_range(0);
2327 const DescriptorProto::ExtensionRange& range2 =
2328 file_.message_type(0).extension_range(1);
2329 const DescriptorProto::ExtensionRange& range3 =
2330 file_.message_type(0).extension_range(2);
2331
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002332 EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range"));
2333 EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002334
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002335 EXPECT_TRUE(HasSpan('b', 'e', range1));
2336 EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
2337 EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002338
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002339 EXPECT_TRUE(HasSpan('f', 'g', range2));
2340 EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
2341 EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002342
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002343 EXPECT_TRUE(HasSpan('j', 'm', range3));
2344 EXPECT_TRUE(HasSpan('j', 'k', range3, "start"));
2345 EXPECT_TRUE(HasSpan('l', 'm', range3, "end"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002346
2347 // Ignore these.
2348 EXPECT_TRUE(HasSpan(file_));
2349 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2350 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2351}
2352
jieluo@google.com4de8f552014-07-18 00:47:59 +00002353TEST_F(SourceInfoTest, Oneofs) {
2354 EXPECT_TRUE(Parse(
2355 "message Foo {\n"
2356 " $a$oneof $c$foo$d$ {\n"
2357 " $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n"
2358 " }$r$\n"
2359 "}\n"));
2360
2361 const OneofDescriptorProto& oneof_decl = file_.message_type(0).oneof_decl(0);
2362 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2363
2364 EXPECT_TRUE(HasSpan('a', 'r', oneof_decl));
2365 EXPECT_TRUE(HasSpan('c', 'd', oneof_decl, "name"));
2366
2367 EXPECT_TRUE(HasSpan('e', 'k', field));
2368 EXPECT_TRUE(HasSpan('e', 'f', field, "type"));
2369 EXPECT_TRUE(HasSpan('g', 'h', field, "name"));
2370 EXPECT_TRUE(HasSpan('i', 'j', field, "number"));
2371
2372 // Ignore these.
2373 EXPECT_TRUE(HasSpan(file_));
2374 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2375 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2376}
2377
liujisi@google.com33165fe2010-11-02 13:14:58 +00002378TEST_F(SourceInfoTest, NestedMessages) {
2379 EXPECT_TRUE(Parse(
2380 "message Foo {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002381 " $a$message $b$Bar$c$ {\n"
2382 " $d$message $e$Baz$f$ {}$g$\n"
2383 " }$h$\n"
2384 " $i$message $j$Qux$k$ {}$l$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002385 "}\n"));
2386
2387 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
2388 const DescriptorProto& baz = bar.nested_type(0);
2389 const DescriptorProto& qux = file_.message_type(0).nested_type(1);
2390
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002391 EXPECT_TRUE(HasSpan('a', 'h', bar));
2392 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
2393 EXPECT_TRUE(HasSpan('d', 'g', baz));
2394 EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
2395 EXPECT_TRUE(HasSpan('i', 'l', qux));
2396 EXPECT_TRUE(HasSpan('j', 'k', qux, "name"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002397
2398 // Ignore these.
2399 EXPECT_TRUE(HasSpan(file_));
2400 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2401 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2402}
2403
2404TEST_F(SourceInfoTest, Groups) {
2405 EXPECT_TRUE(Parse(
2406 "message Foo {\n"
2407 " message Bar {}\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002408 " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
2409 " $i$message Qux {}$j$\n"
2410 " }$k$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002411 "}\n"));
2412
2413 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
2414 const DescriptorProto& baz = file_.message_type(0).nested_type(1);
2415 const DescriptorProto& qux = baz.nested_type(0);
2416 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2417
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002418 EXPECT_TRUE(HasSpan('a', 'k', field));
2419 EXPECT_TRUE(HasSpan('a', 'b', field, "label"));
2420 EXPECT_TRUE(HasSpan('c', 'd', field, "type"));
2421 EXPECT_TRUE(HasSpan('e', 'f', field, "name"));
2422 EXPECT_TRUE(HasSpan('e', 'f', field, "type_name"));
2423 EXPECT_TRUE(HasSpan('g', 'h', field, "number"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002424
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002425 EXPECT_TRUE(HasSpan('a', 'k', baz));
2426 EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
2427 EXPECT_TRUE(HasSpan('i', 'j', qux));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002428
2429 // Ignore these.
2430 EXPECT_TRUE(HasSpan(file_));
2431 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2432 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2433 EXPECT_TRUE(HasSpan(bar));
2434 EXPECT_TRUE(HasSpan(bar, "name"));
2435 EXPECT_TRUE(HasSpan(qux, "name"));
2436}
2437
2438TEST_F(SourceInfoTest, Enums) {
2439 EXPECT_TRUE(Parse(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002440 "$a$enum $b$Foo$c$ {}$d$\n"
2441 "$e$enum $f$Bar$g$ {}$h$\n"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002442
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002443 EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0)));
2444 EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name"));
2445 EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1)));
2446 EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002447
2448 // Ignore these.
2449 EXPECT_TRUE(HasSpan(file_));
2450}
2451
2452TEST_F(SourceInfoTest, EnumValues) {
2453 EXPECT_TRUE(Parse(
2454 "enum Foo {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002455 " $a$BAR$b$ = $c$1$d$;$e$\n"
2456 " $f$BAZ$g$ = $h$2$i$;$j$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002457 "}"));
2458
2459 const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
2460 const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
2461
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002462 EXPECT_TRUE(HasSpan('a', 'e', bar));
2463 EXPECT_TRUE(HasSpan('a', 'b', bar, "name"));
2464 EXPECT_TRUE(HasSpan('c', 'd', bar, "number"));
2465 EXPECT_TRUE(HasSpan('f', 'j', baz));
2466 EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
2467 EXPECT_TRUE(HasSpan('h', 'i', baz, "number"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002468
2469 // Ignore these.
2470 EXPECT_TRUE(HasSpan(file_));
2471 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2472 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2473}
2474
2475TEST_F(SourceInfoTest, NestedEnums) {
2476 EXPECT_TRUE(Parse(
2477 "message Foo {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002478 " $a$enum $b$Bar$c$ {}$d$\n"
2479 " $e$enum $f$Baz$g$ {}$h$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002480 "}\n"));
2481
2482 const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
2483 const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
2484
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002485 EXPECT_TRUE(HasSpan('a', 'd', bar));
2486 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
2487 EXPECT_TRUE(HasSpan('e', 'h', baz));
2488 EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002489
2490 // Ignore these.
2491 EXPECT_TRUE(HasSpan(file_));
2492 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2493 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2494}
2495
2496TEST_F(SourceInfoTest, Services) {
2497 EXPECT_TRUE(Parse(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002498 "$a$service $b$Foo$c$ {}$d$\n"
2499 "$e$service $f$Bar$g$ {}$h$\n"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002500
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002501 EXPECT_TRUE(HasSpan('a', 'd', file_.service(0)));
2502 EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name"));
2503 EXPECT_TRUE(HasSpan('e', 'h', file_.service(1)));
2504 EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002505
2506 // Ignore these.
2507 EXPECT_TRUE(HasSpan(file_));
2508}
2509
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002510TEST_F(SourceInfoTest, MethodsAndStreams) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00002511 EXPECT_TRUE(Parse(
2512 "service Foo {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002513 " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
2514 " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002515 "}"));
2516
2517 const MethodDescriptorProto& bar = file_.service(0).method(0);
2518 const MethodDescriptorProto& baz = file_.service(0).method(1);
2519
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002520 EXPECT_TRUE(HasSpan('a', 'h', bar));
2521 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
2522 EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type"));
2523 EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002524
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002525 EXPECT_TRUE(HasSpan('i', 'p', baz));
2526 EXPECT_TRUE(HasSpan('j', 'k', baz, "name"));
2527 EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type"));
2528 EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002529
2530 // Ignore these.
2531 EXPECT_TRUE(HasSpan(file_));
2532 EXPECT_TRUE(HasSpan(file_.service(0)));
2533 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
2534}
2535
jieluo@google.com4de8f552014-07-18 00:47:59 +00002536
liujisi@google.com33165fe2010-11-02 13:14:58 +00002537TEST_F(SourceInfoTest, Options) {
2538 EXPECT_TRUE(Parse(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002539 "$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
2540 "$h$123$i$;$j$\n"
2541 "$k$option qux = $l$-123$m$;$n$\n"
2542 "$o$option corge = $p$abc$q$;$r$\n"
2543 "$s$option grault = $t$'blah'$u$;$v$\n"
2544 "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
2545 "$0$option waldo = $1$123.0$2$;$3$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002546 ));
2547
2548 const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
2549 const UninterpretedOption& option2 = file_.options().uninterpreted_option(1);
2550 const UninterpretedOption& option3 = file_.options().uninterpreted_option(2);
2551 const UninterpretedOption& option4 = file_.options().uninterpreted_option(3);
2552 const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
2553 const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
2554
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002555 EXPECT_TRUE(HasSpan('a', 'j', file_.options()));
2556 EXPECT_TRUE(HasSpan('a', 'j', option1));
2557 EXPECT_TRUE(HasSpan('b', 'g', option1, "name"));
2558 EXPECT_TRUE(HasSpan('b', 'c', option1.name(0)));
2559 EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part"));
2560 EXPECT_TRUE(HasSpan('d', 'g', option1.name(1)));
2561 EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part"));
2562 EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002563
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002564 EXPECT_TRUE(HasSpan('k', 'n', file_.options()));
2565 EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002566
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002567 EXPECT_TRUE(HasSpan('o', 'r', file_.options()));
2568 EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002569
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002570 EXPECT_TRUE(HasSpan('s', 'v', file_.options()));
2571 EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002572
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002573 EXPECT_TRUE(HasSpan('w', 'z', file_.options()));
2574 EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002575
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002576 EXPECT_TRUE(HasSpan('0', '3', file_.options()));
2577 EXPECT_TRUE(HasSpan('1', '2', option6, "double_value"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002578
2579 // Ignore these.
2580 EXPECT_TRUE(HasSpan(file_));
2581 EXPECT_TRUE(HasSpan(option2));
2582 EXPECT_TRUE(HasSpan(option3));
2583 EXPECT_TRUE(HasSpan(option4));
2584 EXPECT_TRUE(HasSpan(option5));
2585 EXPECT_TRUE(HasSpan(option6));
2586 EXPECT_TRUE(HasSpan(option2, "name"));
2587 EXPECT_TRUE(HasSpan(option3, "name"));
2588 EXPECT_TRUE(HasSpan(option4, "name"));
2589 EXPECT_TRUE(HasSpan(option5, "name"));
2590 EXPECT_TRUE(HasSpan(option6, "name"));
2591 EXPECT_TRUE(HasSpan(option2.name(0)));
2592 EXPECT_TRUE(HasSpan(option3.name(0)));
2593 EXPECT_TRUE(HasSpan(option4.name(0)));
2594 EXPECT_TRUE(HasSpan(option5.name(0)));
2595 EXPECT_TRUE(HasSpan(option6.name(0)));
2596 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2597 EXPECT_TRUE(HasSpan(option3.name(0), "name_part"));
2598 EXPECT_TRUE(HasSpan(option4.name(0), "name_part"));
2599 EXPECT_TRUE(HasSpan(option5.name(0), "name_part"));
2600 EXPECT_TRUE(HasSpan(option6.name(0), "name_part"));
2601}
2602
2603TEST_F(SourceInfoTest, ScopedOptions) {
2604 EXPECT_TRUE(Parse(
2605 "message Foo {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002606 " $a$option mopt = 1;$b$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002607 "}\n"
2608 "enum Bar {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002609 " $c$option eopt = 1;$d$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002610 "}\n"
2611 "service Baz {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002612 " $e$option sopt = 1;$f$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002613 " rpc M(X) returns(Y) {\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002614 " $g$option mopt = 1;$h$\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002615 " }\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002616 " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
2617 " $k$option mopt = 1;$l$\n"
2618 " }\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002619 "}\n"));
2620
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002621 EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
2622 EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options()));
2623 EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options()));
2624 EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options()));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002625
2626 // Ignore these.
2627 EXPECT_TRUE(HasSpan(file_));
2628 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2629 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2630 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2631 .uninterpreted_option(0)));
2632 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2633 .uninterpreted_option(0), "name"));
2634 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2635 .uninterpreted_option(0).name(0)));
2636 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2637 .uninterpreted_option(0).name(0), "name_part"));
2638 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2639 .uninterpreted_option(0), "positive_int_value"));
2640 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2641 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2642 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2643 .uninterpreted_option(0)));
2644 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2645 .uninterpreted_option(0), "name"));
2646 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2647 .uninterpreted_option(0).name(0)));
2648 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2649 .uninterpreted_option(0).name(0), "name_part"));
2650 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2651 .uninterpreted_option(0), "positive_int_value"));
2652 EXPECT_TRUE(HasSpan(file_.service(0)));
2653 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
2654 EXPECT_TRUE(HasSpan(file_.service(0).method(0)));
2655 EXPECT_TRUE(HasSpan(file_.service(0).options()
2656 .uninterpreted_option(0)));
2657 EXPECT_TRUE(HasSpan(file_.service(0).options()
2658 .uninterpreted_option(0), "name"));
2659 EXPECT_TRUE(HasSpan(file_.service(0).options()
2660 .uninterpreted_option(0).name(0)));
2661 EXPECT_TRUE(HasSpan(file_.service(0).options()
2662 .uninterpreted_option(0).name(0), "name_part"));
2663 EXPECT_TRUE(HasSpan(file_.service(0).options()
2664 .uninterpreted_option(0), "positive_int_value"));
2665 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name"));
2666 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type"));
2667 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type"));
2668 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2669 .uninterpreted_option(0)));
2670 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2671 .uninterpreted_option(0), "name"));
2672 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2673 .uninterpreted_option(0).name(0)));
2674 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2675 .uninterpreted_option(0).name(0), "name_part"));
2676 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2677 .uninterpreted_option(0), "positive_int_value"));
Jisi Liu885b6122015-02-28 14:51:22 -08002678
2679 EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
2680 EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
2681 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
2682 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
2683 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
2684 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2685 .uninterpreted_option(0)));
2686 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2687 .uninterpreted_option(0), "name"));
2688 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2689 .uninterpreted_option(0).name(0)));
2690 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2691 .uninterpreted_option(0).name(0), "name_part"));
2692 EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
2693 .uninterpreted_option(0), "positive_int_value"));
2694 EXPECT_TRUE(HasSpan('1', '2', file_.service(0).method(1),
2695 "client_streaming"));
2696 EXPECT_TRUE(HasSpan('3', '4', file_.service(0).method(1),
2697 "server_streaming"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002698}
2699
2700TEST_F(SourceInfoTest, FieldOptions) {
2701 // The actual "name = value" pairs are parsed by the same code as for
2702 // top-level options so we won't re-test that -- just make sure that the
2703 // syntax used for field options is understood.
2704 EXPECT_TRUE(Parse(
2705 "message Foo {"
2706 " optional int32 bar = 1 "
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002707 "$a$[default=$b$123$c$,$d$opt1=123$e$,"
2708 "$f$opt2='hi'$g$]$h$;"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002709 "}\n"
2710 ));
2711
2712 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2713 const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
2714 const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
2715
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002716 EXPECT_TRUE(HasSpan('a', 'h', field.options()));
2717 EXPECT_TRUE(HasSpan('b', 'c', field, "default_value"));
2718 EXPECT_TRUE(HasSpan('d', 'e', option1));
2719 EXPECT_TRUE(HasSpan('f', 'g', option2));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002720
2721 // Ignore these.
2722 EXPECT_TRUE(HasSpan(file_));
2723 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2724 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2725 EXPECT_TRUE(HasSpan(field));
2726 EXPECT_TRUE(HasSpan(field, "label"));
2727 EXPECT_TRUE(HasSpan(field, "type"));
2728 EXPECT_TRUE(HasSpan(field, "name"));
2729 EXPECT_TRUE(HasSpan(field, "number"));
2730 EXPECT_TRUE(HasSpan(option1, "name"));
2731 EXPECT_TRUE(HasSpan(option2, "name"));
2732 EXPECT_TRUE(HasSpan(option1.name(0)));
2733 EXPECT_TRUE(HasSpan(option2.name(0)));
2734 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
2735 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2736 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
2737 EXPECT_TRUE(HasSpan(option2, "string_value"));
2738}
2739
2740TEST_F(SourceInfoTest, EnumValueOptions) {
2741 // The actual "name = value" pairs are parsed by the same code as for
2742 // top-level options so we won't re-test that -- just make sure that the
2743 // syntax used for enum options is understood.
2744 EXPECT_TRUE(Parse(
2745 "enum Foo {"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002746 " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
liujisi@google.com33165fe2010-11-02 13:14:58 +00002747 "}\n"
2748 ));
2749
2750 const EnumValueDescriptorProto& value = file_.enum_type(0).value(0);
2751 const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
2752 const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
2753
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002754 EXPECT_TRUE(HasSpan('a', 'f', value.options()));
2755 EXPECT_TRUE(HasSpan('b', 'c', option1));
2756 EXPECT_TRUE(HasSpan('d', 'e', option2));
liujisi@google.com33165fe2010-11-02 13:14:58 +00002757
2758 // Ignore these.
2759 EXPECT_TRUE(HasSpan(file_));
2760 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2761 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2762 EXPECT_TRUE(HasSpan(value));
2763 EXPECT_TRUE(HasSpan(value, "name"));
2764 EXPECT_TRUE(HasSpan(value, "number"));
2765 EXPECT_TRUE(HasSpan(option1, "name"));
2766 EXPECT_TRUE(HasSpan(option2, "name"));
2767 EXPECT_TRUE(HasSpan(option1.name(0)));
2768 EXPECT_TRUE(HasSpan(option2.name(0)));
2769 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
2770 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2771 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
2772 EXPECT_TRUE(HasSpan(option2, "string_value"));
2773}
2774
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002775TEST_F(SourceInfoTest, DocComments) {
2776 EXPECT_TRUE(Parse(
2777 "// Foo leading\n"
2778 "// line 2\n"
2779 "$a$message Foo {\n"
2780 " // Foo trailing\n"
2781 " // line 2\n"
2782 "\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002783 " // detached\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002784 "\n"
2785 " // bar leading\n"
2786 " $b$optional int32 bar = 1;$c$\n"
2787 " // bar trailing\n"
2788 "}$d$\n"
2789 "// ignored\n"
2790 ));
2791
2792 const DescriptorProto& foo = file_.message_type(0);
2793 const FieldDescriptorProto& bar = foo.field(0);
2794
2795 EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
2796 " Foo leading\n line 2\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002797 " Foo trailing\n line 2\n",
2798 NULL));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002799 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
2800 " bar leading\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002801 " bar trailing\n",
2802 " detached\n"));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002803
2804 // Ignore these.
2805 EXPECT_TRUE(HasSpan(file_));
2806 EXPECT_TRUE(HasSpan(foo, "name"));
2807 EXPECT_TRUE(HasSpan(bar, "label"));
2808 EXPECT_TRUE(HasSpan(bar, "type"));
2809 EXPECT_TRUE(HasSpan(bar, "name"));
2810 EXPECT_TRUE(HasSpan(bar, "number"));
2811}
2812
2813TEST_F(SourceInfoTest, DocComments2) {
2814 EXPECT_TRUE(Parse(
Jisi Liu885b6122015-02-28 14:51:22 -08002815 "// detached before message.\n"
2816 "\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002817 "// Foo leading\n"
2818 "// line 2\n"
2819 "$a$message Foo {\n"
2820 " /* Foo trailing\n"
2821 " * line 2 */\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002822 " // detached\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002823 " /* bar leading\n"
2824 " */"
2825 " $b$optional int32 bar = 1;$c$ // bar trailing\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002826 " // ignored detached\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002827 "}$d$\n"
2828 "// ignored\n"
2829 "\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002830 "// detached before option\n"
2831 "\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002832 "// option leading\n"
2833 "$e$option baz = 123;$f$\n"
2834 "// option trailing\n"
2835 ));
2836
2837 const DescriptorProto& foo = file_.message_type(0);
2838 const FieldDescriptorProto& bar = foo.field(0);
2839 const UninterpretedOption& baz = file_.options().uninterpreted_option(0);
2840
2841 EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
2842 " Foo leading\n line 2\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002843 " Foo trailing\n line 2 ",
2844 " detached before message.\n"));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002845 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
2846 " bar leading\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002847 " bar trailing\n",
2848 " detached\n"));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002849 EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
2850 " option leading\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002851 " option trailing\n",
2852 " detached before option\n"));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002853
2854 // Ignore these.
2855 EXPECT_TRUE(HasSpan(file_));
2856 EXPECT_TRUE(HasSpan(foo, "name"));
2857 EXPECT_TRUE(HasSpan(bar, "label"));
2858 EXPECT_TRUE(HasSpan(bar, "type"));
2859 EXPECT_TRUE(HasSpan(bar, "name"));
2860 EXPECT_TRUE(HasSpan(bar, "number"));
2861 EXPECT_TRUE(HasSpan(file_.options()));
2862 EXPECT_TRUE(HasSpan(baz, "name"));
2863 EXPECT_TRUE(HasSpan(baz.name(0)));
2864 EXPECT_TRUE(HasSpan(baz.name(0), "name_part"));
2865 EXPECT_TRUE(HasSpan(baz, "positive_int_value"));
2866}
2867
2868TEST_F(SourceInfoTest, DocComments3) {
2869 EXPECT_TRUE(Parse(
2870 "$a$message Foo {\n"
2871 " // bar leading\n"
2872 " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
2873 " // bar trailing\n"
2874 "}$d$\n"
2875 "// ignored\n"
2876 ));
2877
2878 const DescriptorProto& foo = file_.message_type(0);
2879 const FieldDescriptorProto& bar = foo.field(0);
2880
2881 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
2882 " bar leading\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002883 " bar trailing\n",
2884 NULL));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002885
2886 // Ignore these.
2887 EXPECT_TRUE(HasSpan(file_));
2888 EXPECT_TRUE(HasSpan(foo));
2889 EXPECT_TRUE(HasSpan(foo, "name"));
2890 EXPECT_TRUE(HasSpan(bar, "label"));
2891 EXPECT_TRUE(HasSpan(bar, "type"));
2892 EXPECT_TRUE(HasSpan(bar, "name"));
2893 EXPECT_TRUE(HasSpan(bar, "number"));
2894 EXPECT_TRUE(HasSpan(bar.options()));
2895 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0)));
2896 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name"));
2897 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0)));
2898 EXPECT_TRUE(HasSpan(
2899 bar.options().uninterpreted_option(0).name(0), "name_part"));
2900 EXPECT_TRUE(HasSpan(
2901 bar.options().uninterpreted_option(0), "aggregate_value"));
2902}
2903
Jisi Liu885b6122015-02-28 14:51:22 -08002904TEST_F(SourceInfoTest, DocCommentsTopLevel) {
2905 EXPECT_TRUE(Parse(
2906 "// detached before syntax paragraph 1\n"
2907 "\n"
2908 "// detached before syntax paragraph 2\n"
2909 "\n"
2910 "// syntax leading\n"
2911 "$a$syntax = \"proto2\";$b$\n"
2912 "// syntax trailing\n"
2913 "\n"
2914 "// syntax-package detached comments\n"
2915 "\n"
2916 ";\n"
2917 "\n"
2918 "// detached after empty before package\n"
2919 "\n"
2920 "// package leading\n"
2921 "package $c$foo$d$;\n"
2922 "// package trailing\n"
2923 "\n"
2924 "// ignored detach\n"
2925 "\n"));
2926
2927 EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1,
2928 " syntax leading\n",
2929 " syntax trailing\n",
2930 " detached before syntax paragraph 1\n"
2931 "\n"
2932 " detached before syntax paragraph 2\n"));
2933 EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1,
2934 " package leading\n",
2935 " package trailing\n",
2936 " syntax-package detached comments\n"
2937 "\n"
2938 " detached after empty before package\n"));
2939
2940 // ignore these.
2941 EXPECT_TRUE(HasSpan(file_));
2942}
2943
jieluo@google.com4de8f552014-07-18 00:47:59 +00002944TEST_F(SourceInfoTest, DocCommentsOneof) {
2945 EXPECT_TRUE(Parse(
jieluo@google.com4de8f552014-07-18 00:47:59 +00002946 "// Foo leading\n"
2947 "$a$message Foo {\n"
2948 " /* Foo trailing\n"
2949 " */\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002950 " // detached before oneof\n"
jieluo@google.com4de8f552014-07-18 00:47:59 +00002951 " /* bar leading\n"
2952 " * line 2 */\n"
2953 " $b$oneof bar {\n"
2954 " /* bar trailing\n"
2955 " * line 2 */\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002956 " // detached before bar_int\n"
jieluo@google.com4de8f552014-07-18 00:47:59 +00002957 " /* bar_int leading\n"
2958 " */\n"
2959 " $c$int32 bar_int = 1;$d$ // bar_int trailing\n"
Jisi Liu885b6122015-02-28 14:51:22 -08002960 " // detach comment ignored\n"
jieluo@google.com4de8f552014-07-18 00:47:59 +00002961 " }$e$\n"
2962 "}$f$\n"));
2963
2964 const DescriptorProto& foo = file_.message_type(0);
2965 const OneofDescriptorProto& bar = foo.oneof_decl(0);
2966 const FieldDescriptorProto& bar_int = foo.field(0);
2967
2968 EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
2969 " Foo leading\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002970 " Foo trailing\n",
2971 NULL));
jieluo@google.com4de8f552014-07-18 00:47:59 +00002972 EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
2973 " bar leading\n line 2 ",
Jisi Liu885b6122015-02-28 14:51:22 -08002974 " bar trailing\n line 2 ",
2975 " detached before oneof\n"));
jieluo@google.com4de8f552014-07-18 00:47:59 +00002976 EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
2977 " bar_int leading\n",
Jisi Liu885b6122015-02-28 14:51:22 -08002978 " bar_int trailing\n",
2979 " detached before bar_int\n"));
jieluo@google.com4de8f552014-07-18 00:47:59 +00002980
2981 // Ignore these.
2982 EXPECT_TRUE(HasSpan(file_));
2983 EXPECT_TRUE(HasSpan(foo, "name"));
2984 EXPECT_TRUE(HasSpan(bar, "name"));
2985 EXPECT_TRUE(HasSpan(bar_int, "type"));
2986 EXPECT_TRUE(HasSpan(bar_int, "name"));
2987 EXPECT_TRUE(HasSpan(bar_int, "number"));
2988}
2989
liujisi@google.com33165fe2010-11-02 13:14:58 +00002990// ===================================================================
temporal40ee5512008-07-10 02:12:20 +00002991
2992} // anonymous namespace
2993
2994} // namespace compiler
2995} // namespace protobuf
2996} // namespace google