1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <vector>
36 #include <algorithm>
37
38 #include <google/protobuf/compiler/parser.h>
39
40 #include <google/protobuf/io/tokenizer.h>
41 #include <google/protobuf/io/zero_copy_stream_impl.h>
42 #include <google/protobuf/descriptor.pb.h>
43 #include <google/protobuf/wire_format.h>
44 #include <google/protobuf/text_format.h>
45 #include <google/protobuf/unittest.pb.h>
46 #include <google/protobuf/stubs/strutil.h>
47 #include <google/protobuf/stubs/substitute.h>
48
49 #include <google/protobuf/testing/googletest.h>
50 #include <gtest/gtest.h>
51
52 namespace google {
53 namespace protobuf {
54 namespace compiler {
55
56 namespace {
57
58 class MockErrorCollector : public io::ErrorCollector {
59 public:
MockErrorCollector()60 MockErrorCollector() {}
~MockErrorCollector()61 ~MockErrorCollector() {}
62
63 string text_;
64
65 // implements ErrorCollector ---------------------------------------
AddError(int line,int column,const string & message)66 void AddError(int line, int column, const string& message) {
67 strings::SubstituteAndAppend(&text_, "$0:$1: $2\n",
68 line, column, message);
69 }
70 };
71
72 class MockValidationErrorCollector : public DescriptorPool::ErrorCollector {
73 public:
MockValidationErrorCollector(const SourceLocationTable & source_locations,io::ErrorCollector * wrapped_collector)74 MockValidationErrorCollector(const SourceLocationTable& source_locations,
75 io::ErrorCollector* wrapped_collector)
76 : source_locations_(source_locations),
77 wrapped_collector_(wrapped_collector) {}
~MockValidationErrorCollector()78 ~MockValidationErrorCollector() {}
79
80 // implements ErrorCollector ---------------------------------------
AddError(const string & filename,const string & element_name,const Message * descriptor,ErrorLocation location,const string & message)81 void AddError(const string& filename,
82 const string& element_name,
83 const Message* descriptor,
84 ErrorLocation location,
85 const string& message) {
86 int line, column;
87 source_locations_.Find(descriptor, location, &line, &column);
88 wrapped_collector_->AddError(line, column, message);
89 }
90
91 private:
92 const SourceLocationTable& source_locations_;
93 io::ErrorCollector* wrapped_collector_;
94 };
95
96 class ParserTest : public testing::Test {
97 protected:
ParserTest()98 ParserTest()
99 : require_syntax_identifier_(false) {}
100
101 // Set up the parser to parse the given text.
SetupParser(const char * text)102 void SetupParser(const char* text) {
103 raw_input_.reset(new io::ArrayInputStream(text, strlen(text)));
104 input_.reset(new io::Tokenizer(raw_input_.get(), &error_collector_));
105 parser_.reset(new Parser());
106 parser_->RecordErrorsTo(&error_collector_);
107 parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_);
108 }
109
110 // Parse the input and expect that the resulting FileDescriptorProto matches
111 // the given output. The output is a FileDescriptorProto in protocol buffer
112 // text format.
ExpectParsesTo(const char * input,const char * output)113 void ExpectParsesTo(const char* input, const char* output) {
114 SetupParser(input);
115 FileDescriptorProto actual, expected;
116
117 parser_->Parse(input_.get(), &actual);
118 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
119 ASSERT_EQ("", error_collector_.text_);
120
121 // Parse the ASCII representation in order to canonicalize it. We could
122 // just compare directly to actual.DebugString(), but that would require
123 // that the caller precisely match the formatting that DebugString()
124 // produces.
125 ASSERT_TRUE(TextFormat::ParseFromString(output, &expected));
126
127 // Compare by comparing debug strings.
128 // TODO(kenton): Use differencer, once it is available.
129 EXPECT_EQ(expected.DebugString(), actual.DebugString());
130 }
131
132 // Parse the text and expect that the given errors are reported.
ExpectHasErrors(const char * text,const char * expected_errors)133 void ExpectHasErrors(const char* text, const char* expected_errors) {
134 ExpectHasEarlyExitErrors(text, expected_errors);
135 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
136 }
137
138 // Same as above but does not expect that the parser parses the complete
139 // input.
ExpectHasEarlyExitErrors(const char * text,const char * expected_errors)140 void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) {
141 SetupParser(text);
142 FileDescriptorProto file;
143 parser_->Parse(input_.get(), &file);
144 EXPECT_EQ(expected_errors, error_collector_.text_);
145 }
146
147 // Parse the text as a file and validate it (with a DescriptorPool), and
148 // expect that the validation step reports the given errors.
ExpectHasValidationErrors(const char * text,const char * expected_errors)149 void ExpectHasValidationErrors(const char* text,
150 const char* expected_errors) {
151 SetupParser(text);
152 SourceLocationTable source_locations;
153 parser_->RecordSourceLocationsTo(&source_locations);
154
155 FileDescriptorProto file;
156 file.set_name("foo.proto");
157 parser_->Parse(input_.get(), &file);
158 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
159 ASSERT_EQ("", error_collector_.text_);
160
161 MockValidationErrorCollector validation_error_collector(
162 source_locations, &error_collector_);
163 EXPECT_TRUE(pool_.BuildFileCollectingErrors(
164 file, &validation_error_collector) == NULL);
165 EXPECT_EQ(expected_errors, error_collector_.text_);
166 }
167
168 MockErrorCollector error_collector_;
169 DescriptorPool pool_;
170
171 scoped_ptr<io::ZeroCopyInputStream> raw_input_;
172 scoped_ptr<io::Tokenizer> input_;
173 scoped_ptr<Parser> parser_;
174 bool require_syntax_identifier_;
175 };
176
177 // ===================================================================
178
TEST_F(ParserTest,StopAfterSyntaxIdentifier)179 TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
180 SetupParser(
181 "// blah\n"
182 "syntax = \"foobar\";\n"
183 "this line will not be parsed\n");
184 parser_->SetStopAfterSyntaxIdentifier(true);
185 EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
186 EXPECT_EQ("", error_collector_.text_);
187 EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
188 }
189
TEST_F(ParserTest,StopAfterOmittedSyntaxIdentifier)190 TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
191 SetupParser(
192 "// blah\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("", parser_->GetSyntaxIdentifier());
198 }
199
TEST_F(ParserTest,StopAfterSyntaxIdentifierWithErrors)200 TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
201 SetupParser(
202 "// blah\n"
203 "syntax = error;\n");
204 parser_->SetStopAfterSyntaxIdentifier(true);
205 EXPECT_FALSE(parser_->Parse(input_.get(), NULL));
206 EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
207 }
208
209 // ===================================================================
210
211 typedef ParserTest ParseMessageTest;
212
TEST_F(ParseMessageTest,SimpleMessage)213 TEST_F(ParseMessageTest, SimpleMessage) {
214 ExpectParsesTo(
215 "message TestMessage {\n"
216 " required int32 foo = 1;\n"
217 "}\n",
218
219 "message_type {"
220 " name: \"TestMessage\""
221 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
222 "}");
223 }
224
TEST_F(ParseMessageTest,ImplicitSyntaxIdentifier)225 TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
226 require_syntax_identifier_ = false;
227 ExpectParsesTo(
228 "message TestMessage {\n"
229 " required int32 foo = 1;\n"
230 "}\n",
231
232 "message_type {"
233 " name: \"TestMessage\""
234 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
235 "}");
236 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
237 }
238
TEST_F(ParseMessageTest,ExplicitSyntaxIdentifier)239 TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
240 ExpectParsesTo(
241 "syntax = \"proto2\";\n"
242 "message TestMessage {\n"
243 " required int32 foo = 1;\n"
244 "}\n",
245
246 "message_type {"
247 " name: \"TestMessage\""
248 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
249 "}");
250 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
251 }
252
TEST_F(ParseMessageTest,ExplicitRequiredSyntaxIdentifier)253 TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
254 require_syntax_identifier_ = true;
255 ExpectParsesTo(
256 "syntax = \"proto2\";\n"
257 "message TestMessage {\n"
258 " required int32 foo = 1;\n"
259 "}\n",
260
261 "message_type {"
262 " name: \"TestMessage\""
263 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
264 "}");
265 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
266 }
267
TEST_F(ParseMessageTest,SimpleFields)268 TEST_F(ParseMessageTest, SimpleFields) {
269 ExpectParsesTo(
270 "message TestMessage {\n"
271 " required int32 foo = 15;\n"
272 " optional int32 bar = 34;\n"
273 " repeated int32 baz = 3;\n"
274 "}\n",
275
276 "message_type {"
277 " name: \"TestMessage\""
278 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
279 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
280 " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }"
281 "}");
282 }
283
TEST_F(ParseMessageTest,PrimitiveFieldTypes)284 TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
285 ExpectParsesTo(
286 "message TestMessage {\n"
287 " required int32 foo = 1;\n"
288 " required int64 foo = 1;\n"
289 " required uint32 foo = 1;\n"
290 " required uint64 foo = 1;\n"
291 " required sint32 foo = 1;\n"
292 " required sint64 foo = 1;\n"
293 " required fixed32 foo = 1;\n"
294 " required fixed64 foo = 1;\n"
295 " required sfixed32 foo = 1;\n"
296 " required sfixed64 foo = 1;\n"
297 " required float foo = 1;\n"
298 " required double foo = 1;\n"
299 " required string foo = 1;\n"
300 " required bytes foo = 1;\n"
301 " required bool foo = 1;\n"
302 "}\n",
303
304 "message_type {"
305 " name: \"TestMessage\""
306 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
307 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 }"
308 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 }"
309 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 }"
310 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 }"
311 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 }"
312 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 }"
313 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 }"
314 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 }"
315 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 }"
316 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 }"
317 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 }"
318 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 }"
319 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 }"
320 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 }"
321 "}");
322 }
323
TEST_F(ParseMessageTest,FieldDefaults)324 TEST_F(ParseMessageTest, FieldDefaults) {
325 ExpectParsesTo(
326 "message TestMessage {\n"
327 " required int32 foo = 1 [default= 1 ];\n"
328 " required int32 foo = 1 [default= -2 ];\n"
329 " required int64 foo = 1 [default= 3 ];\n"
330 " required int64 foo = 1 [default= -4 ];\n"
331 " required uint32 foo = 1 [default= 5 ];\n"
332 " required uint64 foo = 1 [default= 6 ];\n"
333 " required float foo = 1 [default= 7.5];\n"
334 " required float foo = 1 [default= -8.5];\n"
335 " required float foo = 1 [default= 9 ];\n"
336 " required double foo = 1 [default= 10.5];\n"
337 " required double foo = 1 [default=-11.5];\n"
338 " required double foo = 1 [default= 12 ];\n"
339 " required double foo = 1 [default= inf ];\n"
340 " required double foo = 1 [default=-inf ];\n"
341 " required double foo = 1 [default= nan ];\n"
342 " required string foo = 1 [default='13\\001'];\n"
343 " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
344 " required bytes foo = 1 [default='14\\002'];\n"
345 " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
346 " required bool foo = 1 [default=true ];\n"
347 " required Foo foo = 1 [default=FOO ];\n"
348
349 " required int32 foo = 1 [default= 0x7FFFFFFF];\n"
350 " required int32 foo = 1 [default=-0x80000000];\n"
351 " required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
352 " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
353 " required int64 foo = 1 [default=-0x8000000000000000];\n"
354 " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
355 " required double foo = 1 [default= 0xabcd];\n"
356 "}\n",
357
358 #define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
359 "message_type {"
360 " name: \"TestMessage\""
361 " field { type:TYPE_INT32 default_value:\"1\" "ETC" }"
362 " field { type:TYPE_INT32 default_value:\"-2\" "ETC" }"
363 " field { type:TYPE_INT64 default_value:\"3\" "ETC" }"
364 " field { type:TYPE_INT64 default_value:\"-4\" "ETC" }"
365 " field { type:TYPE_UINT32 default_value:\"5\" "ETC" }"
366 " field { type:TYPE_UINT64 default_value:\"6\" "ETC" }"
367 " field { type:TYPE_FLOAT default_value:\"7.5\" "ETC" }"
368 " field { type:TYPE_FLOAT default_value:\"-8.5\" "ETC" }"
369 " field { type:TYPE_FLOAT default_value:\"9\" "ETC" }"
370 " field { type:TYPE_DOUBLE default_value:\"10.5\" "ETC" }"
371 " field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }"
372 " field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }"
373 " field { type:TYPE_DOUBLE default_value:\"inf\" "ETC" }"
374 " field { type:TYPE_DOUBLE default_value:\"-inf\" "ETC" }"
375 " field { type:TYPE_DOUBLE default_value:\"nan\" "ETC" }"
376 " field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }"
377 " field { type:TYPE_STRING default_value:\"abc\" "ETC" }"
378 " field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }"
379 " field { type:TYPE_BYTES default_value:\"abc\" "ETC" }"
380 " field { type:TYPE_BOOL default_value:\"true\" "ETC" }"
381 " field { type_name:\"Foo\" default_value:\"FOO\" "ETC" }"
382
383 " field { type:TYPE_INT32 default_value:\"2147483647\" "ETC" }"
384 " field { type:TYPE_INT32 default_value:\"-2147483648\" "ETC" }"
385 " field { type:TYPE_UINT32 default_value:\"4294967295\" "ETC" }"
386 " field { type:TYPE_INT64 default_value:\"9223372036854775807\" "ETC" }"
387 " field { type:TYPE_INT64 default_value:\"-9223372036854775808\" "ETC" }"
388 " field { type:TYPE_UINT64 default_value:\"18446744073709551615\" "ETC" }"
389 " field { type:TYPE_DOUBLE default_value:\"43981\" "ETC" }"
390 "}");
391 #undef ETC
392 }
393
TEST_F(ParseMessageTest,FieldOptions)394 TEST_F(ParseMessageTest, FieldOptions) {
395 ExpectParsesTo(
396 "message TestMessage {\n"
397 " optional string foo = 1\n"
398 " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
399 " (quux)=\"x\040y\", (baz.qux)=hey];\n"
400 "}\n",
401
402 "message_type {"
403 " name: \"TestMessage\""
404 " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
405 " options { uninterpreted_option: { name { name_part: \"ctype\" "
406 " is_extension: false } "
407 " identifier_value: \"CORD\" }"
408 " uninterpreted_option: { name { name_part: \"foo\" "
409 " is_extension: true } "
410 " positive_int_value: 7 }"
411 " uninterpreted_option: { name { name_part: \"foo\" "
412 " is_extension: false } "
413 " name { name_part: \".bar.baz\""
414 " is_extension: true } "
415 " name { name_part: \"qux\" "
416 " is_extension: false } "
417 " name { name_part: \"quux\" "
418 " is_extension: false } "
419 " name { name_part: \"corge\" "
420 " is_extension: true } "
421 " negative_int_value: -33 }"
422 " uninterpreted_option: { name { name_part: \"quux\" "
423 " is_extension: true } "
424 " string_value: \"x y\" }"
425 " uninterpreted_option: { name { name_part: \"baz.qux\" "
426 " is_extension: true } "
427 " identifier_value: \"hey\" }"
428 " }"
429 " }"
430 "}");
431 }
432
TEST_F(ParseMessageTest,Group)433 TEST_F(ParseMessageTest, Group) {
434 ExpectParsesTo(
435 "message TestMessage {\n"
436 " optional group TestGroup = 1 {};\n"
437 "}\n",
438
439 "message_type {"
440 " name: \"TestMessage\""
441 " nested_type { name: \"TestGroup\" }"
442 " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
443 " type:TYPE_GROUP type_name: \"TestGroup\" }"
444 "}");
445 }
446
TEST_F(ParseMessageTest,NestedMessage)447 TEST_F(ParseMessageTest, NestedMessage) {
448 ExpectParsesTo(
449 "message TestMessage {\n"
450 " message Nested {}\n"
451 " optional Nested test_nested = 1;\n"
452 "}\n",
453
454 "message_type {"
455 " name: \"TestMessage\""
456 " nested_type { name: \"Nested\" }"
457 " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
458 " type_name: \"Nested\" }"
459 "}");
460 }
461
TEST_F(ParseMessageTest,NestedEnum)462 TEST_F(ParseMessageTest, NestedEnum) {
463 ExpectParsesTo(
464 "message TestMessage {\n"
465 " enum NestedEnum {}\n"
466 " optional NestedEnum test_enum = 1;\n"
467 "}\n",
468
469 "message_type {"
470 " name: \"TestMessage\""
471 " enum_type { name: \"NestedEnum\" }"
472 " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
473 " type_name: \"NestedEnum\" }"
474 "}");
475 }
476
TEST_F(ParseMessageTest,ExtensionRange)477 TEST_F(ParseMessageTest, ExtensionRange) {
478 ExpectParsesTo(
479 "message TestMessage {\n"
480 " extensions 10 to 19;\n"
481 " extensions 30 to max;\n"
482 "}\n",
483
484 "message_type {"
485 " name: \"TestMessage\""
486 " extension_range { start:10 end:20 }"
487 " extension_range { start:30 end:536870912 }"
488 "}");
489 }
490
TEST_F(ParseMessageTest,CompoundExtensionRange)491 TEST_F(ParseMessageTest, CompoundExtensionRange) {
492 ExpectParsesTo(
493 "message TestMessage {\n"
494 " extensions 2, 15, 9 to 11, 100 to max, 3;\n"
495 "}\n",
496
497 "message_type {"
498 " name: \"TestMessage\""
499 " extension_range { start:2 end:3 }"
500 " extension_range { start:15 end:16 }"
501 " extension_range { start:9 end:12 }"
502 " extension_range { start:100 end:536870912 }"
503 " extension_range { start:3 end:4 }"
504 "}");
505 }
506
TEST_F(ParseMessageTest,Extensions)507 TEST_F(ParseMessageTest, Extensions) {
508 ExpectParsesTo(
509 "extend Extendee1 { optional int32 foo = 12; }\n"
510 "extend Extendee2 { repeated TestMessage bar = 22; }\n",
511
512 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
513 " extendee: \"Extendee1\" } "
514 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
515 " type_name:\"TestMessage\" extendee: \"Extendee2\" }");
516 }
517
TEST_F(ParseMessageTest,ExtensionsInMessageScope)518 TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
519 ExpectParsesTo(
520 "message TestMessage {\n"
521 " extend Extendee1 { optional int32 foo = 12; }\n"
522 " extend Extendee2 { repeated TestMessage bar = 22; }\n"
523 "}\n",
524
525 "message_type {"
526 " name: \"TestMessage\""
527 " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
528 " extendee: \"Extendee1\" }"
529 " extension { name:\"bar\" label:LABEL_REPEATED number:22"
530 " type_name:\"TestMessage\" extendee: \"Extendee2\" }"
531 "}");
532 }
533
TEST_F(ParseMessageTest,MultipleExtensionsOneExtendee)534 TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
535 ExpectParsesTo(
536 "extend Extendee1 {\n"
537 " optional int32 foo = 12;\n"
538 " repeated TestMessage bar = 22;\n"
539 "}\n",
540
541 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
542 " extendee: \"Extendee1\" } "
543 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
544 " type_name:\"TestMessage\" extendee: \"Extendee1\" }");
545 }
546
547 // ===================================================================
548
549 typedef ParserTest ParseEnumTest;
550
TEST_F(ParseEnumTest,SimpleEnum)551 TEST_F(ParseEnumTest, SimpleEnum) {
552 ExpectParsesTo(
553 "enum TestEnum {\n"
554 " FOO = 0;\n"
555 "}\n",
556
557 "enum_type {"
558 " name: \"TestEnum\""
559 " value { name:\"FOO\" number:0 }"
560 "}");
561 }
562
TEST_F(ParseEnumTest,Values)563 TEST_F(ParseEnumTest, Values) {
564 ExpectParsesTo(
565 "enum TestEnum {\n"
566 " FOO = 13;\n"
567 " BAR = -10;\n"
568 " BAZ = 500;\n"
569 "}\n",
570
571 "enum_type {"
572 " name: \"TestEnum\""
573 " value { name:\"FOO\" number:13 }"
574 " value { name:\"BAR\" number:-10 }"
575 " value { name:\"BAZ\" number:500 }"
576 "}");
577 }
578
TEST_F(ParseEnumTest,ValueOptions)579 TEST_F(ParseEnumTest, ValueOptions) {
580 ExpectParsesTo(
581 "enum TestEnum {\n"
582 " FOO = 13;\n"
583 " BAR = -10 [ (something.text) = 'abc' ];\n"
584 " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
585 "}\n",
586
587 "enum_type {"
588 " name: \"TestEnum\""
589 " value { name: \"FOO\" number: 13 }"
590 " value { name: \"BAR\" number: -10 "
591 " options { "
592 " uninterpreted_option { "
593 " name { name_part: \"something.text\" is_extension: true } "
594 " string_value: \"abc\" "
595 " } "
596 " } "
597 " } "
598 " value { name: \"BAZ\" number: 500 "
599 " options { "
600 " uninterpreted_option { "
601 " name { name_part: \"something.text\" is_extension: true } "
602 " string_value: \"def\" "
603 " } "
604 " uninterpreted_option { "
605 " name { name_part: \"other\" is_extension: false } "
606 " positive_int_value: 1 "
607 " } "
608 " } "
609 " } "
610 "}");
611 }
612
613 // ===================================================================
614
615 typedef ParserTest ParseServiceTest;
616
TEST_F(ParseServiceTest,SimpleService)617 TEST_F(ParseServiceTest, SimpleService) {
618 ExpectParsesTo(
619 "service TestService {\n"
620 " rpc Foo(In) returns (Out);\n"
621 "}\n",
622
623 "service {"
624 " name: \"TestService\""
625 " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
626 "}");
627 }
628
TEST_F(ParseServiceTest,Methods)629 TEST_F(ParseServiceTest, Methods) {
630 ExpectParsesTo(
631 "service TestService {\n"
632 " rpc Foo(In1) returns (Out1);\n"
633 " rpc Bar(In2) returns (Out2);\n"
634 " rpc Baz(In3) returns (Out3);\n"
635 "}\n",
636
637 "service {"
638 " name: \"TestService\""
639 " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
640 " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
641 " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
642 "}");
643 }
644
645 // ===================================================================
646 // imports and packages
647
648 typedef ParserTest ParseMiscTest;
649
TEST_F(ParseMiscTest,ParseImport)650 TEST_F(ParseMiscTest, ParseImport) {
651 ExpectParsesTo(
652 "import \"foo/bar/baz.proto\";\n",
653 "dependency: \"foo/bar/baz.proto\"");
654 }
655
TEST_F(ParseMiscTest,ParseMultipleImports)656 TEST_F(ParseMiscTest, ParseMultipleImports) {
657 ExpectParsesTo(
658 "import \"foo.proto\";\n"
659 "import \"bar.proto\";\n"
660 "import \"baz.proto\";\n",
661 "dependency: \"foo.proto\""
662 "dependency: \"bar.proto\""
663 "dependency: \"baz.proto\"");
664 }
665
TEST_F(ParseMiscTest,ParsePackage)666 TEST_F(ParseMiscTest, ParsePackage) {
667 ExpectParsesTo(
668 "package foo.bar.baz;\n",
669 "package: \"foo.bar.baz\"");
670 }
671
TEST_F(ParseMiscTest,ParsePackageWithSpaces)672 TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
673 ExpectParsesTo(
674 "package foo . bar. \n"
675 " baz;\n",
676 "package: \"foo.bar.baz\"");
677 }
678
679 // ===================================================================
680 // options
681
TEST_F(ParseMiscTest,ParseFileOptions)682 TEST_F(ParseMiscTest, ParseFileOptions) {
683 ExpectParsesTo(
684 "option java_package = \"com.google.foo\";\n"
685 "option optimize_for = CODE_SIZE;",
686
687 "options {"
688 "uninterpreted_option { name { name_part: \"java_package\" "
689 " is_extension: false }"
690 " string_value: \"com.google.foo\"} "
691 "uninterpreted_option { name { name_part: \"optimize_for\" "
692 " is_extension: false }"
693 " identifier_value: \"CODE_SIZE\" } "
694 "}");
695 }
696
697 // ===================================================================
698 // Error tests
699 //
700 // There are a very large number of possible errors that the parser could
701 // report, so it's infeasible to test every single one of them. Instead,
702 // we test each unique call to AddError() in parser.h. This does not mean
703 // we are testing every possible error that Parser can generate because
704 // each variant of the Consume() helper only counts as one unique call to
705 // AddError().
706
707 typedef ParserTest ParseErrorTest;
708
TEST_F(ParseErrorTest,MissingSyntaxIdentifier)709 TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
710 require_syntax_identifier_ = true;
711 ExpectHasEarlyExitErrors(
712 "message TestMessage {}",
713 "0:0: File must begin with 'syntax = \"proto2\";'.\n");
714 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
715 }
716
TEST_F(ParseErrorTest,UnknownSyntaxIdentifier)717 TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
718 ExpectHasEarlyExitErrors(
719 "syntax = \"no_such_syntax\";",
720 "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
721 "only recognizes \"proto2\".\n");
722 EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
723 }
724
TEST_F(ParseErrorTest,SimpleSyntaxError)725 TEST_F(ParseErrorTest, SimpleSyntaxError) {
726 ExpectHasErrors(
727 "message TestMessage @#$ { blah }",
728 "0:20: Expected \"{\".\n");
729 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
730 }
731
TEST_F(ParseErrorTest,ExpectedTopLevel)732 TEST_F(ParseErrorTest, ExpectedTopLevel) {
733 ExpectHasErrors(
734 "blah;",
735 "0:0: Expected top-level statement (e.g. \"message\").\n");
736 }
737
TEST_F(ParseErrorTest,UnmatchedCloseBrace)738 TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
739 // This used to cause an infinite loop. Doh.
740 ExpectHasErrors(
741 "}",
742 "0:0: Expected top-level statement (e.g. \"message\").\n"
743 "0:0: Unmatched \"}\".\n");
744 }
745
746 // -------------------------------------------------------------------
747 // Message errors
748
TEST_F(ParseErrorTest,MessageMissingName)749 TEST_F(ParseErrorTest, MessageMissingName) {
750 ExpectHasErrors(
751 "message {}",
752 "0:8: Expected message name.\n");
753 }
754
TEST_F(ParseErrorTest,MessageMissingBody)755 TEST_F(ParseErrorTest, MessageMissingBody) {
756 ExpectHasErrors(
757 "message TestMessage;",
758 "0:19: Expected \"{\".\n");
759 }
760
TEST_F(ParseErrorTest,EofInMessage)761 TEST_F(ParseErrorTest, EofInMessage) {
762 ExpectHasErrors(
763 "message TestMessage {",
764 "0:21: Reached end of input in message definition (missing '}').\n");
765 }
766
TEST_F(ParseErrorTest,MissingFieldNumber)767 TEST_F(ParseErrorTest, MissingFieldNumber) {
768 ExpectHasErrors(
769 "message TestMessage {\n"
770 " optional int32 foo;\n"
771 "}\n",
772 "1:20: Missing field number.\n");
773 }
774
TEST_F(ParseErrorTest,ExpectedFieldNumber)775 TEST_F(ParseErrorTest, ExpectedFieldNumber) {
776 ExpectHasErrors(
777 "message TestMessage {\n"
778 " optional int32 foo = ;\n"
779 "}\n",
780 "1:23: Expected field number.\n");
781 }
782
TEST_F(ParseErrorTest,FieldNumberOutOfRange)783 TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
784 ExpectHasErrors(
785 "message TestMessage {\n"
786 " optional int32 foo = 0x100000000;\n"
787 "}\n",
788 "1:23: Integer out of range.\n");
789 }
790
TEST_F(ParseErrorTest,MissingLabel)791 TEST_F(ParseErrorTest, MissingLabel) {
792 ExpectHasErrors(
793 "message TestMessage {\n"
794 " int32 foo = 1;\n"
795 "}\n",
796 "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
797 }
798
TEST_F(ParseErrorTest,ExpectedOptionName)799 TEST_F(ParseErrorTest, ExpectedOptionName) {
800 ExpectHasErrors(
801 "message TestMessage {\n"
802 " optional uint32 foo = 1 [];\n"
803 "}\n",
804 "1:27: Expected identifier.\n");
805 }
806
TEST_F(ParseErrorTest,NonExtensionOptionNameBeginningWithDot)807 TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
808 ExpectHasErrors(
809 "message TestMessage {\n"
810 " optional uint32 foo = 1 [.foo=1];\n"
811 "}\n",
812 "1:27: Expected identifier.\n");
813 }
814
TEST_F(ParseErrorTest,DefaultValueTypeMismatch)815 TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
816 ExpectHasErrors(
817 "message TestMessage {\n"
818 " optional uint32 foo = 1 [default=true];\n"
819 "}\n",
820 "1:35: Expected integer.\n");
821 }
822
TEST_F(ParseErrorTest,DefaultValueNotBoolean)823 TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
824 ExpectHasErrors(
825 "message TestMessage {\n"
826 " optional bool foo = 1 [default=blah];\n"
827 "}\n",
828 "1:33: Expected \"true\" or \"false\".\n");
829 }
830
TEST_F(ParseErrorTest,DefaultValueNotString)831 TEST_F(ParseErrorTest, DefaultValueNotString) {
832 ExpectHasErrors(
833 "message TestMessage {\n"
834 " optional string foo = 1 [default=1];\n"
835 "}\n",
836 "1:35: Expected string.\n");
837 }
838
TEST_F(ParseErrorTest,DefaultValueUnsignedNegative)839 TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
840 ExpectHasErrors(
841 "message TestMessage {\n"
842 " optional uint32 foo = 1 [default=-1];\n"
843 "}\n",
844 "1:36: Unsigned field can't have negative default value.\n");
845 }
846
TEST_F(ParseErrorTest,DefaultValueTooLarge)847 TEST_F(ParseErrorTest, DefaultValueTooLarge) {
848 ExpectHasErrors(
849 "message TestMessage {\n"
850 " optional int32 foo = 1 [default= 0x80000000];\n"
851 " optional int32 foo = 1 [default=-0x80000001];\n"
852 " optional uint32 foo = 1 [default= 0x100000000];\n"
853 " optional int64 foo = 1 [default= 0x80000000000000000];\n"
854 " optional int64 foo = 1 [default=-0x80000000000000001];\n"
855 " optional uint64 foo = 1 [default= 0x100000000000000000];\n"
856 "}\n",
857 "1:36: Integer out of range.\n"
858 "2:36: Integer out of range.\n"
859 "3:36: Integer out of range.\n"
860 "4:36: Integer out of range.\n"
861 "5:36: Integer out of range.\n"
862 "6:36: Integer out of range.\n");
863 }
864
TEST_F(ParseErrorTest,DefaultValueMissing)865 TEST_F(ParseErrorTest, DefaultValueMissing) {
866 ExpectHasErrors(
867 "message TestMessage {\n"
868 " optional uint32 foo = 1 [default=];\n"
869 "}\n",
870 "1:35: Expected integer.\n");
871 }
872
TEST_F(ParseErrorTest,DefaultValueForGroup)873 TEST_F(ParseErrorTest, DefaultValueForGroup) {
874 ExpectHasErrors(
875 "message TestMessage {\n"
876 " optional group Foo = 1 [default=blah] {}\n"
877 "}\n",
878 "1:34: Messages can't have default values.\n");
879 }
880
TEST_F(ParseErrorTest,DuplicateDefaultValue)881 TEST_F(ParseErrorTest, DuplicateDefaultValue) {
882 ExpectHasErrors(
883 "message TestMessage {\n"
884 " optional uint32 foo = 1 [default=1,default=2];\n"
885 "}\n",
886 "1:37: Already set option \"default\".\n");
887 }
888
TEST_F(ParseErrorTest,GroupNotCapitalized)889 TEST_F(ParseErrorTest, GroupNotCapitalized) {
890 ExpectHasErrors(
891 "message TestMessage {\n"
892 " optional group foo = 1 {}\n"
893 "}\n",
894 "1:17: Group names must start with a capital letter.\n");
895 }
896
TEST_F(ParseErrorTest,GroupMissingBody)897 TEST_F(ParseErrorTest, GroupMissingBody) {
898 ExpectHasErrors(
899 "message TestMessage {\n"
900 " optional group Foo = 1;\n"
901 "}\n",
902 "1:24: Missing group body.\n");
903 }
904
TEST_F(ParseErrorTest,ExtendingPrimitive)905 TEST_F(ParseErrorTest, ExtendingPrimitive) {
906 ExpectHasErrors(
907 "extend int32 { optional string foo = 4; }\n",
908 "0:7: Expected message type.\n");
909 }
910
TEST_F(ParseErrorTest,ErrorInExtension)911 TEST_F(ParseErrorTest, ErrorInExtension) {
912 ExpectHasErrors(
913 "message Foo { extensions 100 to 199; }\n"
914 "extend Foo { optional string foo; }\n",
915 "1:32: Missing field number.\n");
916 }
917
TEST_F(ParseErrorTest,MultipleParseErrors)918 TEST_F(ParseErrorTest, MultipleParseErrors) {
919 // When a statement has a parse error, the parser should be able to continue
920 // parsing at the next statement.
921 ExpectHasErrors(
922 "message TestMessage {\n"
923 " optional int32 foo;\n"
924 " !invalid statement ending in a block { blah blah { blah } blah }\n"
925 " optional int32 bar = 3 {}\n"
926 "}\n",
927 "1:20: Missing field number.\n"
928 "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
929 "2:2: Expected type name.\n"
930 "3:25: Expected \";\".\n");
931 }
932
933 // -------------------------------------------------------------------
934 // Enum errors
935
TEST_F(ParseErrorTest,EofInEnum)936 TEST_F(ParseErrorTest, EofInEnum) {
937 ExpectHasErrors(
938 "enum TestEnum {",
939 "0:15: Reached end of input in enum definition (missing '}').\n");
940 }
941
TEST_F(ParseErrorTest,EnumValueMissingNumber)942 TEST_F(ParseErrorTest, EnumValueMissingNumber) {
943 ExpectHasErrors(
944 "enum TestEnum {\n"
945 " FOO;\n"
946 "}\n",
947 "1:5: Missing numeric value for enum constant.\n");
948 }
949
950 // -------------------------------------------------------------------
951 // Service errors
952
TEST_F(ParseErrorTest,EofInService)953 TEST_F(ParseErrorTest, EofInService) {
954 ExpectHasErrors(
955 "service TestService {",
956 "0:21: Reached end of input in service definition (missing '}').\n");
957 }
958
TEST_F(ParseErrorTest,ServiceMethodPrimitiveParams)959 TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
960 ExpectHasErrors(
961 "service TestService {\n"
962 " rpc Foo(int32) returns (string);\n"
963 "}\n",
964 "1:10: Expected message type.\n"
965 "1:26: Expected message type.\n");
966 }
967
TEST_F(ParseErrorTest,EofInMethodOptions)968 TEST_F(ParseErrorTest, EofInMethodOptions) {
969 ExpectHasErrors(
970 "service TestService {\n"
971 " rpc Foo(Bar) returns(Bar) {",
972 "1:29: Reached end of input in method options (missing '}').\n"
973 "1:29: Reached end of input in service definition (missing '}').\n");
974 }
975
TEST_F(ParseErrorTest,PrimitiveMethodInput)976 TEST_F(ParseErrorTest, PrimitiveMethodInput) {
977 ExpectHasErrors(
978 "service TestService {\n"
979 " rpc Foo(int32) returns(Bar);\n"
980 "}\n",
981 "1:10: Expected message type.\n");
982 }
983
TEST_F(ParseErrorTest,MethodOptionTypeError)984 TEST_F(ParseErrorTest, MethodOptionTypeError) {
985 // This used to cause an infinite loop.
986 ExpectHasErrors(
987 "message Baz {}\n"
988 "service Foo {\n"
989 " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
990 "}\n",
991 "2:45: Expected \"=\".\n");
992 }
993
994 // -------------------------------------------------------------------
995 // Import and package errors
996
TEST_F(ParseErrorTest,ImportNotQuoted)997 TEST_F(ParseErrorTest, ImportNotQuoted) {
998 ExpectHasErrors(
999 "import foo;\n",
1000 "0:7: Expected a string naming the file to import.\n");
1001 }
1002
TEST_F(ParseErrorTest,MultiplePackagesInFile)1003 TEST_F(ParseErrorTest, MultiplePackagesInFile) {
1004 ExpectHasErrors(
1005 "package foo;\n"
1006 "package bar;\n",
1007 "1:0: Multiple package definitions.\n");
1008 }
1009
1010 // ===================================================================
1011 // Test that errors detected by DescriptorPool correctly report line and
1012 // column numbers. We have one test for every call to RecordLocation() in
1013 // parser.cc.
1014
1015 typedef ParserTest ParserValidationErrorTest;
1016
TEST_F(ParserValidationErrorTest,PackageNameError)1017 TEST_F(ParserValidationErrorTest, PackageNameError) {
1018 // Create another file which defines symbol "foo".
1019 FileDescriptorProto other_file;
1020 other_file.set_name("bar.proto");
1021 other_file.add_message_type()->set_name("foo");
1022 EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
1023
1024 // Now try to define it as a package.
1025 ExpectHasValidationErrors(
1026 "package foo.bar;",
1027 "0:8: \"foo\" is already defined (as something other than a package) "
1028 "in file \"bar.proto\".\n");
1029 }
1030
TEST_F(ParserValidationErrorTest,MessageNameError)1031 TEST_F(ParserValidationErrorTest, MessageNameError) {
1032 ExpectHasValidationErrors(
1033 "message Foo {}\n"
1034 "message Foo {}\n",
1035 "1:8: \"Foo\" is already defined.\n");
1036 }
1037
TEST_F(ParserValidationErrorTest,FieldNameError)1038 TEST_F(ParserValidationErrorTest, FieldNameError) {
1039 ExpectHasValidationErrors(
1040 "message Foo {\n"
1041 " optional int32 bar = 1;\n"
1042 " optional int32 bar = 2;\n"
1043 "}\n",
1044 "2:17: \"bar\" is already defined in \"Foo\".\n");
1045 }
1046
TEST_F(ParserValidationErrorTest,FieldTypeError)1047 TEST_F(ParserValidationErrorTest, FieldTypeError) {
1048 ExpectHasValidationErrors(
1049 "message Foo {\n"
1050 " optional Baz bar = 1;\n"
1051 "}\n",
1052 "1:11: \"Baz\" is not defined.\n");
1053 }
1054
TEST_F(ParserValidationErrorTest,FieldNumberError)1055 TEST_F(ParserValidationErrorTest, FieldNumberError) {
1056 ExpectHasValidationErrors(
1057 "message Foo {\n"
1058 " optional int32 bar = 0;\n"
1059 "}\n",
1060 "1:23: Field numbers must be positive integers.\n");
1061 }
1062
TEST_F(ParserValidationErrorTest,FieldExtendeeError)1063 TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
1064 ExpectHasValidationErrors(
1065 "extend Baz { optional int32 bar = 1; }\n",
1066 "0:7: \"Baz\" is not defined.\n");
1067 }
1068
TEST_F(ParserValidationErrorTest,FieldDefaultValueError)1069 TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
1070 ExpectHasValidationErrors(
1071 "enum Baz { QUX = 1; }\n"
1072 "message Foo {\n"
1073 " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
1074 "}\n",
1075 "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
1076 }
1077
TEST_F(ParserValidationErrorTest,FileOptionNameError)1078 TEST_F(ParserValidationErrorTest, FileOptionNameError) {
1079 ExpectHasValidationErrors(
1080 "option foo = 5;",
1081 "0:7: Option \"foo\" unknown.\n");
1082 }
1083
TEST_F(ParserValidationErrorTest,FileOptionValueError)1084 TEST_F(ParserValidationErrorTest, FileOptionValueError) {
1085 ExpectHasValidationErrors(
1086 "option java_outer_classname = 5;",
1087 "0:30: Value must be quoted string for string option "
1088 "\"google.protobuf.FileOptions.java_outer_classname\".\n");
1089 }
1090
TEST_F(ParserValidationErrorTest,FieldOptionNameError)1091 TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
1092 ExpectHasValidationErrors(
1093 "message Foo {\n"
1094 " optional bool bar = 1 [foo=1];\n"
1095 "}\n",
1096 "1:25: Option \"foo\" unknown.\n");
1097 }
1098
TEST_F(ParserValidationErrorTest,FieldOptionValueError)1099 TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
1100 ExpectHasValidationErrors(
1101 "message Foo {\n"
1102 " optional int32 bar = 1 [ctype=1];\n"
1103 "}\n",
1104 "1:32: Value must be identifier for enum-valued option "
1105 "\"google.protobuf.FieldOptions.ctype\".\n");
1106 }
1107
TEST_F(ParserValidationErrorTest,ExtensionRangeNumberError)1108 TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
1109 ExpectHasValidationErrors(
1110 "message Foo {\n"
1111 " extensions 0;\n"
1112 "}\n",
1113 "1:13: Extension numbers must be positive integers.\n");
1114 }
1115
TEST_F(ParserValidationErrorTest,EnumNameError)1116 TEST_F(ParserValidationErrorTest, EnumNameError) {
1117 ExpectHasValidationErrors(
1118 "enum Foo {A = 1;}\n"
1119 "enum Foo {B = 1;}\n",
1120 "1:5: \"Foo\" is already defined.\n");
1121 }
1122
TEST_F(ParserValidationErrorTest,EnumValueNameError)1123 TEST_F(ParserValidationErrorTest, EnumValueNameError) {
1124 ExpectHasValidationErrors(
1125 "enum Foo {\n"
1126 " BAR = 1;\n"
1127 " BAR = 1;\n"
1128 "}\n",
1129 "2:2: \"BAR\" is already defined.\n");
1130 }
1131
TEST_F(ParserValidationErrorTest,ServiceNameError)1132 TEST_F(ParserValidationErrorTest, ServiceNameError) {
1133 ExpectHasValidationErrors(
1134 "service Foo {}\n"
1135 "service Foo {}\n",
1136 "1:8: \"Foo\" is already defined.\n");
1137 }
1138
TEST_F(ParserValidationErrorTest,MethodNameError)1139 TEST_F(ParserValidationErrorTest, MethodNameError) {
1140 ExpectHasValidationErrors(
1141 "message Baz {}\n"
1142 "service Foo {\n"
1143 " rpc Bar(Baz) returns(Baz);\n"
1144 " rpc Bar(Baz) returns(Baz);\n"
1145 "}\n",
1146 "3:6: \"Bar\" is already defined in \"Foo\".\n");
1147 }
1148
TEST_F(ParserValidationErrorTest,MethodInputTypeError)1149 TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
1150 ExpectHasValidationErrors(
1151 "message Baz {}\n"
1152 "service Foo {\n"
1153 " rpc Bar(Qux) returns(Baz);\n"
1154 "}\n",
1155 "2:10: \"Qux\" is not defined.\n");
1156 }
1157
TEST_F(ParserValidationErrorTest,MethodOutputTypeError)1158 TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
1159 ExpectHasValidationErrors(
1160 "message Baz {}\n"
1161 "service Foo {\n"
1162 " rpc Bar(Baz) returns(Qux);\n"
1163 "}\n",
1164 "2:23: \"Qux\" is not defined.\n");
1165 }
1166
1167 // ===================================================================
1168 // Test that the output from FileDescriptor::DebugString() (and all other
1169 // descriptor types) is parseable, and results in the same Descriptor
1170 // definitions again afoter parsing (not, however, that the order of messages
1171 // cannot be guaranteed to be the same)
1172
1173 typedef ParserTest ParseDecriptorDebugTest;
1174
1175 class CompareDescriptorNames {
1176 public:
operator ()(const DescriptorProto * left,const DescriptorProto * right)1177 bool operator()(const DescriptorProto* left, const DescriptorProto* right) {
1178 return left->name() < right->name();
1179 }
1180 };
1181
1182 // Sorts nested DescriptorProtos of a DescriptoProto, by name.
SortMessages(DescriptorProto * descriptor_proto)1183 void SortMessages(DescriptorProto *descriptor_proto) {
1184 int size = descriptor_proto->nested_type_size();
1185 // recursively sort; we can't guarantee the order of nested messages either
1186 for (int i = 0; i < size; ++i) {
1187 SortMessages(descriptor_proto->mutable_nested_type(i));
1188 }
1189 DescriptorProto **data =
1190 descriptor_proto->mutable_nested_type()->mutable_data();
1191 sort(data, data + size, CompareDescriptorNames());
1192 }
1193
1194 // Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
SortMessages(FileDescriptorProto * file_descriptor_proto)1195 void SortMessages(FileDescriptorProto *file_descriptor_proto) {
1196 int size = file_descriptor_proto->message_type_size();
1197 // recursively sort; we can't guarantee the order of nested messages either
1198 for (int i = 0; i < size; ++i) {
1199 SortMessages(file_descriptor_proto->mutable_message_type(i));
1200 }
1201 DescriptorProto **data =
1202 file_descriptor_proto->mutable_message_type()->mutable_data();
1203 sort(data, data + size, CompareDescriptorNames());
1204 }
1205
TEST_F(ParseDecriptorDebugTest,TestAllDescriptorTypes)1206 TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
1207 const FileDescriptor* original_file =
1208 protobuf_unittest::TestAllTypes::descriptor()->file();
1209 FileDescriptorProto expected;
1210 original_file->CopyTo(&expected);
1211
1212 // Get the DebugString of the unittest.proto FileDecriptor, which includes
1213 // all other descriptor types
1214 string debug_string = original_file->DebugString();
1215
1216 // Parse the debug string
1217 SetupParser(debug_string.c_str());
1218 FileDescriptorProto parsed;
1219 parser_->Parse(input_.get(), &parsed);
1220 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1221 ASSERT_EQ("", error_collector_.text_);
1222
1223 // We now have a FileDescriptorProto, but to compare with the expected we
1224 // need to link to a FileDecriptor, then output back to a proto. We'll
1225 // also need to give it the same name as the original.
1226 parsed.set_name("google/protobuf/unittest.proto");
1227 // We need the imported dependency before we can build our parsed proto
1228 const FileDescriptor* import =
1229 protobuf_unittest_import::ImportMessage::descriptor()->file();
1230 FileDescriptorProto import_proto;
1231 import->CopyTo(&import_proto);
1232 ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
1233 const FileDescriptor* actual = pool_.BuildFile(parsed);
1234 parsed.Clear();
1235 actual->CopyTo(&parsed);
1236 ASSERT_TRUE(actual != NULL);
1237
1238 // The messages might be in different orders, making them hard to compare.
1239 // So, sort the messages in the descriptor protos (including nested messages,
1240 // recursively).
1241 SortMessages(&expected);
1242 SortMessages(&parsed);
1243
1244 // I really wanted to use StringDiff here for the debug output on fail,
1245 // but the strings are too long for it, and if I increase its max size,
1246 // we get a memory allocation failure :(
1247 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
1248 }
1249
1250 // ===================================================================
1251
1252 } // anonymous namespace
1253
1254 } // namespace compiler
1255 } // namespace protobuf
1256 } // namespace google
1257