blob: 156c0dc3c8ae71d7f9273ec3ff5c2986bfbf27ce [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.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
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
35#include <vector>
36#include <algorithm>
liujisi@google.com33165fe2010-11-02 13:14:58 +000037#include <map>
temporal40ee5512008-07-10 02:12:20 +000038
39#include <google/protobuf/compiler/parser.h>
40
41#include <google/protobuf/io/tokenizer.h>
42#include <google/protobuf/io/zero_copy_stream_impl.h>
43#include <google/protobuf/descriptor.pb.h>
44#include <google/protobuf/wire_format.h>
45#include <google/protobuf/text_format.h>
46#include <google/protobuf/unittest.pb.h>
47#include <google/protobuf/stubs/strutil.h>
48#include <google/protobuf/stubs/substitute.h>
liujisi@google.com33165fe2010-11-02 13:14:58 +000049#include <google/protobuf/stubs/map-util.h>
temporal40ee5512008-07-10 02:12:20 +000050
51#include <google/protobuf/testing/googletest.h>
52#include <gtest/gtest.h>
53
54namespace google {
55namespace protobuf {
56namespace compiler {
57
58namespace {
59
60class MockErrorCollector : public io::ErrorCollector {
61 public:
62 MockErrorCollector() {}
63 ~MockErrorCollector() {}
64
65 string text_;
66
67 // implements ErrorCollector ---------------------------------------
68 void AddError(int line, int column, const string& message) {
69 strings::SubstituteAndAppend(&text_, "$0:$1: $2\n",
70 line, column, message);
71 }
72};
73
74class MockValidationErrorCollector : public DescriptorPool::ErrorCollector {
75 public:
76 MockValidationErrorCollector(const SourceLocationTable& source_locations,
77 io::ErrorCollector* wrapped_collector)
78 : source_locations_(source_locations),
79 wrapped_collector_(wrapped_collector) {}
80 ~MockValidationErrorCollector() {}
81
82 // implements ErrorCollector ---------------------------------------
83 void AddError(const string& filename,
84 const string& element_name,
85 const Message* descriptor,
86 ErrorLocation location,
87 const string& message) {
88 int line, column;
89 source_locations_.Find(descriptor, location, &line, &column);
90 wrapped_collector_->AddError(line, column, message);
91 }
92
93 private:
94 const SourceLocationTable& source_locations_;
95 io::ErrorCollector* wrapped_collector_;
96};
97
98class ParserTest : public testing::Test {
99 protected:
100 ParserTest()
101 : require_syntax_identifier_(false) {}
102
103 // Set up the parser to parse the given text.
104 void SetupParser(const char* text) {
105 raw_input_.reset(new io::ArrayInputStream(text, strlen(text)));
106 input_.reset(new io::Tokenizer(raw_input_.get(), &error_collector_));
107 parser_.reset(new Parser());
108 parser_->RecordErrorsTo(&error_collector_);
109 parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_);
110 }
111
112 // Parse the input and expect that the resulting FileDescriptorProto matches
113 // the given output. The output is a FileDescriptorProto in protocol buffer
114 // text format.
115 void ExpectParsesTo(const char* input, const char* output) {
116 SetupParser(input);
117 FileDescriptorProto actual, expected;
118
119 parser_->Parse(input_.get(), &actual);
120 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
121 ASSERT_EQ("", error_collector_.text_);
122
liujisi@google.com33165fe2010-11-02 13:14:58 +0000123 // We don't cover SourceCodeInfo in these tests.
124 actual.clear_source_code_info();
125
temporal40ee5512008-07-10 02:12:20 +0000126 // Parse the ASCII representation in order to canonicalize it. We could
127 // just compare directly to actual.DebugString(), but that would require
128 // that the caller precisely match the formatting that DebugString()
129 // produces.
130 ASSERT_TRUE(TextFormat::ParseFromString(output, &expected));
131
132 // Compare by comparing debug strings.
133 // TODO(kenton): Use differencer, once it is available.
134 EXPECT_EQ(expected.DebugString(), actual.DebugString());
135 }
136
137 // Parse the text and expect that the given errors are reported.
138 void ExpectHasErrors(const char* text, const char* expected_errors) {
139 ExpectHasEarlyExitErrors(text, expected_errors);
140 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
141 }
142
143 // Same as above but does not expect that the parser parses the complete
144 // input.
145 void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) {
146 SetupParser(text);
147 FileDescriptorProto file;
148 parser_->Parse(input_.get(), &file);
149 EXPECT_EQ(expected_errors, error_collector_.text_);
150 }
151
152 // Parse the text as a file and validate it (with a DescriptorPool), and
153 // expect that the validation step reports the given errors.
154 void ExpectHasValidationErrors(const char* text,
155 const char* expected_errors) {
156 SetupParser(text);
157 SourceLocationTable source_locations;
158 parser_->RecordSourceLocationsTo(&source_locations);
159
160 FileDescriptorProto file;
161 file.set_name("foo.proto");
162 parser_->Parse(input_.get(), &file);
163 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
164 ASSERT_EQ("", error_collector_.text_);
165
166 MockValidationErrorCollector validation_error_collector(
167 source_locations, &error_collector_);
168 EXPECT_TRUE(pool_.BuildFileCollectingErrors(
169 file, &validation_error_collector) == NULL);
170 EXPECT_EQ(expected_errors, error_collector_.text_);
171 }
172
173 MockErrorCollector error_collector_;
174 DescriptorPool pool_;
175
176 scoped_ptr<io::ZeroCopyInputStream> raw_input_;
177 scoped_ptr<io::Tokenizer> input_;
178 scoped_ptr<Parser> parser_;
179 bool require_syntax_identifier_;
180};
181
182// ===================================================================
183
kenton@google.comd37d46d2009-04-25 02:53:47 +0000184TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
185 SetupParser(
186 "// blah\n"
187 "syntax = \"foobar\";\n"
188 "this line will not be parsed\n");
189 parser_->SetStopAfterSyntaxIdentifier(true);
190 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
191 EXPECT_EQ("", error_collector_.text_);
192 EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
193}
194
195TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
196 SetupParser(
197 "// blah\n"
198 "this line will not be parsed\n");
199 parser_->SetStopAfterSyntaxIdentifier(true);
200 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
201 EXPECT_EQ("", error_collector_.text_);
202 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
203}
204
205TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
206 SetupParser(
207 "// blah\n"
208 "syntax = error;\n");
209 parser_->SetStopAfterSyntaxIdentifier(true);
210 EXPECT_FALSE(parser_->Parse(input_.get(), NULL));
211 EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
212}
213
214// ===================================================================
215
temporal40ee5512008-07-10 02:12:20 +0000216typedef ParserTest ParseMessageTest;
217
218TEST_F(ParseMessageTest, SimpleMessage) {
219 ExpectParsesTo(
220 "message TestMessage {\n"
221 " required int32 foo = 1;\n"
222 "}\n",
223
224 "message_type {"
225 " name: \"TestMessage\""
226 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
227 "}");
228}
229
230TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
231 require_syntax_identifier_ = false;
232 ExpectParsesTo(
233 "message TestMessage {\n"
234 " required int32 foo = 1;\n"
235 "}\n",
236
237 "message_type {"
238 " name: \"TestMessage\""
239 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
240 "}");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000241 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000242}
243
244TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
245 ExpectParsesTo(
246 "syntax = \"proto2\";\n"
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, ExplicitRequiredSyntaxIdentifier) {
259 require_syntax_identifier_ = true;
260 ExpectParsesTo(
261 "syntax = \"proto2\";\n"
262 "message TestMessage {\n"
263 " required int32 foo = 1;\n"
264 "}\n",
265
266 "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, SimpleFields) {
274 ExpectParsesTo(
275 "message TestMessage {\n"
276 " required int32 foo = 15;\n"
277 " optional int32 bar = 34;\n"
278 " repeated int32 baz = 3;\n"
279 "}\n",
280
281 "message_type {"
282 " name: \"TestMessage\""
283 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
284 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
285 " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }"
286 "}");
287}
288
289TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
290 ExpectParsesTo(
291 "message TestMessage {\n"
292 " required int32 foo = 1;\n"
293 " required int64 foo = 1;\n"
294 " required uint32 foo = 1;\n"
295 " required uint64 foo = 1;\n"
296 " required sint32 foo = 1;\n"
297 " required sint64 foo = 1;\n"
298 " required fixed32 foo = 1;\n"
299 " required fixed64 foo = 1;\n"
300 " required sfixed32 foo = 1;\n"
301 " required sfixed64 foo = 1;\n"
302 " required float foo = 1;\n"
303 " required double foo = 1;\n"
304 " required string foo = 1;\n"
305 " required bytes foo = 1;\n"
306 " required bool foo = 1;\n"
307 "}\n",
308
309 "message_type {"
310 " name: \"TestMessage\""
311 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
312 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 }"
313 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 }"
314 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 }"
315 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 }"
316 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 }"
317 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 }"
318 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 }"
319 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 }"
320 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 }"
321 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 }"
322 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 }"
323 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 }"
324 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 }"
325 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 }"
326 "}");
327}
328
329TEST_F(ParseMessageTest, FieldDefaults) {
330 ExpectParsesTo(
331 "message TestMessage {\n"
332 " required int32 foo = 1 [default= 1 ];\n"
333 " required int32 foo = 1 [default= -2 ];\n"
334 " required int64 foo = 1 [default= 3 ];\n"
335 " required int64 foo = 1 [default= -4 ];\n"
336 " required uint32 foo = 1 [default= 5 ];\n"
337 " required uint64 foo = 1 [default= 6 ];\n"
338 " required float foo = 1 [default= 7.5];\n"
339 " required float foo = 1 [default= -8.5];\n"
340 " required float foo = 1 [default= 9 ];\n"
341 " required double foo = 1 [default= 10.5];\n"
342 " required double foo = 1 [default=-11.5];\n"
343 " required double foo = 1 [default= 12 ];\n"
kenton@google.comfccb1462009-12-18 02:11:36 +0000344 " required double foo = 1 [default= inf ];\n"
345 " required double foo = 1 [default=-inf ];\n"
346 " required double foo = 1 [default= nan ];\n"
temporal40ee5512008-07-10 02:12:20 +0000347 " required string foo = 1 [default='13\\001'];\n"
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000348 " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
temporal40ee5512008-07-10 02:12:20 +0000349 " required bytes foo = 1 [default='14\\002'];\n"
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000350 " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
temporal40ee5512008-07-10 02:12:20 +0000351 " required bool foo = 1 [default=true ];\n"
352 " required Foo foo = 1 [default=FOO ];\n"
353
354 " required int32 foo = 1 [default= 0x7FFFFFFF];\n"
355 " required int32 foo = 1 [default=-0x80000000];\n"
356 " required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
357 " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
358 " required int64 foo = 1 [default=-0x8000000000000000];\n"
359 " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
360 " required double foo = 1 [default= 0xabcd];\n"
361 "}\n",
362
363#define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
364 "message_type {"
365 " name: \"TestMessage\""
366 " field { type:TYPE_INT32 default_value:\"1\" "ETC" }"
367 " field { type:TYPE_INT32 default_value:\"-2\" "ETC" }"
368 " field { type:TYPE_INT64 default_value:\"3\" "ETC" }"
369 " field { type:TYPE_INT64 default_value:\"-4\" "ETC" }"
370 " field { type:TYPE_UINT32 default_value:\"5\" "ETC" }"
371 " field { type:TYPE_UINT64 default_value:\"6\" "ETC" }"
372 " field { type:TYPE_FLOAT default_value:\"7.5\" "ETC" }"
373 " field { type:TYPE_FLOAT default_value:\"-8.5\" "ETC" }"
374 " field { type:TYPE_FLOAT default_value:\"9\" "ETC" }"
375 " field { type:TYPE_DOUBLE default_value:\"10.5\" "ETC" }"
376 " field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }"
377 " field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }"
kenton@google.comfccb1462009-12-18 02:11:36 +0000378 " field { type:TYPE_DOUBLE default_value:\"inf\" "ETC" }"
379 " field { type:TYPE_DOUBLE default_value:\"-inf\" "ETC" }"
380 " field { type:TYPE_DOUBLE default_value:\"nan\" "ETC" }"
temporal40ee5512008-07-10 02:12:20 +0000381 " field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }"
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000382 " field { type:TYPE_STRING default_value:\"abc\" "ETC" }"
temporal40ee5512008-07-10 02:12:20 +0000383 " field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }"
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000384 " field { type:TYPE_BYTES default_value:\"abc\" "ETC" }"
temporal40ee5512008-07-10 02:12:20 +0000385 " field { type:TYPE_BOOL default_value:\"true\" "ETC" }"
386 " field { type_name:\"Foo\" default_value:\"FOO\" "ETC" }"
387
388 " field { type:TYPE_INT32 default_value:\"2147483647\" "ETC" }"
389 " field { type:TYPE_INT32 default_value:\"-2147483648\" "ETC" }"
390 " field { type:TYPE_UINT32 default_value:\"4294967295\" "ETC" }"
391 " field { type:TYPE_INT64 default_value:\"9223372036854775807\" "ETC" }"
392 " field { type:TYPE_INT64 default_value:\"-9223372036854775808\" "ETC" }"
393 " field { type:TYPE_UINT64 default_value:\"18446744073709551615\" "ETC" }"
394 " field { type:TYPE_DOUBLE default_value:\"43981\" "ETC" }"
395 "}");
396#undef ETC
397}
398
399TEST_F(ParseMessageTest, FieldOptions) {
400 ExpectParsesTo(
401 "message TestMessage {\n"
kenton@google.com24bf56f2008-09-24 20:31:01 +0000402 " optional string foo = 1\n"
403 " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
404 " (quux)=\"x\040y\", (baz.qux)=hey];\n"
temporal40ee5512008-07-10 02:12:20 +0000405 "}\n",
406
407 "message_type {"
408 " name: \"TestMessage\""
kenton@google.com24bf56f2008-09-24 20:31:01 +0000409 " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
410 " options { uninterpreted_option: { name { name_part: \"ctype\" "
411 " is_extension: false } "
412 " identifier_value: \"CORD\" }"
413 " uninterpreted_option: { name { name_part: \"foo\" "
414 " is_extension: true } "
415 " positive_int_value: 7 }"
416 " uninterpreted_option: { name { name_part: \"foo\" "
417 " is_extension: false } "
418 " name { name_part: \".bar.baz\""
419 " is_extension: true } "
420 " name { name_part: \"qux\" "
421 " is_extension: false } "
422 " name { name_part: \"quux\" "
423 " is_extension: false } "
424 " name { name_part: \"corge\" "
425 " is_extension: true } "
426 " negative_int_value: -33 }"
427 " uninterpreted_option: { name { name_part: \"quux\" "
428 " is_extension: true } "
429 " string_value: \"x y\" }"
430 " uninterpreted_option: { name { name_part: \"baz.qux\" "
431 " is_extension: true } "
432 " identifier_value: \"hey\" }"
433 " }"
434 " }"
temporal40ee5512008-07-10 02:12:20 +0000435 "}");
436}
437
438TEST_F(ParseMessageTest, Group) {
439 ExpectParsesTo(
440 "message TestMessage {\n"
441 " optional group TestGroup = 1 {};\n"
442 "}\n",
443
444 "message_type {"
445 " name: \"TestMessage\""
446 " nested_type { name: \"TestGroup\" }"
447 " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
448 " type:TYPE_GROUP type_name: \"TestGroup\" }"
449 "}");
450}
451
452TEST_F(ParseMessageTest, NestedMessage) {
453 ExpectParsesTo(
454 "message TestMessage {\n"
455 " message Nested {}\n"
456 " optional Nested test_nested = 1;\n"
457 "}\n",
458
459 "message_type {"
460 " name: \"TestMessage\""
461 " nested_type { name: \"Nested\" }"
462 " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
463 " type_name: \"Nested\" }"
464 "}");
465}
466
467TEST_F(ParseMessageTest, NestedEnum) {
468 ExpectParsesTo(
469 "message TestMessage {\n"
470 " enum NestedEnum {}\n"
471 " optional NestedEnum test_enum = 1;\n"
472 "}\n",
473
474 "message_type {"
475 " name: \"TestMessage\""
476 " enum_type { name: \"NestedEnum\" }"
477 " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
478 " type_name: \"NestedEnum\" }"
479 "}");
480}
481
482TEST_F(ParseMessageTest, ExtensionRange) {
483 ExpectParsesTo(
484 "message TestMessage {\n"
485 " extensions 10 to 19;\n"
486 " extensions 30 to max;\n"
487 "}\n",
488
489 "message_type {"
490 " name: \"TestMessage\""
491 " extension_range { start:10 end:20 }"
492 " extension_range { start:30 end:536870912 }"
493 "}");
494}
495
496TEST_F(ParseMessageTest, CompoundExtensionRange) {
497 ExpectParsesTo(
498 "message TestMessage {\n"
499 " extensions 2, 15, 9 to 11, 100 to max, 3;\n"
500 "}\n",
501
502 "message_type {"
503 " name: \"TestMessage\""
504 " extension_range { start:2 end:3 }"
505 " extension_range { start:15 end:16 }"
506 " extension_range { start:9 end:12 }"
507 " extension_range { start:100 end:536870912 }"
508 " extension_range { start:3 end:4 }"
509 "}");
510}
511
512TEST_F(ParseMessageTest, Extensions) {
513 ExpectParsesTo(
514 "extend Extendee1 { optional int32 foo = 12; }\n"
515 "extend Extendee2 { repeated TestMessage bar = 22; }\n",
516
517 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
518 " extendee: \"Extendee1\" } "
519 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
520 " type_name:\"TestMessage\" extendee: \"Extendee2\" }");
521}
522
523TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
524 ExpectParsesTo(
525 "message TestMessage {\n"
526 " extend Extendee1 { optional int32 foo = 12; }\n"
527 " extend Extendee2 { repeated TestMessage bar = 22; }\n"
528 "}\n",
529
530 "message_type {"
531 " name: \"TestMessage\""
532 " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
533 " extendee: \"Extendee1\" }"
534 " extension { name:\"bar\" label:LABEL_REPEATED number:22"
535 " type_name:\"TestMessage\" extendee: \"Extendee2\" }"
536 "}");
537}
538
539TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
540 ExpectParsesTo(
541 "extend Extendee1 {\n"
542 " optional int32 foo = 12;\n"
543 " repeated TestMessage bar = 22;\n"
544 "}\n",
545
546 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
547 " extendee: \"Extendee1\" } "
548 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
549 " type_name:\"TestMessage\" extendee: \"Extendee1\" }");
550}
551
552// ===================================================================
553
554typedef ParserTest ParseEnumTest;
555
556TEST_F(ParseEnumTest, SimpleEnum) {
557 ExpectParsesTo(
558 "enum TestEnum {\n"
559 " FOO = 0;\n"
560 "}\n",
561
562 "enum_type {"
563 " name: \"TestEnum\""
564 " value { name:\"FOO\" number:0 }"
565 "}");
566}
567
568TEST_F(ParseEnumTest, Values) {
569 ExpectParsesTo(
570 "enum TestEnum {\n"
571 " FOO = 13;\n"
572 " BAR = -10;\n"
573 " BAZ = 500;\n"
574 "}\n",
575
576 "enum_type {"
577 " name: \"TestEnum\""
578 " value { name:\"FOO\" number:13 }"
579 " value { name:\"BAR\" number:-10 }"
580 " value { name:\"BAZ\" number:500 }"
581 "}");
582}
583
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000584TEST_F(ParseEnumTest, ValueOptions) {
585 ExpectParsesTo(
586 "enum TestEnum {\n"
587 " FOO = 13;\n"
588 " BAR = -10 [ (something.text) = 'abc' ];\n"
589 " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
590 "}\n",
591
592 "enum_type {"
593 " name: \"TestEnum\""
594 " value { name: \"FOO\" number: 13 }"
595 " value { name: \"BAR\" number: -10 "
596 " options { "
597 " uninterpreted_option { "
598 " name { name_part: \"something.text\" is_extension: true } "
599 " string_value: \"abc\" "
600 " } "
601 " } "
602 " } "
603 " value { name: \"BAZ\" number: 500 "
604 " options { "
605 " uninterpreted_option { "
606 " name { name_part: \"something.text\" is_extension: true } "
607 " string_value: \"def\" "
608 " } "
609 " uninterpreted_option { "
610 " name { name_part: \"other\" is_extension: false } "
611 " positive_int_value: 1 "
612 " } "
613 " } "
614 " } "
615 "}");
616}
617
temporal40ee5512008-07-10 02:12:20 +0000618// ===================================================================
619
620typedef ParserTest ParseServiceTest;
621
622TEST_F(ParseServiceTest, SimpleService) {
623 ExpectParsesTo(
624 "service TestService {\n"
625 " rpc Foo(In) returns (Out);\n"
626 "}\n",
627
628 "service {"
629 " name: \"TestService\""
630 " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
631 "}");
632}
633
634TEST_F(ParseServiceTest, Methods) {
635 ExpectParsesTo(
636 "service TestService {\n"
637 " rpc Foo(In1) returns (Out1);\n"
638 " rpc Bar(In2) returns (Out2);\n"
639 " rpc Baz(In3) returns (Out3);\n"
640 "}\n",
641
642 "service {"
643 " name: \"TestService\""
644 " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
645 " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
646 " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
647 "}");
648}
649
650// ===================================================================
651// imports and packages
652
653typedef ParserTest ParseMiscTest;
654
655TEST_F(ParseMiscTest, ParseImport) {
656 ExpectParsesTo(
657 "import \"foo/bar/baz.proto\";\n",
658 "dependency: \"foo/bar/baz.proto\"");
659}
660
661TEST_F(ParseMiscTest, ParseMultipleImports) {
662 ExpectParsesTo(
663 "import \"foo.proto\";\n"
664 "import \"bar.proto\";\n"
665 "import \"baz.proto\";\n",
666 "dependency: \"foo.proto\""
667 "dependency: \"bar.proto\""
668 "dependency: \"baz.proto\"");
669}
670
671TEST_F(ParseMiscTest, ParsePackage) {
672 ExpectParsesTo(
673 "package foo.bar.baz;\n",
674 "package: \"foo.bar.baz\"");
675}
676
677TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
678 ExpectParsesTo(
679 "package foo . bar. \n"
680 " baz;\n",
681 "package: \"foo.bar.baz\"");
682}
683
684// ===================================================================
685// options
686
687TEST_F(ParseMiscTest, ParseFileOptions) {
688 ExpectParsesTo(
689 "option java_package = \"com.google.foo\";\n"
690 "option optimize_for = CODE_SIZE;",
691
692 "options {"
kenton@google.com24bf56f2008-09-24 20:31:01 +0000693 "uninterpreted_option { name { name_part: \"java_package\" "
694 " is_extension: false }"
695 " string_value: \"com.google.foo\"} "
696 "uninterpreted_option { name { name_part: \"optimize_for\" "
697 " is_extension: false }"
698 " identifier_value: \"CODE_SIZE\" } "
temporal40ee5512008-07-10 02:12:20 +0000699 "}");
700}
701
temporal40ee5512008-07-10 02:12:20 +0000702// ===================================================================
703// Error tests
704//
705// There are a very large number of possible errors that the parser could
706// report, so it's infeasible to test every single one of them. Instead,
707// we test each unique call to AddError() in parser.h. This does not mean
708// we are testing every possible error that Parser can generate because
709// each variant of the Consume() helper only counts as one unique call to
710// AddError().
711
712typedef ParserTest ParseErrorTest;
713
714TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
715 require_syntax_identifier_ = true;
716 ExpectHasEarlyExitErrors(
717 "message TestMessage {}",
718 "0:0: File must begin with 'syntax = \"proto2\";'.\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000719 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000720}
721
722TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
723 ExpectHasEarlyExitErrors(
724 "syntax = \"no_such_syntax\";",
725 "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
726 "only recognizes \"proto2\".\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000727 EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000728}
729
730TEST_F(ParseErrorTest, SimpleSyntaxError) {
731 ExpectHasErrors(
732 "message TestMessage @#$ { blah }",
733 "0:20: Expected \"{\".\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000734 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
temporal40ee5512008-07-10 02:12:20 +0000735}
736
737TEST_F(ParseErrorTest, ExpectedTopLevel) {
738 ExpectHasErrors(
739 "blah;",
740 "0:0: Expected top-level statement (e.g. \"message\").\n");
741}
742
743TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
744 // This used to cause an infinite loop. Doh.
745 ExpectHasErrors(
746 "}",
747 "0:0: Expected top-level statement (e.g. \"message\").\n"
748 "0:0: Unmatched \"}\".\n");
749}
750
751// -------------------------------------------------------------------
752// Message errors
753
754TEST_F(ParseErrorTest, MessageMissingName) {
755 ExpectHasErrors(
756 "message {}",
757 "0:8: Expected message name.\n");
758}
759
760TEST_F(ParseErrorTest, MessageMissingBody) {
761 ExpectHasErrors(
762 "message TestMessage;",
763 "0:19: Expected \"{\".\n");
764}
765
766TEST_F(ParseErrorTest, EofInMessage) {
767 ExpectHasErrors(
768 "message TestMessage {",
769 "0:21: Reached end of input in message definition (missing '}').\n");
770}
771
772TEST_F(ParseErrorTest, MissingFieldNumber) {
773 ExpectHasErrors(
774 "message TestMessage {\n"
775 " optional int32 foo;\n"
776 "}\n",
777 "1:20: Missing field number.\n");
778}
779
780TEST_F(ParseErrorTest, ExpectedFieldNumber) {
781 ExpectHasErrors(
782 "message TestMessage {\n"
783 " optional int32 foo = ;\n"
784 "}\n",
785 "1:23: Expected field number.\n");
786}
787
788TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
789 ExpectHasErrors(
790 "message TestMessage {\n"
791 " optional int32 foo = 0x100000000;\n"
792 "}\n",
793 "1:23: Integer out of range.\n");
794}
795
796TEST_F(ParseErrorTest, MissingLabel) {
797 ExpectHasErrors(
798 "message TestMessage {\n"
799 " int32 foo = 1;\n"
800 "}\n",
801 "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
802}
803
804TEST_F(ParseErrorTest, ExpectedOptionName) {
805 ExpectHasErrors(
806 "message TestMessage {\n"
807 " optional uint32 foo = 1 [];\n"
808 "}\n",
kenton@google.com24bf56f2008-09-24 20:31:01 +0000809 "1:27: Expected identifier.\n");
temporal40ee5512008-07-10 02:12:20 +0000810}
811
kenton@google.com24bf56f2008-09-24 20:31:01 +0000812TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
temporal40ee5512008-07-10 02:12:20 +0000813 ExpectHasErrors(
814 "message TestMessage {\n"
kenton@google.com24bf56f2008-09-24 20:31:01 +0000815 " optional uint32 foo = 1 [.foo=1];\n"
temporal40ee5512008-07-10 02:12:20 +0000816 "}\n",
kenton@google.com24bf56f2008-09-24 20:31:01 +0000817 "1:27: Expected identifier.\n");
temporal40ee5512008-07-10 02:12:20 +0000818}
819
820TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
821 ExpectHasErrors(
822 "message TestMessage {\n"
823 " optional uint32 foo = 1 [default=true];\n"
824 "}\n",
825 "1:35: Expected integer.\n");
826}
827
828TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
829 ExpectHasErrors(
830 "message TestMessage {\n"
831 " optional bool foo = 1 [default=blah];\n"
832 "}\n",
833 "1:33: Expected \"true\" or \"false\".\n");
834}
835
836TEST_F(ParseErrorTest, DefaultValueNotString) {
837 ExpectHasErrors(
838 "message TestMessage {\n"
839 " optional string foo = 1 [default=1];\n"
840 "}\n",
841 "1:35: Expected string.\n");
842}
843
844TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
845 ExpectHasErrors(
846 "message TestMessage {\n"
847 " optional uint32 foo = 1 [default=-1];\n"
848 "}\n",
849 "1:36: Unsigned field can't have negative default value.\n");
850}
851
852TEST_F(ParseErrorTest, DefaultValueTooLarge) {
853 ExpectHasErrors(
854 "message TestMessage {\n"
855 " optional int32 foo = 1 [default= 0x80000000];\n"
856 " optional int32 foo = 1 [default=-0x80000001];\n"
857 " optional uint32 foo = 1 [default= 0x100000000];\n"
858 " optional int64 foo = 1 [default= 0x80000000000000000];\n"
859 " optional int64 foo = 1 [default=-0x80000000000000001];\n"
860 " optional uint64 foo = 1 [default= 0x100000000000000000];\n"
861 "}\n",
862 "1:36: Integer out of range.\n"
863 "2:36: Integer out of range.\n"
864 "3:36: Integer out of range.\n"
865 "4:36: Integer out of range.\n"
866 "5:36: Integer out of range.\n"
867 "6:36: Integer out of range.\n");
868}
869
870TEST_F(ParseErrorTest, DefaultValueMissing) {
871 ExpectHasErrors(
872 "message TestMessage {\n"
873 " optional uint32 foo = 1 [default=];\n"
874 "}\n",
875 "1:35: Expected integer.\n");
876}
877
878TEST_F(ParseErrorTest, DefaultValueForGroup) {
879 ExpectHasErrors(
880 "message TestMessage {\n"
881 " optional group Foo = 1 [default=blah] {}\n"
882 "}\n",
883 "1:34: Messages can't have default values.\n");
884}
885
886TEST_F(ParseErrorTest, DuplicateDefaultValue) {
887 ExpectHasErrors(
888 "message TestMessage {\n"
889 " optional uint32 foo = 1 [default=1,default=2];\n"
890 "}\n",
891 "1:37: Already set option \"default\".\n");
892}
893
894TEST_F(ParseErrorTest, GroupNotCapitalized) {
895 ExpectHasErrors(
896 "message TestMessage {\n"
897 " optional group foo = 1 {}\n"
898 "}\n",
899 "1:17: Group names must start with a capital letter.\n");
900}
901
902TEST_F(ParseErrorTest, GroupMissingBody) {
903 ExpectHasErrors(
904 "message TestMessage {\n"
905 " optional group Foo = 1;\n"
906 "}\n",
907 "1:24: Missing group body.\n");
908}
909
910TEST_F(ParseErrorTest, ExtendingPrimitive) {
911 ExpectHasErrors(
912 "extend int32 { optional string foo = 4; }\n",
913 "0:7: Expected message type.\n");
914}
915
916TEST_F(ParseErrorTest, ErrorInExtension) {
917 ExpectHasErrors(
918 "message Foo { extensions 100 to 199; }\n"
919 "extend Foo { optional string foo; }\n",
920 "1:32: Missing field number.\n");
921}
922
923TEST_F(ParseErrorTest, MultipleParseErrors) {
924 // When a statement has a parse error, the parser should be able to continue
925 // parsing at the next statement.
926 ExpectHasErrors(
927 "message TestMessage {\n"
928 " optional int32 foo;\n"
929 " !invalid statement ending in a block { blah blah { blah } blah }\n"
930 " optional int32 bar = 3 {}\n"
931 "}\n",
932 "1:20: Missing field number.\n"
933 "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
934 "2:2: Expected type name.\n"
935 "3:25: Expected \";\".\n");
936}
937
liujisi@google.com33165fe2010-11-02 13:14:58 +0000938TEST_F(ParseErrorTest, EofInAggregateValue) {
939 ExpectHasErrors(
940 "option (fileopt) = { i:100\n",
941 "1:0: Unexpected end of stream while parsing aggregate value.\n");
942}
943
temporal40ee5512008-07-10 02:12:20 +0000944// -------------------------------------------------------------------
945// Enum errors
946
947TEST_F(ParseErrorTest, EofInEnum) {
948 ExpectHasErrors(
949 "enum TestEnum {",
950 "0:15: Reached end of input in enum definition (missing '}').\n");
951}
952
953TEST_F(ParseErrorTest, EnumValueMissingNumber) {
954 ExpectHasErrors(
955 "enum TestEnum {\n"
956 " FOO;\n"
957 "}\n",
958 "1:5: Missing numeric value for enum constant.\n");
959}
960
961// -------------------------------------------------------------------
962// Service errors
963
964TEST_F(ParseErrorTest, EofInService) {
965 ExpectHasErrors(
966 "service TestService {",
967 "0:21: Reached end of input in service definition (missing '}').\n");
968}
969
970TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
971 ExpectHasErrors(
972 "service TestService {\n"
973 " rpc Foo(int32) returns (string);\n"
974 "}\n",
975 "1:10: Expected message type.\n"
976 "1:26: Expected message type.\n");
977}
978
979TEST_F(ParseErrorTest, EofInMethodOptions) {
980 ExpectHasErrors(
981 "service TestService {\n"
982 " rpc Foo(Bar) returns(Bar) {",
983 "1:29: Reached end of input in method options (missing '}').\n"
984 "1:29: Reached end of input in service definition (missing '}').\n");
985}
986
987TEST_F(ParseErrorTest, PrimitiveMethodInput) {
988 ExpectHasErrors(
989 "service TestService {\n"
990 " rpc Foo(int32) returns(Bar);\n"
991 "}\n",
992 "1:10: Expected message type.\n");
993}
994
995TEST_F(ParseErrorTest, MethodOptionTypeError) {
996 // This used to cause an infinite loop.
997 ExpectHasErrors(
998 "message Baz {}\n"
999 "service Foo {\n"
1000 " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
1001 "}\n",
kenton@google.com24bf56f2008-09-24 20:31:01 +00001002 "2:45: Expected \"=\".\n");
temporal40ee5512008-07-10 02:12:20 +00001003}
1004
1005// -------------------------------------------------------------------
1006// Import and package errors
1007
1008TEST_F(ParseErrorTest, ImportNotQuoted) {
1009 ExpectHasErrors(
1010 "import foo;\n",
1011 "0:7: Expected a string naming the file to import.\n");
1012}
1013
1014TEST_F(ParseErrorTest, MultiplePackagesInFile) {
1015 ExpectHasErrors(
1016 "package foo;\n"
1017 "package bar;\n",
1018 "1:0: Multiple package definitions.\n");
1019}
1020
temporal40ee5512008-07-10 02:12:20 +00001021// ===================================================================
1022// Test that errors detected by DescriptorPool correctly report line and
1023// column numbers. We have one test for every call to RecordLocation() in
1024// parser.cc.
1025
1026typedef ParserTest ParserValidationErrorTest;
1027
1028TEST_F(ParserValidationErrorTest, PackageNameError) {
1029 // Create another file which defines symbol "foo".
1030 FileDescriptorProto other_file;
1031 other_file.set_name("bar.proto");
1032 other_file.add_message_type()->set_name("foo");
1033 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1034
1035 // Now try to define it as a package.
1036 ExpectHasValidationErrors(
1037 "package foo.bar;",
1038 "0:8: \"foo\" is already defined (as something other than a package) "
1039 "in file \"bar.proto\".\n");
1040}
1041
1042TEST_F(ParserValidationErrorTest, MessageNameError) {
1043 ExpectHasValidationErrors(
1044 "message Foo {}\n"
1045 "message Foo {}\n",
1046 "1:8: \"Foo\" is already defined.\n");
1047}
1048
1049TEST_F(ParserValidationErrorTest, FieldNameError) {
1050 ExpectHasValidationErrors(
1051 "message Foo {\n"
1052 " optional int32 bar = 1;\n"
1053 " optional int32 bar = 2;\n"
1054 "}\n",
1055 "2:17: \"bar\" is already defined in \"Foo\".\n");
1056}
1057
1058TEST_F(ParserValidationErrorTest, FieldTypeError) {
1059 ExpectHasValidationErrors(
1060 "message Foo {\n"
1061 " optional Baz bar = 1;\n"
1062 "}\n",
1063 "1:11: \"Baz\" is not defined.\n");
1064}
1065
1066TEST_F(ParserValidationErrorTest, FieldNumberError) {
1067 ExpectHasValidationErrors(
1068 "message Foo {\n"
1069 " optional int32 bar = 0;\n"
1070 "}\n",
1071 "1:23: Field numbers must be positive integers.\n");
1072}
1073
1074TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
1075 ExpectHasValidationErrors(
1076 "extend Baz { optional int32 bar = 1; }\n",
1077 "0:7: \"Baz\" is not defined.\n");
1078}
1079
1080TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
1081 ExpectHasValidationErrors(
1082 "enum Baz { QUX = 1; }\n"
1083 "message Foo {\n"
1084 " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
1085 "}\n",
1086 "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
1087}
1088
kenton@google.com24bf56f2008-09-24 20:31:01 +00001089TEST_F(ParserValidationErrorTest, FileOptionNameError) {
1090 ExpectHasValidationErrors(
1091 "option foo = 5;",
1092 "0:7: Option \"foo\" unknown.\n");
1093}
1094
1095TEST_F(ParserValidationErrorTest, FileOptionValueError) {
1096 ExpectHasValidationErrors(
1097 "option java_outer_classname = 5;",
1098 "0:30: Value must be quoted string for string option "
1099 "\"google.protobuf.FileOptions.java_outer_classname\".\n");
1100}
1101
1102TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
1103 ExpectHasValidationErrors(
1104 "message Foo {\n"
1105 " optional bool bar = 1 [foo=1];\n"
1106 "}\n",
1107 "1:25: Option \"foo\" unknown.\n");
1108}
1109
1110TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
1111 ExpectHasValidationErrors(
1112 "message Foo {\n"
1113 " optional int32 bar = 1 [ctype=1];\n"
1114 "}\n",
1115 "1:32: Value must be identifier for enum-valued option "
1116 "\"google.protobuf.FieldOptions.ctype\".\n");
1117}
1118
temporal40ee5512008-07-10 02:12:20 +00001119TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
1120 ExpectHasValidationErrors(
1121 "message Foo {\n"
1122 " extensions 0;\n"
1123 "}\n",
1124 "1:13: Extension numbers must be positive integers.\n");
1125}
1126
1127TEST_F(ParserValidationErrorTest, EnumNameError) {
1128 ExpectHasValidationErrors(
1129 "enum Foo {A = 1;}\n"
1130 "enum Foo {B = 1;}\n",
1131 "1:5: \"Foo\" is already defined.\n");
1132}
1133
1134TEST_F(ParserValidationErrorTest, EnumValueNameError) {
1135 ExpectHasValidationErrors(
1136 "enum Foo {\n"
1137 " BAR = 1;\n"
1138 " BAR = 1;\n"
1139 "}\n",
1140 "2:2: \"BAR\" is already defined.\n");
1141}
1142
1143TEST_F(ParserValidationErrorTest, ServiceNameError) {
1144 ExpectHasValidationErrors(
1145 "service Foo {}\n"
1146 "service Foo {}\n",
1147 "1:8: \"Foo\" is already defined.\n");
1148}
1149
1150TEST_F(ParserValidationErrorTest, MethodNameError) {
1151 ExpectHasValidationErrors(
1152 "message Baz {}\n"
1153 "service Foo {\n"
1154 " rpc Bar(Baz) returns(Baz);\n"
1155 " rpc Bar(Baz) returns(Baz);\n"
1156 "}\n",
1157 "3:6: \"Bar\" is already defined in \"Foo\".\n");
1158}
1159
1160TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
1161 ExpectHasValidationErrors(
1162 "message Baz {}\n"
1163 "service Foo {\n"
1164 " rpc Bar(Qux) returns(Baz);\n"
1165 "}\n",
1166 "2:10: \"Qux\" is not defined.\n");
1167}
1168
1169TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
1170 ExpectHasValidationErrors(
1171 "message Baz {}\n"
1172 "service Foo {\n"
1173 " rpc Bar(Baz) returns(Qux);\n"
1174 "}\n",
1175 "2:23: \"Qux\" is not defined.\n");
1176}
1177
1178// ===================================================================
1179// Test that the output from FileDescriptor::DebugString() (and all other
1180// descriptor types) is parseable, and results in the same Descriptor
1181// definitions again afoter parsing (not, however, that the order of messages
1182// cannot be guaranteed to be the same)
1183
1184typedef ParserTest ParseDecriptorDebugTest;
1185
1186class CompareDescriptorNames {
1187 public:
1188 bool operator()(const DescriptorProto* left, const DescriptorProto* right) {
1189 return left->name() < right->name();
1190 }
1191};
1192
1193// Sorts nested DescriptorProtos of a DescriptoProto, by name.
1194void SortMessages(DescriptorProto *descriptor_proto) {
1195 int size = descriptor_proto->nested_type_size();
1196 // recursively sort; we can't guarantee the order of nested messages either
1197 for (int i = 0; i < size; ++i) {
1198 SortMessages(descriptor_proto->mutable_nested_type(i));
1199 }
1200 DescriptorProto **data =
1201 descriptor_proto->mutable_nested_type()->mutable_data();
1202 sort(data, data + size, CompareDescriptorNames());
1203}
1204
1205// Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
1206void SortMessages(FileDescriptorProto *file_descriptor_proto) {
1207 int size = file_descriptor_proto->message_type_size();
1208 // recursively sort; we can't guarantee the order of nested messages either
1209 for (int i = 0; i < size; ++i) {
1210 SortMessages(file_descriptor_proto->mutable_message_type(i));
1211 }
1212 DescriptorProto **data =
1213 file_descriptor_proto->mutable_message_type()->mutable_data();
1214 sort(data, data + size, CompareDescriptorNames());
1215}
1216
1217TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
1218 const FileDescriptor* original_file =
1219 protobuf_unittest::TestAllTypes::descriptor()->file();
1220 FileDescriptorProto expected;
1221 original_file->CopyTo(&expected);
1222
1223 // Get the DebugString of the unittest.proto FileDecriptor, which includes
1224 // all other descriptor types
1225 string debug_string = original_file->DebugString();
1226
1227 // Parse the debug string
1228 SetupParser(debug_string.c_str());
1229 FileDescriptorProto parsed;
1230 parser_->Parse(input_.get(), &parsed);
1231 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1232 ASSERT_EQ("", error_collector_.text_);
1233
1234 // We now have a FileDescriptorProto, but to compare with the expected we
1235 // need to link to a FileDecriptor, then output back to a proto. We'll
1236 // also need to give it the same name as the original.
1237 parsed.set_name("google/protobuf/unittest.proto");
1238 // We need the imported dependency before we can build our parsed proto
1239 const FileDescriptor* import =
1240 protobuf_unittest_import::ImportMessage::descriptor()->file();
1241 FileDescriptorProto import_proto;
1242 import->CopyTo(&import_proto);
1243 ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
1244 const FileDescriptor* actual = pool_.BuildFile(parsed);
1245 parsed.Clear();
1246 actual->CopyTo(&parsed);
1247 ASSERT_TRUE(actual != NULL);
1248
1249 // The messages might be in different orders, making them hard to compare.
1250 // So, sort the messages in the descriptor protos (including nested messages,
1251 // recursively).
1252 SortMessages(&expected);
1253 SortMessages(&parsed);
1254
1255 // I really wanted to use StringDiff here for the debug output on fail,
1256 // but the strings are too long for it, and if I increase its max size,
1257 // we get a memory allocation failure :(
1258 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
1259}
1260
1261// ===================================================================
liujisi@google.com33165fe2010-11-02 13:14:58 +00001262// SourceCodeInfo tests.
1263
1264// Follows a path -- as defined by SourceCodeInfo.Location.path -- from a
1265// message to a particular sub-field.
1266// * If the target is itself a message, sets *output_message to point at it,
1267// *output_field to NULL, and *output_index to -1.
1268// * Otherwise, if the target is an element of a repeated field, sets
1269// *output_message to the containing message, *output_field to the descriptor
1270// of the field, and *output_index to the index of the element.
1271// * Otherwise, the target is a field (possibly a repeated field, but not any
1272// one element). Sets *output_message to the containing message,
1273// *output_field to the descriptor of the field, and *output_index to -1.
1274// Returns true if the path was valid, false otherwise. A gTest failure is
1275// recorded before returning false.
1276bool FollowPath(const Message& root,
1277 const int* path_begin, const int* path_end,
1278 const Message** output_message,
1279 const FieldDescriptor** output_field,
1280 int* output_index) {
1281 if (path_begin == path_end) {
1282 // Path refers to this whole message.
1283 *output_message = &root;
1284 *output_field = NULL;
1285 *output_index = -1;
1286 return true;
1287 }
1288
1289 const Descriptor* descriptor = root.GetDescriptor();
1290 const Reflection* reflection = root.GetReflection();
1291
1292 const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
1293
1294 if (field == NULL) {
1295 ADD_FAILURE() << descriptor->name() << " has no field number: "
1296 << *path_begin;
1297 return false;
1298 }
1299
1300 ++path_begin;
1301
1302 if (field->is_repeated()) {
1303 if (path_begin == path_end) {
1304 // Path refers to the whole repeated field.
1305 *output_message = &root;
1306 *output_field = field;
1307 *output_index = -1;
1308 return true;
1309 }
1310
1311 int index = *path_begin++;
1312 int size = reflection->FieldSize(root, field);
1313
1314 if (index >= size) {
1315 ADD_FAILURE() << descriptor->name() << "." << field->name()
1316 << " has size " << size << ", but path contained index: "
1317 << index;
1318 return false;
1319 }
1320
1321 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1322 // Descend into child message.
1323 const Message& child = reflection->GetRepeatedMessage(root, field, index);
1324 return FollowPath(child, path_begin, path_end,
1325 output_message, output_field, output_index);
1326 } else if (path_begin == path_end) {
1327 // Path refers to this element.
1328 *output_message = &root;
1329 *output_field = field;
1330 *output_index = index;
1331 return true;
1332 } else {
1333 ADD_FAILURE() << descriptor->name() << "." << field->name()
1334 << " is not a message; cannot descend into it.";
1335 return false;
1336 }
1337 } else {
1338 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1339 const Message& child = reflection->GetMessage(root, field);
1340 return FollowPath(child, path_begin, path_end,
1341 output_message, output_field, output_index);
1342 } else if (path_begin == path_end) {
1343 // Path refers to this field.
1344 *output_message = &root;
1345 *output_field = field;
1346 *output_index = -1;
1347 return true;
1348 } else {
1349 ADD_FAILURE() << descriptor->name() << "." << field->name()
1350 << " is not a message; cannot descend into it.";
1351 return false;
1352 }
1353 }
1354}
1355
1356// Split some text on line breaks. The line breaks are retained in the output,
1357// so each line (except the last) ends with a '\n', and the lines can be
1358// concatenated to produce the original text.
1359//
1360// I couldn't find the proper string utility function for this. Our
1361// split-on-delimiter functions don't include the delimiter in the output.
1362void SplitLines(const string& text, vector<string>* lines) {
1363 string::size_type pos = 0;
1364
1365 while (pos != string::npos) {
1366 string::size_type last_pos = pos;
1367 pos = text.find_first_of('\n', pos);
1368 if (pos != string::npos) ++pos;
1369 lines->push_back(text.substr(last_pos, pos - last_pos));
1370 }
1371}
1372
1373// Look for the given tags in the given text and construct a span (as defined
1374// by SourceCodeInfo.Location.span) from them. E.g. for text like:
1375// /*a*/message /*b*/Foo/*c*/ {}/*d*/
1376// There are four tags: "a", "b", "c", and "d". The constructed span starts
1377// immediately after the start tag's trailing '/' and ends immediately before
1378// the end tags leading '/'.
1379void MakeExpectedSpan(const vector<string>& lines,
1380 const string& start_tag, const string& end_tag,
1381 RepeatedField<int>* output) {
1382 string start_comment = "/*" + start_tag + "*/";
1383 string end_comment = "/*" + end_tag + "*/";
1384
1385 int start_line = -1;
1386 int start_column = -1;
1387 for (int i = 0; i < lines.size(); i++) {
1388 string::size_type pos = lines[i].find(start_comment);
1389 if (pos != string::npos) {
1390 start_line = i;
1391 start_column = pos + start_comment.size();
1392 break;
1393 }
1394 }
1395 ASSERT_NE(start_line, -1)
1396 << "Tag \"" << start_comment << "\" not found in text.";
1397
1398 int end_line = -1;
1399 int end_column = -1;
1400 for (int i = start_line; i < lines.size(); i++) {
1401 string::size_type pos = lines[i].find(end_comment);
1402 if (pos != string::npos) {
1403 end_line = i;
1404 end_column = pos;
1405 break;
1406 }
1407 }
1408 ASSERT_NE(end_line, -1)
1409 << "Tag \"" << end_comment << "\" not found in text.";
1410
1411 output->Add(start_line);
1412 output->Add(start_column);
1413 if (end_line != start_line) output->Add(end_line);
1414 output->Add(end_column);
1415}
1416
1417// Check if two spans are equal.
1418bool CompareSpans(const RepeatedField<int>& span1,
1419 const RepeatedField<int>& span2) {
1420 if (span1.size() != span2.size()) return false;
1421 for (int i = 0; i < span1.size(); i++) {
1422 if (span1.Get(i) != span2.Get(i)) return false;
1423 }
1424 return true;
1425}
1426
1427// Test fixture for source info tests, which check that source locations are
1428// recorded correctly in FileDescriptorProto.source_code_info.location.
1429class SourceInfoTest : public ParserTest {
1430 protected:
1431 // The parsed file (initialized by Parse()).
1432 FileDescriptorProto file_;
1433
1434 // Parse the given text as a .proto file and populate the spans_ map with
1435 // all the source location spans in its SourceCodeInfo table.
1436 bool Parse(const char* text) {
1437 SetupParser(text);
1438 SplitLines(text, &lines_);
1439 if (!parser_->Parse(input_.get(), &file_)) {
1440 return false;
1441 }
1442
1443 const SourceCodeInfo& source_info = file_.source_code_info();
1444 for (int i = 0; i < source_info.location_size(); i++) {
1445 const SourceCodeInfo::Location& location = source_info.location(i);
1446 const Message* descriptor_proto = NULL;
1447 const FieldDescriptor* field = NULL;
1448 int index = 0;
1449 if (!FollowPath(file_, location.path().begin(), location.path().end(),
1450 &descriptor_proto, &field, &index)) {
1451 return false;
1452 }
1453
1454 spans_.insert(make_pair(SpanKey(*descriptor_proto, field, index),
1455 &location));
1456 }
1457
1458 return true;
1459 }
1460
1461 virtual void TearDown() {
1462 EXPECT_TRUE(spans_.empty())
1463 << "Forgot to call HasSpan() for:\n"
1464 << spans_.begin()->second->DebugString();
1465 }
1466
1467 // -----------------------------------------------------------------
1468 // HasSpan() checks that the span of source code delimited by the given
1469 // tags (comments) correspond via the SourceCodeInfo table to the given
1470 // part of the FileDescriptorProto. (If unclear, look at the actual tests;
1471 // it should quickly become obvious.)
1472
1473 bool HasSpan(const char* start_tag, const char* end_tag,
1474 const Message& descriptor_proto) {
1475 return HasSpan(start_tag, end_tag, descriptor_proto, NULL, -1);
1476 }
1477
1478 bool HasSpan(const char* start_tag, const char* end_tag,
1479 const Message& descriptor_proto, const string& field_name) {
1480 return HasSpan(start_tag, end_tag, descriptor_proto, field_name, -1);
1481 }
1482
1483 bool HasSpan(const char* start_tag, const char* end_tag,
1484 const Message& descriptor_proto, const string& field_name,
1485 int index) {
1486 const FieldDescriptor* field =
1487 descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
1488 if (field == NULL) {
1489 ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
1490 << " has no such field: " << field_name;
1491 return false;
1492 }
1493
1494 return HasSpan(start_tag, end_tag, descriptor_proto, field, index);
1495 }
1496
1497 bool HasSpan(const Message& descriptor_proto) {
1498 return HasSpan(NULL, NULL, descriptor_proto, NULL, -1);
1499 }
1500
1501 bool HasSpan(const Message& descriptor_proto, const string& field_name) {
1502 return HasSpan(NULL, NULL, descriptor_proto, field_name, -1);
1503 }
1504
1505 bool HasSpan(const Message& descriptor_proto, const string& field_name,
1506 int index) {
1507 return HasSpan(NULL, NULL, descriptor_proto, field_name, index);
1508 }
1509
1510 bool HasSpan(const char* start_tag, const char* end_tag,
1511 const Message& descriptor_proto, const FieldDescriptor* field,
1512 int index) {
1513 pair<SpanMap::iterator, SpanMap::iterator> range =
1514 spans_.equal_range(SpanKey(descriptor_proto, field, index));
1515
1516 if (start_tag == NULL) {
1517 if (range.first == range.second) {
1518 return false;
1519 } else {
1520 spans_.erase(range.first);
1521 return true;
1522 }
1523 } else {
1524 RepeatedField<int> expected_span;
1525 MakeExpectedSpan(lines_, start_tag, end_tag, &expected_span);
1526
1527 for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
1528 if (CompareSpans(expected_span, iter->second->span())) {
1529 spans_.erase(iter);
1530 return true;
1531 }
1532 }
1533
1534 return false;
1535 }
1536 }
1537
1538 private:
1539 struct SpanKey {
1540 const Message* descriptor_proto;
1541 const FieldDescriptor* field;
1542 int index;
1543
1544 inline SpanKey() {}
1545 inline SpanKey(const Message& descriptor_proto,
1546 const FieldDescriptor* field,
1547 int index)
1548 : descriptor_proto(&descriptor_proto), field(field), index(index) {}
1549
1550 inline bool operator<(const SpanKey& other) const {
1551 if (descriptor_proto < other.descriptor_proto) return true;
1552 if (descriptor_proto > other.descriptor_proto) return false;
1553 if (field < other.field) return true;
1554 if (field > other.field) return false;
1555 return index < other.index;
1556 }
1557 };
1558
1559 typedef multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
1560 SpanMap spans_;
1561 vector<string> lines_;
1562};
1563
1564TEST_F(SourceInfoTest, BasicFileDecls) {
1565 EXPECT_TRUE(Parse(
1566 "/*a*/syntax = \"proto2\";\n"
1567 "package /*b*/foo.bar/*c*/;\n"
1568 "import /*d*/\"baz.proto\"/*e*/;\n"
1569 "import /*f*/\"qux.proto\"/*g*/;/*h*/\n"
1570 "// comment ignored\n"));
1571
1572 EXPECT_TRUE(HasSpan("a", "h", file_));
1573 EXPECT_TRUE(HasSpan("b", "c", file_, "package"));
1574 EXPECT_TRUE(HasSpan("d", "e", file_, "dependency", 0));
1575 EXPECT_TRUE(HasSpan("f", "g", file_, "dependency", 1));
1576}
1577
1578TEST_F(SourceInfoTest, Messages) {
1579 EXPECT_TRUE(Parse(
1580 "/*a*/message /*b*/Foo/*c*/ {}/*d*/\n"
1581 "/*e*/message /*f*/Bar/*g*/ {}/*h*/\n"));
1582
1583 EXPECT_TRUE(HasSpan("a", "d", file_.message_type(0)));
1584 EXPECT_TRUE(HasSpan("b", "c", file_.message_type(0), "name"));
1585 EXPECT_TRUE(HasSpan("e", "h", file_.message_type(1)));
1586 EXPECT_TRUE(HasSpan("f", "g", file_.message_type(1), "name"));
1587
1588 // Ignore these.
1589 EXPECT_TRUE(HasSpan(file_));
1590}
1591
1592TEST_F(SourceInfoTest, Fields) {
1593 EXPECT_TRUE(Parse(
1594 "message Foo {\n"
1595 " /*a*/optional/*b*/ /*c*/int32/*d*/ /*e*/bar/*f*/ = /*g*/1/*h*/;/*i*/\n"
1596 " /*j*/repeated/*k*/ /*l*/X.Y/*m*/ /*n*/baz/*o*/ = /*p*/2/*q*/;/*r*/\n"
1597 "}\n"));
1598
1599 const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
1600 const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
1601
1602 EXPECT_TRUE(HasSpan("a", "i", field1));
1603 EXPECT_TRUE(HasSpan("a", "b", field1, "label"));
1604 EXPECT_TRUE(HasSpan("c", "d", field1, "type"));
1605 EXPECT_TRUE(HasSpan("e", "f", field1, "name"));
1606 EXPECT_TRUE(HasSpan("g", "h", field1, "number"));
1607
1608 EXPECT_TRUE(HasSpan("j", "r", field2));
1609 EXPECT_TRUE(HasSpan("j", "k", field2, "label"));
1610 EXPECT_TRUE(HasSpan("l", "m", field2, "type_name"));
1611 EXPECT_TRUE(HasSpan("n", "o", field2, "name"));
1612 EXPECT_TRUE(HasSpan("p", "q", field2, "number"));
1613
1614 // Ignore these.
1615 EXPECT_TRUE(HasSpan(file_));
1616 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1617 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1618}
1619
1620TEST_F(SourceInfoTest, Extensions) {
1621 EXPECT_TRUE(Parse(
1622 "/*a*/extend /*b*/Foo/*c*/ {\n"
1623 " /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
1624 " /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
1625 "}/*j*/\n"
1626 "/*k*/extend /*l*/Bar/*m*/ {\n"
1627 " /*n*/optional int32 qux = 1;/*o*/\n"
1628 "}/*p*/\n"));
1629
1630 const FieldDescriptorProto& field1 = file_.extension(0);
1631 const FieldDescriptorProto& field2 = file_.extension(1);
1632 const FieldDescriptorProto& field3 = file_.extension(2);
1633
1634 EXPECT_TRUE(HasSpan("a", "j", file_, "extension"));
1635 EXPECT_TRUE(HasSpan("k", "p", file_, "extension"));
1636
1637 EXPECT_TRUE(HasSpan("d", "f", field1));
1638 EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
1639 EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
1640
1641 EXPECT_TRUE(HasSpan("g", "i", field2));
1642 EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
1643 EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
1644
1645 EXPECT_TRUE(HasSpan("n", "o", field3));
1646 EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
1647
1648 // Ignore these.
1649 EXPECT_TRUE(HasSpan(file_));
1650 EXPECT_TRUE(HasSpan(field1, "type"));
1651 EXPECT_TRUE(HasSpan(field1, "name"));
1652 EXPECT_TRUE(HasSpan(field1, "number"));
1653 EXPECT_TRUE(HasSpan(field2, "type_name"));
1654 EXPECT_TRUE(HasSpan(field2, "name"));
1655 EXPECT_TRUE(HasSpan(field2, "number"));
1656 EXPECT_TRUE(HasSpan(field3, "label"));
1657 EXPECT_TRUE(HasSpan(field3, "type"));
1658 EXPECT_TRUE(HasSpan(field3, "name"));
1659 EXPECT_TRUE(HasSpan(field3, "number"));
1660}
1661
1662TEST_F(SourceInfoTest, NestedExtensions) {
1663 EXPECT_TRUE(Parse(
1664 "message Message {\n"
1665 " /*a*/extend /*b*/Foo/*c*/ {\n"
1666 " /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
1667 " /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
1668 " }/*j*/\n"
1669 " /*k*/extend /*l*/Bar/*m*/ {\n"
1670 " /*n*/optional int32 qux = 1;/*o*/\n"
1671 " }/*p*/\n"
1672 "}\n"));
1673
1674 const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
1675 const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
1676 const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
1677
1678 EXPECT_TRUE(HasSpan("a", "j", file_.message_type(0), "extension"));
1679 EXPECT_TRUE(HasSpan("k", "p", file_.message_type(0), "extension"));
1680
1681 EXPECT_TRUE(HasSpan("d", "f", field1));
1682 EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
1683 EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
1684
1685 EXPECT_TRUE(HasSpan("g", "i", field2));
1686 EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
1687 EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
1688
1689 EXPECT_TRUE(HasSpan("n", "o", field3));
1690 EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
1691
1692 // Ignore these.
1693 EXPECT_TRUE(HasSpan(file_));
1694 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1695 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1696 EXPECT_TRUE(HasSpan(field1, "type"));
1697 EXPECT_TRUE(HasSpan(field1, "name"));
1698 EXPECT_TRUE(HasSpan(field1, "number"));
1699 EXPECT_TRUE(HasSpan(field2, "type_name"));
1700 EXPECT_TRUE(HasSpan(field2, "name"));
1701 EXPECT_TRUE(HasSpan(field2, "number"));
1702 EXPECT_TRUE(HasSpan(field3, "label"));
1703 EXPECT_TRUE(HasSpan(field3, "type"));
1704 EXPECT_TRUE(HasSpan(field3, "name"));
1705 EXPECT_TRUE(HasSpan(field3, "number"));
1706}
1707
1708TEST_F(SourceInfoTest, ExtensionRanges) {
1709 EXPECT_TRUE(Parse(
1710 "message Message {\n"
1711 " /*a*/extensions /*b*/1/*c*/ to /*d*/4/*e*/, /*f*/6/*g*/;/*h*/\n"
1712 " /*i*/extensions /*j*/8/*k*/ to /*l*/max/*m*/;/*n*/\n"
1713 "}\n"));
1714
1715 const DescriptorProto::ExtensionRange& range1 =
1716 file_.message_type(0).extension_range(0);
1717 const DescriptorProto::ExtensionRange& range2 =
1718 file_.message_type(0).extension_range(1);
1719 const DescriptorProto::ExtensionRange& range3 =
1720 file_.message_type(0).extension_range(2);
1721
1722 EXPECT_TRUE(HasSpan("a", "h", file_.message_type(0), "extension_range"));
1723 EXPECT_TRUE(HasSpan("i", "n", file_.message_type(0), "extension_range"));
1724
1725 EXPECT_TRUE(HasSpan("b", "e", range1));
1726 EXPECT_TRUE(HasSpan("b", "c", range1, "start"));
1727 EXPECT_TRUE(HasSpan("d", "e", range1, "end"));
1728
1729 EXPECT_TRUE(HasSpan("f", "g", range2));
1730 EXPECT_TRUE(HasSpan("f", "g", range2, "start"));
1731 EXPECT_TRUE(HasSpan("f", "g", range2, "end"));
1732
1733 EXPECT_TRUE(HasSpan("j", "m", range3));
1734 EXPECT_TRUE(HasSpan("j", "k", range3, "start"));
1735 EXPECT_TRUE(HasSpan("l", "m", range3, "end"));
1736
1737 // Ignore these.
1738 EXPECT_TRUE(HasSpan(file_));
1739 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1740 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1741}
1742
1743TEST_F(SourceInfoTest, NestedMessages) {
1744 EXPECT_TRUE(Parse(
1745 "message Foo {\n"
1746 " /*a*/message /*b*/Bar/*c*/ {\n"
1747 " /*d*/message /*e*/Baz/*f*/ {}/*g*/\n"
1748 " }/*h*/\n"
1749 " /*i*/message /*j*/Qux/*k*/ {}/*l*/\n"
1750 "}\n"));
1751
1752 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
1753 const DescriptorProto& baz = bar.nested_type(0);
1754 const DescriptorProto& qux = file_.message_type(0).nested_type(1);
1755
1756 EXPECT_TRUE(HasSpan("a", "h", bar));
1757 EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
1758 EXPECT_TRUE(HasSpan("d", "g", baz));
1759 EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
1760 EXPECT_TRUE(HasSpan("i", "l", qux));
1761 EXPECT_TRUE(HasSpan("j", "k", qux, "name"));
1762
1763 // Ignore these.
1764 EXPECT_TRUE(HasSpan(file_));
1765 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1766 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1767}
1768
1769TEST_F(SourceInfoTest, Groups) {
1770 EXPECT_TRUE(Parse(
1771 "message Foo {\n"
1772 " message Bar {}\n"
1773 " /*a*/optional/*b*/ /*c*/group/*d*/ /*e*/Baz/*f*/ = /*g*/1/*h*/ {\n"
1774 " /*i*/message Qux {}/*j*/\n"
1775 " }/*k*/\n"
1776 "}\n"));
1777
1778 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
1779 const DescriptorProto& baz = file_.message_type(0).nested_type(1);
1780 const DescriptorProto& qux = baz.nested_type(0);
1781 const FieldDescriptorProto& field = file_.message_type(0).field(0);
1782
1783 EXPECT_TRUE(HasSpan("a", "k", field));
1784 EXPECT_TRUE(HasSpan("a", "b", field, "label"));
1785 EXPECT_TRUE(HasSpan("c", "d", field, "type"));
1786 EXPECT_TRUE(HasSpan("e", "f", field, "name"));
1787 EXPECT_TRUE(HasSpan("e", "f", field, "type_name"));
1788 EXPECT_TRUE(HasSpan("g", "h", field, "number"));
1789
1790 EXPECT_TRUE(HasSpan("a", "k", baz));
1791 EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
1792 EXPECT_TRUE(HasSpan("i", "j", qux));
1793
1794 // Ignore these.
1795 EXPECT_TRUE(HasSpan(file_));
1796 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1797 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1798 EXPECT_TRUE(HasSpan(bar));
1799 EXPECT_TRUE(HasSpan(bar, "name"));
1800 EXPECT_TRUE(HasSpan(qux, "name"));
1801}
1802
1803TEST_F(SourceInfoTest, Enums) {
1804 EXPECT_TRUE(Parse(
1805 "/*a*/enum /*b*/Foo/*c*/ {}/*d*/\n"
1806 "/*e*/enum /*f*/Bar/*g*/ {}/*h*/\n"));
1807
1808 EXPECT_TRUE(HasSpan("a", "d", file_.enum_type(0)));
1809 EXPECT_TRUE(HasSpan("b", "c", file_.enum_type(0), "name"));
1810 EXPECT_TRUE(HasSpan("e", "h", file_.enum_type(1)));
1811 EXPECT_TRUE(HasSpan("f", "g", file_.enum_type(1), "name"));
1812
1813 // Ignore these.
1814 EXPECT_TRUE(HasSpan(file_));
1815}
1816
1817TEST_F(SourceInfoTest, EnumValues) {
1818 EXPECT_TRUE(Parse(
1819 "enum Foo {\n"
1820 " /*a*/BAR/*b*/ = /*c*/1/*d*/;/*e*/\n"
1821 " /*f*/BAZ/*g*/ = /*h*/2/*i*/;/*j*/\n"
1822 "}"));
1823
1824 const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
1825 const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
1826
1827 EXPECT_TRUE(HasSpan("a", "e", bar));
1828 EXPECT_TRUE(HasSpan("a", "b", bar, "name"));
1829 EXPECT_TRUE(HasSpan("c", "d", bar, "number"));
1830 EXPECT_TRUE(HasSpan("f", "j", baz));
1831 EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
1832 EXPECT_TRUE(HasSpan("h", "i", baz, "number"));
1833
1834 // Ignore these.
1835 EXPECT_TRUE(HasSpan(file_));
1836 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
1837 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
1838}
1839
1840TEST_F(SourceInfoTest, NestedEnums) {
1841 EXPECT_TRUE(Parse(
1842 "message Foo {\n"
1843 " /*a*/enum /*b*/Bar/*c*/ {}/*d*/\n"
1844 " /*e*/enum /*f*/Baz/*g*/ {}/*h*/\n"
1845 "}\n"));
1846
1847 const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
1848 const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
1849
1850 EXPECT_TRUE(HasSpan("a", "d", bar));
1851 EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
1852 EXPECT_TRUE(HasSpan("e", "h", baz));
1853 EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
1854
1855 // Ignore these.
1856 EXPECT_TRUE(HasSpan(file_));
1857 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1858 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1859}
1860
1861TEST_F(SourceInfoTest, Services) {
1862 EXPECT_TRUE(Parse(
1863 "/*a*/service /*b*/Foo/*c*/ {}/*d*/\n"
1864 "/*e*/service /*f*/Bar/*g*/ {}/*h*/\n"));
1865
1866 EXPECT_TRUE(HasSpan("a", "d", file_.service(0)));
1867 EXPECT_TRUE(HasSpan("b", "c", file_.service(0), "name"));
1868 EXPECT_TRUE(HasSpan("e", "h", file_.service(1)));
1869 EXPECT_TRUE(HasSpan("f", "g", file_.service(1), "name"));
1870
1871 // Ignore these.
1872 EXPECT_TRUE(HasSpan(file_));
1873}
1874
1875TEST_F(SourceInfoTest, Methods) {
1876 EXPECT_TRUE(Parse(
1877 "service Foo {\n"
1878 " /*a*/rpc /*b*/Bar/*c*/(/*d*/X/*e*/) returns(/*f*/Y/*g*/);/*h*/"
1879 " /*i*/rpc /*j*/Baz/*k*/(/*l*/Z/*m*/) returns(/*n*/W/*o*/);/*p*/"
1880 "}"));
1881
1882 const MethodDescriptorProto& bar = file_.service(0).method(0);
1883 const MethodDescriptorProto& baz = file_.service(0).method(1);
1884
1885 EXPECT_TRUE(HasSpan("a", "h", bar));
1886 EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
1887 EXPECT_TRUE(HasSpan("d", "e", bar, "input_type"));
1888 EXPECT_TRUE(HasSpan("f", "g", bar, "output_type"));
1889
1890 EXPECT_TRUE(HasSpan("i", "p", baz));
1891 EXPECT_TRUE(HasSpan("j", "k", baz, "name"));
1892 EXPECT_TRUE(HasSpan("l", "m", baz, "input_type"));
1893 EXPECT_TRUE(HasSpan("n", "o", baz, "output_type"));
1894
1895 // Ignore these.
1896 EXPECT_TRUE(HasSpan(file_));
1897 EXPECT_TRUE(HasSpan(file_.service(0)));
1898 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
1899}
1900
1901TEST_F(SourceInfoTest, Options) {
1902 EXPECT_TRUE(Parse(
1903 "/*a*/option /*b*/foo/*c*/./*d*/(/*e*/bar.baz/*f*/)/*g*/ = "
1904 "/*h*/123/*i*/;/*j*/\n"
1905 "/*k*/option qux = /*l*/-123/*m*/;/*n*/\n"
1906 "/*o*/option corge = /*p*/abc/*q*/;/*r*/\n"
1907 "/*s*/option grault = /*t*/'blah'/*u*/;/*v*/\n"
1908 "/*w*/option garply = /*x*/{ yadda yadda }/*y*/;/*z*/\n"
1909 "/*0*/option waldo = /*1*/123.0/*2*/;/*3*/\n"
1910 ));
1911
1912 const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
1913 const UninterpretedOption& option2 = file_.options().uninterpreted_option(1);
1914 const UninterpretedOption& option3 = file_.options().uninterpreted_option(2);
1915 const UninterpretedOption& option4 = file_.options().uninterpreted_option(3);
1916 const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
1917 const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
1918
1919 EXPECT_TRUE(HasSpan("a", "j", file_.options()));
1920 EXPECT_TRUE(HasSpan("b", "i", option1));
1921 EXPECT_TRUE(HasSpan("b", "g", option1, "name"));
1922 EXPECT_TRUE(HasSpan("b", "c", option1.name(0)));
1923 EXPECT_TRUE(HasSpan("b", "c", option1.name(0), "name_part"));
1924 EXPECT_TRUE(HasSpan("d", "g", option1.name(1)));
1925 EXPECT_TRUE(HasSpan("e", "f", option1.name(1), "name_part"));
1926 EXPECT_TRUE(HasSpan("h", "i", option1, "positive_int_value"));
1927
1928 EXPECT_TRUE(HasSpan("k", "n", file_.options()));
1929 EXPECT_TRUE(HasSpan("l", "m", option2, "negative_int_value"));
1930
1931 EXPECT_TRUE(HasSpan("o", "r", file_.options()));
1932 EXPECT_TRUE(HasSpan("p", "q", option3, "identifier_value"));
1933
1934 EXPECT_TRUE(HasSpan("s", "v", file_.options()));
1935 EXPECT_TRUE(HasSpan("t", "u", option4, "string_value"));
1936
1937 EXPECT_TRUE(HasSpan("w", "z", file_.options()));
1938 EXPECT_TRUE(HasSpan("x", "y", option5, "aggregate_value"));
1939
1940 EXPECT_TRUE(HasSpan("0", "3", file_.options()));
1941 EXPECT_TRUE(HasSpan("1", "2", option6, "double_value"));
1942
1943 // Ignore these.
1944 EXPECT_TRUE(HasSpan(file_));
1945 EXPECT_TRUE(HasSpan(option2));
1946 EXPECT_TRUE(HasSpan(option3));
1947 EXPECT_TRUE(HasSpan(option4));
1948 EXPECT_TRUE(HasSpan(option5));
1949 EXPECT_TRUE(HasSpan(option6));
1950 EXPECT_TRUE(HasSpan(option2, "name"));
1951 EXPECT_TRUE(HasSpan(option3, "name"));
1952 EXPECT_TRUE(HasSpan(option4, "name"));
1953 EXPECT_TRUE(HasSpan(option5, "name"));
1954 EXPECT_TRUE(HasSpan(option6, "name"));
1955 EXPECT_TRUE(HasSpan(option2.name(0)));
1956 EXPECT_TRUE(HasSpan(option3.name(0)));
1957 EXPECT_TRUE(HasSpan(option4.name(0)));
1958 EXPECT_TRUE(HasSpan(option5.name(0)));
1959 EXPECT_TRUE(HasSpan(option6.name(0)));
1960 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
1961 EXPECT_TRUE(HasSpan(option3.name(0), "name_part"));
1962 EXPECT_TRUE(HasSpan(option4.name(0), "name_part"));
1963 EXPECT_TRUE(HasSpan(option5.name(0), "name_part"));
1964 EXPECT_TRUE(HasSpan(option6.name(0), "name_part"));
1965}
1966
1967TEST_F(SourceInfoTest, ScopedOptions) {
1968 EXPECT_TRUE(Parse(
1969 "message Foo {\n"
1970 " /*a*/option mopt = 1;/*b*/\n"
1971 "}\n"
1972 "enum Bar {\n"
1973 " /*c*/option eopt = 1;/*d*/\n"
1974 "}\n"
1975 "service Baz {\n"
1976 " /*e*/option sopt = 1;/*f*/\n"
1977 " rpc M(X) returns(Y) {\n"
1978 " /*g*/option mopt = 1;/*h*/\n"
1979 " }\n"
1980 "}\n"));
1981
1982 EXPECT_TRUE(HasSpan("a", "b", file_.message_type(0).options()));
1983 EXPECT_TRUE(HasSpan("c", "d", file_.enum_type(0).options()));
1984 EXPECT_TRUE(HasSpan("e", "f", file_.service(0).options()));
1985 EXPECT_TRUE(HasSpan("g", "h", file_.service(0).method(0).options()));
1986
1987 // Ignore these.
1988 EXPECT_TRUE(HasSpan(file_));
1989 EXPECT_TRUE(HasSpan(file_.message_type(0)));
1990 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
1991 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
1992 .uninterpreted_option(0)));
1993 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
1994 .uninterpreted_option(0), "name"));
1995 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
1996 .uninterpreted_option(0).name(0)));
1997 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
1998 .uninterpreted_option(0).name(0), "name_part"));
1999 EXPECT_TRUE(HasSpan(file_.message_type(0).options()
2000 .uninterpreted_option(0), "positive_int_value"));
2001 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2002 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2003 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2004 .uninterpreted_option(0)));
2005 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2006 .uninterpreted_option(0), "name"));
2007 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2008 .uninterpreted_option(0).name(0)));
2009 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2010 .uninterpreted_option(0).name(0), "name_part"));
2011 EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
2012 .uninterpreted_option(0), "positive_int_value"));
2013 EXPECT_TRUE(HasSpan(file_.service(0)));
2014 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
2015 EXPECT_TRUE(HasSpan(file_.service(0).method(0)));
2016 EXPECT_TRUE(HasSpan(file_.service(0).options()
2017 .uninterpreted_option(0)));
2018 EXPECT_TRUE(HasSpan(file_.service(0).options()
2019 .uninterpreted_option(0), "name"));
2020 EXPECT_TRUE(HasSpan(file_.service(0).options()
2021 .uninterpreted_option(0).name(0)));
2022 EXPECT_TRUE(HasSpan(file_.service(0).options()
2023 .uninterpreted_option(0).name(0), "name_part"));
2024 EXPECT_TRUE(HasSpan(file_.service(0).options()
2025 .uninterpreted_option(0), "positive_int_value"));
2026 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name"));
2027 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type"));
2028 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type"));
2029 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2030 .uninterpreted_option(0)));
2031 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2032 .uninterpreted_option(0), "name"));
2033 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2034 .uninterpreted_option(0).name(0)));
2035 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2036 .uninterpreted_option(0).name(0), "name_part"));
2037 EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
2038 .uninterpreted_option(0), "positive_int_value"));
2039}
2040
2041TEST_F(SourceInfoTest, FieldOptions) {
2042 // The actual "name = value" pairs are parsed by the same code as for
2043 // top-level options so we won't re-test that -- just make sure that the
2044 // syntax used for field options is understood.
2045 EXPECT_TRUE(Parse(
2046 "message Foo {"
2047 " optional int32 bar = 1 "
2048 "/*a*/[default=/*b*/123/*c*/,/*d*/opt1=123/*e*/,"
2049 "/*f*/opt2='hi'/*g*/]/*h*/;"
2050 "}\n"
2051 ));
2052
2053 const FieldDescriptorProto& field = file_.message_type(0).field(0);
2054 const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
2055 const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
2056
2057 EXPECT_TRUE(HasSpan("a", "h", field.options()));
2058 EXPECT_TRUE(HasSpan("b", "c", field, "default_value"));
2059 EXPECT_TRUE(HasSpan("d", "e", option1));
2060 EXPECT_TRUE(HasSpan("f", "g", option2));
2061
2062 // Ignore these.
2063 EXPECT_TRUE(HasSpan(file_));
2064 EXPECT_TRUE(HasSpan(file_.message_type(0)));
2065 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
2066 EXPECT_TRUE(HasSpan(field));
2067 EXPECT_TRUE(HasSpan(field, "label"));
2068 EXPECT_TRUE(HasSpan(field, "type"));
2069 EXPECT_TRUE(HasSpan(field, "name"));
2070 EXPECT_TRUE(HasSpan(field, "number"));
2071 EXPECT_TRUE(HasSpan(option1, "name"));
2072 EXPECT_TRUE(HasSpan(option2, "name"));
2073 EXPECT_TRUE(HasSpan(option1.name(0)));
2074 EXPECT_TRUE(HasSpan(option2.name(0)));
2075 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
2076 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2077 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
2078 EXPECT_TRUE(HasSpan(option2, "string_value"));
2079}
2080
2081TEST_F(SourceInfoTest, EnumValueOptions) {
2082 // The actual "name = value" pairs are parsed by the same code as for
2083 // top-level options so we won't re-test that -- just make sure that the
2084 // syntax used for enum options is understood.
2085 EXPECT_TRUE(Parse(
2086 "enum Foo {"
2087 " BAR = 1 /*a*/[/*b*/opt1=123/*c*/,/*d*/opt2='hi'/*e*/]/*f*/;"
2088 "}\n"
2089 ));
2090
2091 const EnumValueDescriptorProto& value = file_.enum_type(0).value(0);
2092 const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
2093 const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
2094
2095 EXPECT_TRUE(HasSpan("a", "f", value.options()));
2096 EXPECT_TRUE(HasSpan("b", "c", option1));
2097 EXPECT_TRUE(HasSpan("d", "e", option2));
2098
2099 // Ignore these.
2100 EXPECT_TRUE(HasSpan(file_));
2101 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
2102 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
2103 EXPECT_TRUE(HasSpan(value));
2104 EXPECT_TRUE(HasSpan(value, "name"));
2105 EXPECT_TRUE(HasSpan(value, "number"));
2106 EXPECT_TRUE(HasSpan(option1, "name"));
2107 EXPECT_TRUE(HasSpan(option2, "name"));
2108 EXPECT_TRUE(HasSpan(option1.name(0)));
2109 EXPECT_TRUE(HasSpan(option2.name(0)));
2110 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
2111 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
2112 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
2113 EXPECT_TRUE(HasSpan(option2, "string_value"));
2114}
2115
2116// ===================================================================
temporal40ee5512008-07-10 02:12:20 +00002117
2118} // anonymous namespace
2119
2120} // namespace compiler
2121} // namespace protobuf
2122} // namespace google