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 52namespace google { 53namespace protobuf { 54namespace compiler { 55 56namespace { 57 58class MockErrorCollector : public io::ErrorCollector { 59 public: 60 MockErrorCollector() {} 61 ~MockErrorCollector() {} 62 63 string text_; 64 65 // implements ErrorCollector --------------------------------------- 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 72class MockValidationErrorCollector : public DescriptorPool::ErrorCollector { 73 public: 74 MockValidationErrorCollector(const SourceLocationTable& source_locations, 75 io::ErrorCollector* wrapped_collector) 76 : source_locations_(source_locations), 77 wrapped_collector_(wrapped_collector) {} 78 ~MockValidationErrorCollector() {} 79 80 // implements ErrorCollector --------------------------------------- 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 96class ParserTest : public testing::Test { 97 protected: 98 ParserTest() 99 : require_syntax_identifier_(false) {} 100 101 // Set up the parser to parse the given 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. 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. 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. 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. 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 179TEST_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 190TEST_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 200TEST_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 211typedef ParserTest ParseMessageTest; 212 213TEST_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 225TEST_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 239TEST_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 253TEST_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 268TEST_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 284TEST_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 324TEST_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 394TEST_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 433TEST_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 447TEST_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 462TEST_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 477TEST_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 491TEST_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 507TEST_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 518TEST_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 534TEST_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 549typedef ParserTest ParseEnumTest; 550 551TEST_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 563TEST_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 579TEST_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 615typedef ParserTest ParseServiceTest; 616 617TEST_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 629TEST_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 648typedef ParserTest ParseMiscTest; 649 650TEST_F(ParseMiscTest, ParseImport) { 651 ExpectParsesTo( 652 "import \"foo/bar/baz.proto\";\n", 653 "dependency: \"foo/bar/baz.proto\""); 654} 655 656TEST_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 666TEST_F(ParseMiscTest, ParsePackage) { 667 ExpectParsesTo( 668 "package foo.bar.baz;\n", 669 "package: \"foo.bar.baz\""); 670} 671 672TEST_F(ParseMiscTest, ParsePackageWithSpaces) { 673 ExpectParsesTo( 674 "package foo . bar. \n" 675 " baz;\n", 676 "package: \"foo.bar.baz\""); 677} 678 679// =================================================================== 680// options 681 682TEST_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 707typedef ParserTest ParseErrorTest; 708 709TEST_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 717TEST_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 725TEST_F(ParseErrorTest, SimpleSyntaxError) { 726 ExpectHasErrors( 727 "message TestMessage @#$ { blah }", 728 "0:20: Expected \"{\".\n"); 729 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); 730} 731 732TEST_F(ParseErrorTest, ExpectedTopLevel) { 733 ExpectHasErrors( 734 "blah;", 735 "0:0: Expected top-level statement (e.g. \"message\").\n"); 736} 737 738TEST_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 749TEST_F(ParseErrorTest, MessageMissingName) { 750 ExpectHasErrors( 751 "message {}", 752 "0:8: Expected message name.\n"); 753} 754 755TEST_F(ParseErrorTest, MessageMissingBody) { 756 ExpectHasErrors( 757 "message TestMessage;", 758 "0:19: Expected \"{\".\n"); 759} 760 761TEST_F(ParseErrorTest, EofInMessage) { 762 ExpectHasErrors( 763 "message TestMessage {", 764 "0:21: Reached end of input in message definition (missing '}').\n"); 765} 766 767TEST_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 775TEST_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 783TEST_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 791TEST_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 799TEST_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 807TEST_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 815TEST_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 823TEST_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 831TEST_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 839TEST_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 847TEST_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 865TEST_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 873TEST_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 881TEST_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 889TEST_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 897TEST_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 905TEST_F(ParseErrorTest, ExtendingPrimitive) { 906 ExpectHasErrors( 907 "extend int32 { optional string foo = 4; }\n", 908 "0:7: Expected message type.\n"); 909} 910 911TEST_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 918TEST_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 936TEST_F(ParseErrorTest, EofInEnum) { 937 ExpectHasErrors( 938 "enum TestEnum {", 939 "0:15: Reached end of input in enum definition (missing '}').\n"); 940} 941 942TEST_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 953TEST_F(ParseErrorTest, EofInService) { 954 ExpectHasErrors( 955 "service TestService {", 956 "0:21: Reached end of input in service definition (missing '}').\n"); 957} 958 959TEST_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 968TEST_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 976TEST_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 984TEST_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 997TEST_F(ParseErrorTest, ImportNotQuoted) { 998 ExpectHasErrors( 999 "import foo;\n", 1000 "0:7: Expected a string naming the file to import.\n"); 1001} 1002 1003TEST_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 1015typedef ParserTest ParserValidationErrorTest; 1016 1017TEST_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 1031TEST_F(ParserValidationErrorTest, MessageNameError) { 1032 ExpectHasValidationErrors( 1033 "message Foo {}\n" 1034 "message Foo {}\n", 1035 "1:8: \"Foo\" is already defined.\n"); 1036} 1037 1038TEST_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 1047TEST_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 1055TEST_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 1063TEST_F(ParserValidationErrorTest, FieldExtendeeError) { 1064 ExpectHasValidationErrors( 1065 "extend Baz { optional int32 bar = 1; }\n", 1066 "0:7: \"Baz\" is not defined.\n"); 1067} 1068 1069TEST_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 1078TEST_F(ParserValidationErrorTest, FileOptionNameError) { 1079 ExpectHasValidationErrors( 1080 "option foo = 5;", 1081 "0:7: Option \"foo\" unknown.\n"); 1082} 1083 1084TEST_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 1091TEST_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 1099TEST_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 1108TEST_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 1116TEST_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 1123TEST_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 1132TEST_F(ParserValidationErrorTest, ServiceNameError) { 1133 ExpectHasValidationErrors( 1134 "service Foo {}\n" 1135 "service Foo {}\n", 1136 "1:8: \"Foo\" is already defined.\n"); 1137} 1138 1139TEST_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 1149TEST_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 1158TEST_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 1173typedef ParserTest ParseDecriptorDebugTest; 1174 1175class CompareDescriptorNames { 1176 public: 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. 1183void 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. 1195void 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 1206TEST_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