1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // Author: kenton (at) google.com (Kenton Varda) 32 // Based on original Protocol Buffers design by 33 // Sanjay Ghemawat, Jeff Dean, and others. 34 // 35 // This file makes extensive use of RFC 3092. :) 36 37 #include <memory> 38 #ifndef _SHARED_PTR_H 39 #include <google/protobuf/stubs/shared_ptr.h> 40 #endif 41 #include <vector> 42 43 #include <google/protobuf/compiler/importer.h> 44 #include <google/protobuf/unittest.pb.h> 45 #include <google/protobuf/unittest_custom_options.pb.h> 46 #include <google/protobuf/io/zero_copy_stream_impl.h> 47 #include <google/protobuf/descriptor.pb.h> 48 #include <google/protobuf/descriptor.h> 49 #include <google/protobuf/descriptor_database.h> 50 #include <google/protobuf/dynamic_message.h> 51 #include <google/protobuf/text_format.h> 52 #include <google/protobuf/stubs/strutil.h> 53 #include <google/protobuf/stubs/substitute.h> 54 55 #include <google/protobuf/stubs/common.h> 56 #include <google/protobuf/stubs/logging.h> 57 #include <google/protobuf/stubs/logging.h> 58 #include <google/protobuf/stubs/scoped_ptr.h> 59 #include <google/protobuf/testing/googletest.h> 60 #include <gtest/gtest.h> 61 62 namespace google { 63 namespace protobuf { 64 65 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler. 66 namespace descriptor_unittest { 67 68 // Some helpers to make assembling descriptors faster. 69 DescriptorProto* AddMessage(FileDescriptorProto* file, const string& name) { 70 DescriptorProto* result = file->add_message_type(); 71 result->set_name(name); 72 return result; 73 } 74 75 DescriptorProto* AddNestedMessage(DescriptorProto* parent, const string& name) { 76 DescriptorProto* result = parent->add_nested_type(); 77 result->set_name(name); 78 return result; 79 } 80 81 EnumDescriptorProto* AddEnum(FileDescriptorProto* file, const string& name) { 82 EnumDescriptorProto* result = file->add_enum_type(); 83 result->set_name(name); 84 return result; 85 } 86 87 EnumDescriptorProto* AddNestedEnum(DescriptorProto* parent, 88 const string& name) { 89 EnumDescriptorProto* result = parent->add_enum_type(); 90 result->set_name(name); 91 return result; 92 } 93 94 ServiceDescriptorProto* AddService(FileDescriptorProto* file, 95 const string& name) { 96 ServiceDescriptorProto* result = file->add_service(); 97 result->set_name(name); 98 return result; 99 } 100 101 FieldDescriptorProto* AddField(DescriptorProto* parent, 102 const string& name, int number, 103 FieldDescriptorProto::Label label, 104 FieldDescriptorProto::Type type) { 105 FieldDescriptorProto* result = parent->add_field(); 106 result->set_name(name); 107 result->set_number(number); 108 result->set_label(label); 109 result->set_type(type); 110 return result; 111 } 112 113 FieldDescriptorProto* AddExtension(FileDescriptorProto* file, 114 const string& extendee, 115 const string& name, int number, 116 FieldDescriptorProto::Label label, 117 FieldDescriptorProto::Type type) { 118 FieldDescriptorProto* result = file->add_extension(); 119 result->set_name(name); 120 result->set_number(number); 121 result->set_label(label); 122 result->set_type(type); 123 result->set_extendee(extendee); 124 return result; 125 } 126 127 FieldDescriptorProto* AddNestedExtension(DescriptorProto* parent, 128 const string& extendee, 129 const string& name, int number, 130 FieldDescriptorProto::Label label, 131 FieldDescriptorProto::Type type) { 132 FieldDescriptorProto* result = parent->add_extension(); 133 result->set_name(name); 134 result->set_number(number); 135 result->set_label(label); 136 result->set_type(type); 137 result->set_extendee(extendee); 138 return result; 139 } 140 141 DescriptorProto::ExtensionRange* AddExtensionRange(DescriptorProto* parent, 142 int start, int end) { 143 DescriptorProto::ExtensionRange* result = parent->add_extension_range(); 144 result->set_start(start); 145 result->set_end(end); 146 return result; 147 } 148 149 DescriptorProto::ReservedRange* AddReservedRange(DescriptorProto* parent, 150 int start, int end) { 151 DescriptorProto::ReservedRange* result = parent->add_reserved_range(); 152 result->set_start(start); 153 result->set_end(end); 154 return result; 155 } 156 157 EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto, 158 const string& name, int number) { 159 EnumValueDescriptorProto* result = enum_proto->add_value(); 160 result->set_name(name); 161 result->set_number(number); 162 return result; 163 } 164 165 MethodDescriptorProto* AddMethod(ServiceDescriptorProto* service, 166 const string& name, 167 const string& input_type, 168 const string& output_type) { 169 MethodDescriptorProto* result = service->add_method(); 170 result->set_name(name); 171 result->set_input_type(input_type); 172 result->set_output_type(output_type); 173 return result; 174 } 175 176 // Empty enums technically aren't allowed. We need to insert a dummy value 177 // into them. 178 void AddEmptyEnum(FileDescriptorProto* file, const string& name) { 179 AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1); 180 } 181 182 class MockErrorCollector : public DescriptorPool::ErrorCollector { 183 public: 184 MockErrorCollector() {} 185 ~MockErrorCollector() {} 186 187 string text_; 188 string warning_text_; 189 190 // implements ErrorCollector --------------------------------------- 191 void AddError(const string& filename, 192 const string& element_name, const Message* descriptor, 193 ErrorLocation location, const string& message) { 194 const char* location_name = NULL; 195 switch (location) { 196 case NAME : location_name = "NAME" ; break; 197 case NUMBER : location_name = "NUMBER" ; break; 198 case TYPE : location_name = "TYPE" ; break; 199 case EXTENDEE : location_name = "EXTENDEE" ; break; 200 case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break; 201 case OPTION_NAME : location_name = "OPTION_NAME" ; break; 202 case OPTION_VALUE : location_name = "OPTION_VALUE" ; break; 203 case INPUT_TYPE : location_name = "INPUT_TYPE" ; break; 204 case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break; 205 case OTHER : location_name = "OTHER" ; break; 206 } 207 208 strings::SubstituteAndAppend( 209 &text_, "$0: $1: $2: $3\n", 210 filename, element_name, location_name, message); 211 } 212 213 // implements ErrorCollector --------------------------------------- 214 void AddWarning(const string& filename, const string& element_name, 215 const Message* descriptor, ErrorLocation location, 216 const string& message) { 217 const char* location_name = NULL; 218 switch (location) { 219 case NAME : location_name = "NAME" ; break; 220 case NUMBER : location_name = "NUMBER" ; break; 221 case TYPE : location_name = "TYPE" ; break; 222 case EXTENDEE : location_name = "EXTENDEE" ; break; 223 case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break; 224 case OPTION_NAME : location_name = "OPTION_NAME" ; break; 225 case OPTION_VALUE : location_name = "OPTION_VALUE" ; break; 226 case INPUT_TYPE : location_name = "INPUT_TYPE" ; break; 227 case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break; 228 case OTHER : location_name = "OTHER" ; break; 229 } 230 231 strings::SubstituteAndAppend( 232 &warning_text_, "$0: $1: $2: $3\n", 233 filename, element_name, location_name, message); 234 } 235 }; 236 237 // =================================================================== 238 239 // Test simple files. 240 class FileDescriptorTest : public testing::Test { 241 protected: 242 virtual void SetUp() { 243 // Build descriptors for the following definitions: 244 // 245 // // in "foo.proto" 246 // message FooMessage { extensions 1; } 247 // enum FooEnum {FOO_ENUM_VALUE = 1;} 248 // service FooService {} 249 // extend FooMessage { optional int32 foo_extension = 1; } 250 // 251 // // in "bar.proto" 252 // package bar_package; 253 // message BarMessage { extensions 1; } 254 // enum BarEnum {BAR_ENUM_VALUE = 1;} 255 // service BarService {} 256 // extend BarMessage { optional int32 bar_extension = 1; } 257 // 258 // Also, we have an empty file "baz.proto". This file's purpose is to 259 // make sure that even though it has the same package as foo.proto, 260 // searching it for members of foo.proto won't work. 261 262 FileDescriptorProto foo_file; 263 foo_file.set_name("foo.proto"); 264 AddExtensionRange(AddMessage(&foo_file, "FooMessage"), 1, 2); 265 AddEnumValue(AddEnum(&foo_file, "FooEnum"), "FOO_ENUM_VALUE", 1); 266 AddService(&foo_file, "FooService"); 267 AddExtension(&foo_file, "FooMessage", "foo_extension", 1, 268 FieldDescriptorProto::LABEL_OPTIONAL, 269 FieldDescriptorProto::TYPE_INT32); 270 271 FileDescriptorProto bar_file; 272 bar_file.set_name("bar.proto"); 273 bar_file.set_package("bar_package"); 274 bar_file.add_dependency("foo.proto"); 275 AddExtensionRange(AddMessage(&bar_file, "BarMessage"), 1, 2); 276 AddEnumValue(AddEnum(&bar_file, "BarEnum"), "BAR_ENUM_VALUE", 1); 277 AddService(&bar_file, "BarService"); 278 AddExtension(&bar_file, "bar_package.BarMessage", "bar_extension", 1, 279 FieldDescriptorProto::LABEL_OPTIONAL, 280 FieldDescriptorProto::TYPE_INT32); 281 282 FileDescriptorProto baz_file; 283 baz_file.set_name("baz.proto"); 284 285 // Build the descriptors and get the pointers. 286 foo_file_ = pool_.BuildFile(foo_file); 287 ASSERT_TRUE(foo_file_ != NULL); 288 289 bar_file_ = pool_.BuildFile(bar_file); 290 ASSERT_TRUE(bar_file_ != NULL); 291 292 baz_file_ = pool_.BuildFile(baz_file); 293 ASSERT_TRUE(baz_file_ != NULL); 294 295 ASSERT_EQ(1, foo_file_->message_type_count()); 296 foo_message_ = foo_file_->message_type(0); 297 ASSERT_EQ(1, foo_file_->enum_type_count()); 298 foo_enum_ = foo_file_->enum_type(0); 299 ASSERT_EQ(1, foo_enum_->value_count()); 300 foo_enum_value_ = foo_enum_->value(0); 301 ASSERT_EQ(1, foo_file_->service_count()); 302 foo_service_ = foo_file_->service(0); 303 ASSERT_EQ(1, foo_file_->extension_count()); 304 foo_extension_ = foo_file_->extension(0); 305 306 ASSERT_EQ(1, bar_file_->message_type_count()); 307 bar_message_ = bar_file_->message_type(0); 308 ASSERT_EQ(1, bar_file_->enum_type_count()); 309 bar_enum_ = bar_file_->enum_type(0); 310 ASSERT_EQ(1, bar_enum_->value_count()); 311 bar_enum_value_ = bar_enum_->value(0); 312 ASSERT_EQ(1, bar_file_->service_count()); 313 bar_service_ = bar_file_->service(0); 314 ASSERT_EQ(1, bar_file_->extension_count()); 315 bar_extension_ = bar_file_->extension(0); 316 } 317 318 DescriptorPool pool_; 319 320 const FileDescriptor* foo_file_; 321 const FileDescriptor* bar_file_; 322 const FileDescriptor* baz_file_; 323 324 const Descriptor* foo_message_; 325 const EnumDescriptor* foo_enum_; 326 const EnumValueDescriptor* foo_enum_value_; 327 const ServiceDescriptor* foo_service_; 328 const FieldDescriptor* foo_extension_; 329 330 const Descriptor* bar_message_; 331 const EnumDescriptor* bar_enum_; 332 const EnumValueDescriptor* bar_enum_value_; 333 const ServiceDescriptor* bar_service_; 334 const FieldDescriptor* bar_extension_; 335 }; 336 337 TEST_F(FileDescriptorTest, Name) { 338 EXPECT_EQ("foo.proto", foo_file_->name()); 339 EXPECT_EQ("bar.proto", bar_file_->name()); 340 EXPECT_EQ("baz.proto", baz_file_->name()); 341 } 342 343 TEST_F(FileDescriptorTest, Package) { 344 EXPECT_EQ("", foo_file_->package()); 345 EXPECT_EQ("bar_package", bar_file_->package()); 346 } 347 348 TEST_F(FileDescriptorTest, Dependencies) { 349 EXPECT_EQ(0, foo_file_->dependency_count()); 350 EXPECT_EQ(1, bar_file_->dependency_count()); 351 EXPECT_EQ(foo_file_, bar_file_->dependency(0)); 352 } 353 354 TEST_F(FileDescriptorTest, FindMessageTypeByName) { 355 EXPECT_EQ(foo_message_, foo_file_->FindMessageTypeByName("FooMessage")); 356 EXPECT_EQ(bar_message_, bar_file_->FindMessageTypeByName("BarMessage")); 357 358 EXPECT_TRUE(foo_file_->FindMessageTypeByName("BarMessage") == NULL); 359 EXPECT_TRUE(bar_file_->FindMessageTypeByName("FooMessage") == NULL); 360 EXPECT_TRUE(baz_file_->FindMessageTypeByName("FooMessage") == NULL); 361 362 EXPECT_TRUE(foo_file_->FindMessageTypeByName("NoSuchMessage") == NULL); 363 EXPECT_TRUE(foo_file_->FindMessageTypeByName("FooEnum") == NULL); 364 } 365 366 TEST_F(FileDescriptorTest, FindEnumTypeByName) { 367 EXPECT_EQ(foo_enum_, foo_file_->FindEnumTypeByName("FooEnum")); 368 EXPECT_EQ(bar_enum_, bar_file_->FindEnumTypeByName("BarEnum")); 369 370 EXPECT_TRUE(foo_file_->FindEnumTypeByName("BarEnum") == NULL); 371 EXPECT_TRUE(bar_file_->FindEnumTypeByName("FooEnum") == NULL); 372 EXPECT_TRUE(baz_file_->FindEnumTypeByName("FooEnum") == NULL); 373 374 EXPECT_TRUE(foo_file_->FindEnumTypeByName("NoSuchEnum") == NULL); 375 EXPECT_TRUE(foo_file_->FindEnumTypeByName("FooMessage") == NULL); 376 } 377 378 TEST_F(FileDescriptorTest, FindEnumValueByName) { 379 EXPECT_EQ(foo_enum_value_, foo_file_->FindEnumValueByName("FOO_ENUM_VALUE")); 380 EXPECT_EQ(bar_enum_value_, bar_file_->FindEnumValueByName("BAR_ENUM_VALUE")); 381 382 EXPECT_TRUE(foo_file_->FindEnumValueByName("BAR_ENUM_VALUE") == NULL); 383 EXPECT_TRUE(bar_file_->FindEnumValueByName("FOO_ENUM_VALUE") == NULL); 384 EXPECT_TRUE(baz_file_->FindEnumValueByName("FOO_ENUM_VALUE") == NULL); 385 386 EXPECT_TRUE(foo_file_->FindEnumValueByName("NO_SUCH_VALUE") == NULL); 387 EXPECT_TRUE(foo_file_->FindEnumValueByName("FooMessage") == NULL); 388 } 389 390 TEST_F(FileDescriptorTest, FindServiceByName) { 391 EXPECT_EQ(foo_service_, foo_file_->FindServiceByName("FooService")); 392 EXPECT_EQ(bar_service_, bar_file_->FindServiceByName("BarService")); 393 394 EXPECT_TRUE(foo_file_->FindServiceByName("BarService") == NULL); 395 EXPECT_TRUE(bar_file_->FindServiceByName("FooService") == NULL); 396 EXPECT_TRUE(baz_file_->FindServiceByName("FooService") == NULL); 397 398 EXPECT_TRUE(foo_file_->FindServiceByName("NoSuchService") == NULL); 399 EXPECT_TRUE(foo_file_->FindServiceByName("FooMessage") == NULL); 400 } 401 402 TEST_F(FileDescriptorTest, FindExtensionByName) { 403 EXPECT_EQ(foo_extension_, foo_file_->FindExtensionByName("foo_extension")); 404 EXPECT_EQ(bar_extension_, bar_file_->FindExtensionByName("bar_extension")); 405 406 EXPECT_TRUE(foo_file_->FindExtensionByName("bar_extension") == NULL); 407 EXPECT_TRUE(bar_file_->FindExtensionByName("foo_extension") == NULL); 408 EXPECT_TRUE(baz_file_->FindExtensionByName("foo_extension") == NULL); 409 410 EXPECT_TRUE(foo_file_->FindExtensionByName("no_such_extension") == NULL); 411 EXPECT_TRUE(foo_file_->FindExtensionByName("FooMessage") == NULL); 412 } 413 414 TEST_F(FileDescriptorTest, FindExtensionByNumber) { 415 EXPECT_EQ(foo_extension_, pool_.FindExtensionByNumber(foo_message_, 1)); 416 EXPECT_EQ(bar_extension_, pool_.FindExtensionByNumber(bar_message_, 1)); 417 418 EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == NULL); 419 } 420 421 TEST_F(FileDescriptorTest, BuildAgain) { 422 // Test that if te call BuildFile again on the same input we get the same 423 // FileDescriptor back. 424 FileDescriptorProto file; 425 foo_file_->CopyTo(&file); 426 EXPECT_EQ(foo_file_, pool_.BuildFile(file)); 427 428 // But if we change the file then it won't work. 429 file.set_package("some.other.package"); 430 EXPECT_TRUE(pool_.BuildFile(file) == NULL); 431 } 432 433 TEST_F(FileDescriptorTest, BuildAgainWithSyntax) { 434 // Test that if te call BuildFile again on the same input we get the same 435 // FileDescriptor back even if syntax param is specified. 436 FileDescriptorProto proto_syntax2; 437 proto_syntax2.set_name("foo_syntax2"); 438 proto_syntax2.set_syntax("proto2"); 439 440 const FileDescriptor* proto2_descriptor = pool_.BuildFile(proto_syntax2); 441 EXPECT_TRUE(proto2_descriptor != NULL); 442 EXPECT_EQ(proto2_descriptor, pool_.BuildFile(proto_syntax2)); 443 444 FileDescriptorProto implicit_proto2; 445 implicit_proto2.set_name("foo_implicit_syntax2"); 446 447 const FileDescriptor* implicit_proto2_descriptor = 448 pool_.BuildFile(implicit_proto2); 449 EXPECT_TRUE(implicit_proto2_descriptor != NULL); 450 // We get the same FileDescriptor back if syntax param is explicitly 451 // specified. 452 implicit_proto2.set_syntax("proto2"); 453 EXPECT_EQ(implicit_proto2_descriptor, pool_.BuildFile(implicit_proto2)); 454 455 FileDescriptorProto proto_syntax3; 456 proto_syntax3.set_name("foo_syntax3"); 457 proto_syntax3.set_syntax("proto3"); 458 459 const FileDescriptor* proto3_descriptor = pool_.BuildFile(proto_syntax3); 460 EXPECT_TRUE(proto3_descriptor != NULL); 461 EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3)); 462 } 463 464 TEST_F(FileDescriptorTest, Syntax) { 465 FileDescriptorProto proto; 466 proto.set_name("foo"); 467 // Enable the test when we also populate the syntax for proto2. 468 #if 0 469 { 470 proto.set_syntax("proto2"); 471 DescriptorPool pool; 472 const FileDescriptor* file = pool.BuildFile(proto); 473 EXPECT_TRUE(file != NULL); 474 EXPECT_EQ(FileDescriptor::SYNTAX_PROTO2, file->syntax()); 475 FileDescriptorProto other; 476 file->CopyTo(&other); 477 EXPECT_EQ("proto2", other.syntax()); 478 } 479 #endif 480 { 481 proto.set_syntax("proto3"); 482 DescriptorPool pool; 483 const FileDescriptor* file = pool.BuildFile(proto); 484 EXPECT_TRUE(file != NULL); 485 EXPECT_EQ(FileDescriptor::SYNTAX_PROTO3, file->syntax()); 486 FileDescriptorProto other; 487 file->CopyTo(&other); 488 EXPECT_EQ("proto3", other.syntax()); 489 } 490 } 491 492 // =================================================================== 493 494 // Test simple flat messages and fields. 495 class DescriptorTest : public testing::Test { 496 protected: 497 virtual void SetUp() { 498 // Build descriptors for the following definitions: 499 // 500 // // in "foo.proto" 501 // message TestForeign {} 502 // enum TestEnum {} 503 // 504 // message TestMessage { 505 // required string foo = 1; 506 // optional TestEnum bar = 6; 507 // repeated TestForeign baz = 500000000; 508 // optional group qux = 15 {} 509 // } 510 // 511 // // in "bar.proto" 512 // package corge.grault; 513 // message TestMessage2 { 514 // required string foo = 1; 515 // required string bar = 2; 516 // required string quux = 6; 517 // } 518 // 519 // // in "map.proto" 520 // message TestMessage3 { 521 // map<int32, int32> map_int32_int32 = 1; 522 // } 523 // 524 // // in "json.proto" 525 // message TestMessage4 { 526 // optional int32 field_name1 = 1; 527 // optional int32 fieldName2 = 2; 528 // optional int32 FieldName3 = 3; 529 // optional int32 _field_name4 = 4; 530 // optional int32 FIELD_NAME5 = 5; 531 // optional int32 field_name6 = 6 [json_name = "@type"]; 532 // } 533 // 534 // We cheat and use TestForeign as the type for qux rather than create 535 // an actual nested type. 536 // 537 // Since all primitive types (including string) use the same building 538 // code, there's no need to test each one individually. 539 // 540 // TestMessage2 is primarily here to test FindFieldByName and friends. 541 // All messages created from the same DescriptorPool share the same lookup 542 // table, so we need to insure that they don't interfere. 543 544 FileDescriptorProto foo_file; 545 foo_file.set_name("foo.proto"); 546 AddMessage(&foo_file, "TestForeign"); 547 AddEmptyEnum(&foo_file, "TestEnum"); 548 549 DescriptorProto* message = AddMessage(&foo_file, "TestMessage"); 550 AddField(message, "foo", 1, 551 FieldDescriptorProto::LABEL_REQUIRED, 552 FieldDescriptorProto::TYPE_STRING); 553 AddField(message, "bar", 6, 554 FieldDescriptorProto::LABEL_OPTIONAL, 555 FieldDescriptorProto::TYPE_ENUM) 556 ->set_type_name("TestEnum"); 557 AddField(message, "baz", 500000000, 558 FieldDescriptorProto::LABEL_REPEATED, 559 FieldDescriptorProto::TYPE_MESSAGE) 560 ->set_type_name("TestForeign"); 561 AddField(message, "qux", 15, 562 FieldDescriptorProto::LABEL_OPTIONAL, 563 FieldDescriptorProto::TYPE_GROUP) 564 ->set_type_name("TestForeign"); 565 566 FileDescriptorProto bar_file; 567 bar_file.set_name("bar.proto"); 568 bar_file.set_package("corge.grault"); 569 570 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2"); 571 AddField(message2, "foo", 1, 572 FieldDescriptorProto::LABEL_REQUIRED, 573 FieldDescriptorProto::TYPE_STRING); 574 AddField(message2, "bar", 2, 575 FieldDescriptorProto::LABEL_REQUIRED, 576 FieldDescriptorProto::TYPE_STRING); 577 AddField(message2, "quux", 6, 578 FieldDescriptorProto::LABEL_REQUIRED, 579 FieldDescriptorProto::TYPE_STRING); 580 581 FileDescriptorProto map_file; 582 map_file.set_name("map.proto"); 583 DescriptorProto* message3 = AddMessage(&map_file, "TestMessage3"); 584 585 DescriptorProto* entry = AddNestedMessage(message3, "MapInt32Int32Entry"); 586 AddField(entry, "key", 1, 587 FieldDescriptorProto::LABEL_OPTIONAL, 588 FieldDescriptorProto::TYPE_INT32); 589 AddField(entry, "value", 2, 590 FieldDescriptorProto::LABEL_OPTIONAL, 591 FieldDescriptorProto::TYPE_INT32); 592 entry->mutable_options()->set_map_entry(true); 593 594 AddField(message3, "map_int32_int32", 1, 595 FieldDescriptorProto::LABEL_REPEATED, 596 FieldDescriptorProto::TYPE_MESSAGE) 597 ->set_type_name("MapInt32Int32Entry"); 598 599 FileDescriptorProto json_file; 600 json_file.set_name("json.proto"); 601 json_file.set_syntax("proto3"); 602 DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4"); 603 AddField(message4, "field_name1", 1, 604 FieldDescriptorProto::LABEL_OPTIONAL, 605 FieldDescriptorProto::TYPE_INT32); 606 AddField(message4, "fieldName2", 2, 607 FieldDescriptorProto::LABEL_OPTIONAL, 608 FieldDescriptorProto::TYPE_INT32); 609 AddField(message4, "FieldName3", 3, 610 FieldDescriptorProto::LABEL_OPTIONAL, 611 FieldDescriptorProto::TYPE_INT32); 612 AddField(message4, "_field_name4", 4, 613 FieldDescriptorProto::LABEL_OPTIONAL, 614 FieldDescriptorProto::TYPE_INT32); 615 AddField(message4, "FIELD_NAME5", 5, 616 FieldDescriptorProto::LABEL_OPTIONAL, 617 FieldDescriptorProto::TYPE_INT32); 618 AddField(message4, "field_name6", 6, 619 FieldDescriptorProto::LABEL_OPTIONAL, 620 FieldDescriptorProto::TYPE_INT32) 621 ->set_json_name("@type"); 622 623 // Build the descriptors and get the pointers. 624 foo_file_ = pool_.BuildFile(foo_file); 625 ASSERT_TRUE(foo_file_ != NULL); 626 627 bar_file_ = pool_.BuildFile(bar_file); 628 ASSERT_TRUE(bar_file_ != NULL); 629 630 map_file_ = pool_.BuildFile(map_file); 631 ASSERT_TRUE(map_file_ != NULL); 632 633 json_file_ = pool_.BuildFile(json_file); 634 ASSERT_TRUE(json_file_ != NULL); 635 636 ASSERT_EQ(1, foo_file_->enum_type_count()); 637 enum_ = foo_file_->enum_type(0); 638 639 ASSERT_EQ(2, foo_file_->message_type_count()); 640 foreign_ = foo_file_->message_type(0); 641 message_ = foo_file_->message_type(1); 642 643 ASSERT_EQ(4, message_->field_count()); 644 foo_ = message_->field(0); 645 bar_ = message_->field(1); 646 baz_ = message_->field(2); 647 qux_ = message_->field(3); 648 649 ASSERT_EQ(1, bar_file_->message_type_count()); 650 message2_ = bar_file_->message_type(0); 651 652 ASSERT_EQ(3, message2_->field_count()); 653 foo2_ = message2_->field(0); 654 bar2_ = message2_->field(1); 655 quux2_ = message2_->field(2); 656 657 ASSERT_EQ(1, map_file_->message_type_count()); 658 message3_ = map_file_->message_type(0); 659 660 ASSERT_EQ(1, message3_->field_count()); 661 map_ = message3_->field(0); 662 663 ASSERT_EQ(1, json_file_->message_type_count()); 664 message4_ = json_file_->message_type(0); 665 } 666 667 void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) { 668 message->CopyTo(proto); 669 message->CopyJsonNameTo(proto); 670 } 671 672 DescriptorPool pool_; 673 674 const FileDescriptor* foo_file_; 675 const FileDescriptor* bar_file_; 676 const FileDescriptor* map_file_; 677 const FileDescriptor* json_file_; 678 679 const Descriptor* message_; 680 const Descriptor* message2_; 681 const Descriptor* message3_; 682 const Descriptor* message4_; 683 const Descriptor* foreign_; 684 const EnumDescriptor* enum_; 685 686 const FieldDescriptor* foo_; 687 const FieldDescriptor* bar_; 688 const FieldDescriptor* baz_; 689 const FieldDescriptor* qux_; 690 691 const FieldDescriptor* foo2_; 692 const FieldDescriptor* bar2_; 693 const FieldDescriptor* quux2_; 694 695 const FieldDescriptor* map_; 696 }; 697 698 TEST_F(DescriptorTest, Name) { 699 EXPECT_EQ("TestMessage", message_->name()); 700 EXPECT_EQ("TestMessage", message_->full_name()); 701 EXPECT_EQ(foo_file_, message_->file()); 702 703 EXPECT_EQ("TestMessage2", message2_->name()); 704 EXPECT_EQ("corge.grault.TestMessage2", message2_->full_name()); 705 EXPECT_EQ(bar_file_, message2_->file()); 706 } 707 708 TEST_F(DescriptorTest, ContainingType) { 709 EXPECT_TRUE(message_->containing_type() == NULL); 710 EXPECT_TRUE(message2_->containing_type() == NULL); 711 } 712 713 TEST_F(DescriptorTest, FieldsByIndex) { 714 ASSERT_EQ(4, message_->field_count()); 715 EXPECT_EQ(foo_, message_->field(0)); 716 EXPECT_EQ(bar_, message_->field(1)); 717 EXPECT_EQ(baz_, message_->field(2)); 718 EXPECT_EQ(qux_, message_->field(3)); 719 } 720 721 TEST_F(DescriptorTest, FindFieldByName) { 722 // All messages in the same DescriptorPool share a single lookup table for 723 // fields. So, in addition to testing that FindFieldByName finds the fields 724 // of the message, we need to test that it does *not* find the fields of 725 // *other* messages. 726 727 EXPECT_EQ(foo_, message_->FindFieldByName("foo")); 728 EXPECT_EQ(bar_, message_->FindFieldByName("bar")); 729 EXPECT_EQ(baz_, message_->FindFieldByName("baz")); 730 EXPECT_EQ(qux_, message_->FindFieldByName("qux")); 731 EXPECT_TRUE(message_->FindFieldByName("no_such_field") == NULL); 732 EXPECT_TRUE(message_->FindFieldByName("quux") == NULL); 733 734 EXPECT_EQ(foo2_ , message2_->FindFieldByName("foo" )); 735 EXPECT_EQ(bar2_ , message2_->FindFieldByName("bar" )); 736 EXPECT_EQ(quux2_, message2_->FindFieldByName("quux")); 737 EXPECT_TRUE(message2_->FindFieldByName("baz") == NULL); 738 EXPECT_TRUE(message2_->FindFieldByName("qux") == NULL); 739 } 740 741 TEST_F(DescriptorTest, FindFieldByNumber) { 742 EXPECT_EQ(foo_, message_->FindFieldByNumber(1)); 743 EXPECT_EQ(bar_, message_->FindFieldByNumber(6)); 744 EXPECT_EQ(baz_, message_->FindFieldByNumber(500000000)); 745 EXPECT_EQ(qux_, message_->FindFieldByNumber(15)); 746 EXPECT_TRUE(message_->FindFieldByNumber(837592) == NULL); 747 EXPECT_TRUE(message_->FindFieldByNumber(2) == NULL); 748 749 EXPECT_EQ(foo2_ , message2_->FindFieldByNumber(1)); 750 EXPECT_EQ(bar2_ , message2_->FindFieldByNumber(2)); 751 EXPECT_EQ(quux2_, message2_->FindFieldByNumber(6)); 752 EXPECT_TRUE(message2_->FindFieldByNumber(15) == NULL); 753 EXPECT_TRUE(message2_->FindFieldByNumber(500000000) == NULL); 754 } 755 756 TEST_F(DescriptorTest, FieldName) { 757 EXPECT_EQ("foo", foo_->name()); 758 EXPECT_EQ("bar", bar_->name()); 759 EXPECT_EQ("baz", baz_->name()); 760 EXPECT_EQ("qux", qux_->name()); 761 } 762 763 TEST_F(DescriptorTest, FieldFullName) { 764 EXPECT_EQ("TestMessage.foo", foo_->full_name()); 765 EXPECT_EQ("TestMessage.bar", bar_->full_name()); 766 EXPECT_EQ("TestMessage.baz", baz_->full_name()); 767 EXPECT_EQ("TestMessage.qux", qux_->full_name()); 768 769 EXPECT_EQ("corge.grault.TestMessage2.foo", foo2_->full_name()); 770 EXPECT_EQ("corge.grault.TestMessage2.bar", bar2_->full_name()); 771 EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name()); 772 } 773 774 TEST_F(DescriptorTest, FieldJsonName) { 775 EXPECT_EQ("fieldName1", message4_->field(0)->json_name()); 776 EXPECT_EQ("fieldName2", message4_->field(1)->json_name()); 777 EXPECT_EQ("fieldName3", message4_->field(2)->json_name()); 778 EXPECT_EQ("fieldName4", message4_->field(3)->json_name()); 779 EXPECT_EQ("fIELDNAME5", message4_->field(4)->json_name()); 780 EXPECT_EQ("@type", message4_->field(5)->json_name()); 781 782 DescriptorProto proto; 783 message4_->CopyTo(&proto); 784 ASSERT_EQ(6, proto.field_size()); 785 EXPECT_FALSE(proto.field(0).has_json_name()); 786 EXPECT_FALSE(proto.field(1).has_json_name()); 787 EXPECT_FALSE(proto.field(2).has_json_name()); 788 EXPECT_FALSE(proto.field(3).has_json_name()); 789 EXPECT_FALSE(proto.field(4).has_json_name()); 790 EXPECT_EQ("@type", proto.field(5).json_name()); 791 792 proto.Clear(); 793 CopyWithJsonName(message4_, &proto); 794 ASSERT_EQ(6, proto.field_size()); 795 EXPECT_EQ("fieldName1", proto.field(0).json_name()); 796 EXPECT_EQ("fieldName2", proto.field(1).json_name()); 797 EXPECT_EQ("fieldName3", proto.field(2).json_name()); 798 EXPECT_EQ("fieldName4", proto.field(3).json_name()); 799 EXPECT_EQ("fIELDNAME5", proto.field(4).json_name()); 800 EXPECT_EQ("@type", proto.field(5).json_name()); 801 } 802 803 TEST_F(DescriptorTest, FieldFile) { 804 EXPECT_EQ(foo_file_, foo_->file()); 805 EXPECT_EQ(foo_file_, bar_->file()); 806 EXPECT_EQ(foo_file_, baz_->file()); 807 EXPECT_EQ(foo_file_, qux_->file()); 808 809 EXPECT_EQ(bar_file_, foo2_->file()); 810 EXPECT_EQ(bar_file_, bar2_->file()); 811 EXPECT_EQ(bar_file_, quux2_->file()); 812 } 813 814 TEST_F(DescriptorTest, FieldIndex) { 815 EXPECT_EQ(0, foo_->index()); 816 EXPECT_EQ(1, bar_->index()); 817 EXPECT_EQ(2, baz_->index()); 818 EXPECT_EQ(3, qux_->index()); 819 } 820 821 TEST_F(DescriptorTest, FieldNumber) { 822 EXPECT_EQ( 1, foo_->number()); 823 EXPECT_EQ( 6, bar_->number()); 824 EXPECT_EQ(500000000, baz_->number()); 825 EXPECT_EQ( 15, qux_->number()); 826 } 827 828 TEST_F(DescriptorTest, FieldType) { 829 EXPECT_EQ(FieldDescriptor::TYPE_STRING , foo_->type()); 830 EXPECT_EQ(FieldDescriptor::TYPE_ENUM , bar_->type()); 831 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_->type()); 832 EXPECT_EQ(FieldDescriptor::TYPE_GROUP , qux_->type()); 833 } 834 835 TEST_F(DescriptorTest, FieldLabel) { 836 EXPECT_EQ(FieldDescriptor::LABEL_REQUIRED, foo_->label()); 837 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->label()); 838 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, baz_->label()); 839 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, qux_->label()); 840 841 EXPECT_TRUE (foo_->is_required()); 842 EXPECT_FALSE(foo_->is_optional()); 843 EXPECT_FALSE(foo_->is_repeated()); 844 845 EXPECT_FALSE(bar_->is_required()); 846 EXPECT_TRUE (bar_->is_optional()); 847 EXPECT_FALSE(bar_->is_repeated()); 848 849 EXPECT_FALSE(baz_->is_required()); 850 EXPECT_FALSE(baz_->is_optional()); 851 EXPECT_TRUE (baz_->is_repeated()); 852 } 853 854 TEST_F(DescriptorTest, IsMap) { 855 EXPECT_TRUE(map_->is_map()); 856 EXPECT_FALSE(baz_->is_map()); 857 EXPECT_TRUE(map_->message_type()->options().map_entry()); 858 } 859 860 TEST_F(DescriptorTest, FieldHasDefault) { 861 EXPECT_FALSE(foo_->has_default_value()); 862 EXPECT_FALSE(bar_->has_default_value()); 863 EXPECT_FALSE(baz_->has_default_value()); 864 EXPECT_FALSE(qux_->has_default_value()); 865 } 866 867 TEST_F(DescriptorTest, FieldContainingType) { 868 EXPECT_EQ(message_, foo_->containing_type()); 869 EXPECT_EQ(message_, bar_->containing_type()); 870 EXPECT_EQ(message_, baz_->containing_type()); 871 EXPECT_EQ(message_, qux_->containing_type()); 872 873 EXPECT_EQ(message2_, foo2_ ->containing_type()); 874 EXPECT_EQ(message2_, bar2_ ->containing_type()); 875 EXPECT_EQ(message2_, quux2_->containing_type()); 876 } 877 878 TEST_F(DescriptorTest, FieldMessageType) { 879 EXPECT_TRUE(foo_->message_type() == NULL); 880 EXPECT_TRUE(bar_->message_type() == NULL); 881 882 EXPECT_EQ(foreign_, baz_->message_type()); 883 EXPECT_EQ(foreign_, qux_->message_type()); 884 } 885 886 TEST_F(DescriptorTest, FieldEnumType) { 887 EXPECT_TRUE(foo_->enum_type() == NULL); 888 EXPECT_TRUE(baz_->enum_type() == NULL); 889 EXPECT_TRUE(qux_->enum_type() == NULL); 890 891 EXPECT_EQ(enum_, bar_->enum_type()); 892 } 893 894 // =================================================================== 895 896 // Test simple flat messages and fields. 897 class OneofDescriptorTest : public testing::Test { 898 protected: 899 virtual void SetUp() { 900 // Build descriptors for the following definitions: 901 // 902 // package garply; 903 // message TestOneof { 904 // optional int32 a = 1; 905 // oneof foo { 906 // string b = 2; 907 // TestOneof c = 3; 908 // } 909 // oneof bar { 910 // float d = 4; 911 // } 912 // } 913 914 FileDescriptorProto baz_file; 915 baz_file.set_name("baz.proto"); 916 baz_file.set_package("garply"); 917 918 DescriptorProto* oneof_message = AddMessage(&baz_file, "TestOneof"); 919 oneof_message->add_oneof_decl()->set_name("foo"); 920 oneof_message->add_oneof_decl()->set_name("bar"); 921 922 AddField(oneof_message, "a", 1, 923 FieldDescriptorProto::LABEL_OPTIONAL, 924 FieldDescriptorProto::TYPE_INT32); 925 AddField(oneof_message, "b", 2, 926 FieldDescriptorProto::LABEL_OPTIONAL, 927 FieldDescriptorProto::TYPE_STRING); 928 oneof_message->mutable_field(1)->set_oneof_index(0); 929 AddField(oneof_message, "c", 3, 930 FieldDescriptorProto::LABEL_OPTIONAL, 931 FieldDescriptorProto::TYPE_MESSAGE); 932 oneof_message->mutable_field(2)->set_oneof_index(0); 933 oneof_message->mutable_field(2)->set_type_name("TestOneof"); 934 935 AddField(oneof_message, "d", 4, 936 FieldDescriptorProto::LABEL_OPTIONAL, 937 FieldDescriptorProto::TYPE_FLOAT); 938 oneof_message->mutable_field(3)->set_oneof_index(1); 939 940 // Build the descriptors and get the pointers. 941 baz_file_ = pool_.BuildFile(baz_file); 942 ASSERT_TRUE(baz_file_ != NULL); 943 944 ASSERT_EQ(1, baz_file_->message_type_count()); 945 oneof_message_ = baz_file_->message_type(0); 946 947 ASSERT_EQ(2, oneof_message_->oneof_decl_count()); 948 oneof_ = oneof_message_->oneof_decl(0); 949 oneof2_ = oneof_message_->oneof_decl(1); 950 951 ASSERT_EQ(4, oneof_message_->field_count()); 952 a_ = oneof_message_->field(0); 953 b_ = oneof_message_->field(1); 954 c_ = oneof_message_->field(2); 955 d_ = oneof_message_->field(3); 956 } 957 958 DescriptorPool pool_; 959 960 const FileDescriptor* baz_file_; 961 962 const Descriptor* oneof_message_; 963 964 const OneofDescriptor* oneof_; 965 const OneofDescriptor* oneof2_; 966 const FieldDescriptor* a_; 967 const FieldDescriptor* b_; 968 const FieldDescriptor* c_; 969 const FieldDescriptor* d_; 970 const FieldDescriptor* e_; 971 const FieldDescriptor* f_; 972 }; 973 974 TEST_F(OneofDescriptorTest, Normal) { 975 EXPECT_EQ("foo", oneof_->name()); 976 EXPECT_EQ("garply.TestOneof.foo", oneof_->full_name()); 977 EXPECT_EQ(0, oneof_->index()); 978 ASSERT_EQ(2, oneof_->field_count()); 979 EXPECT_EQ(b_, oneof_->field(0)); 980 EXPECT_EQ(c_, oneof_->field(1)); 981 EXPECT_TRUE(a_->containing_oneof() == NULL); 982 EXPECT_EQ(oneof_, b_->containing_oneof()); 983 EXPECT_EQ(oneof_, c_->containing_oneof()); 984 } 985 986 TEST_F(OneofDescriptorTest, FindByName) { 987 EXPECT_EQ(oneof_, oneof_message_->FindOneofByName("foo")); 988 EXPECT_EQ(oneof2_, oneof_message_->FindOneofByName("bar")); 989 EXPECT_TRUE(oneof_message_->FindOneofByName("no_such_oneof") == NULL); 990 } 991 992 // =================================================================== 993 994 class StylizedFieldNamesTest : public testing::Test { 995 protected: 996 void SetUp() { 997 FileDescriptorProto file; 998 file.set_name("foo.proto"); 999 1000 AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000); 1001 1002 DescriptorProto* message = AddMessage(&file, "TestMessage"); 1003 AddField(message, "foo_foo", 1, 1004 FieldDescriptorProto::LABEL_OPTIONAL, 1005 FieldDescriptorProto::TYPE_INT32); 1006 AddField(message, "FooBar", 2, 1007 FieldDescriptorProto::LABEL_OPTIONAL, 1008 FieldDescriptorProto::TYPE_INT32); 1009 AddField(message, "fooBaz", 3, 1010 FieldDescriptorProto::LABEL_OPTIONAL, 1011 FieldDescriptorProto::TYPE_INT32); 1012 AddField(message, "fooFoo", 4, // Camel-case conflict with foo_foo. 1013 FieldDescriptorProto::LABEL_OPTIONAL, 1014 FieldDescriptorProto::TYPE_INT32); 1015 AddField(message, "foobar", 5, // Lower-case conflict with FooBar. 1016 FieldDescriptorProto::LABEL_OPTIONAL, 1017 FieldDescriptorProto::TYPE_INT32); 1018 1019 AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1, 1020 FieldDescriptorProto::LABEL_OPTIONAL, 1021 FieldDescriptorProto::TYPE_INT32); 1022 AddNestedExtension(message, "ExtendableMessage", "BarBar", 2, 1023 FieldDescriptorProto::LABEL_OPTIONAL, 1024 FieldDescriptorProto::TYPE_INT32); 1025 AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3, 1026 FieldDescriptorProto::LABEL_OPTIONAL, 1027 FieldDescriptorProto::TYPE_INT32); 1028 AddNestedExtension(message, "ExtendableMessage", "barFoo", 4, // Conflict 1029 FieldDescriptorProto::LABEL_OPTIONAL, 1030 FieldDescriptorProto::TYPE_INT32); 1031 AddNestedExtension(message, "ExtendableMessage", "barbar", 5, // Conflict 1032 FieldDescriptorProto::LABEL_OPTIONAL, 1033 FieldDescriptorProto::TYPE_INT32); 1034 1035 AddExtension(&file, "ExtendableMessage", "baz_foo", 11, 1036 FieldDescriptorProto::LABEL_OPTIONAL, 1037 FieldDescriptorProto::TYPE_INT32); 1038 AddExtension(&file, "ExtendableMessage", "BazBar", 12, 1039 FieldDescriptorProto::LABEL_OPTIONAL, 1040 FieldDescriptorProto::TYPE_INT32); 1041 AddExtension(&file, "ExtendableMessage", "BazBaz", 13, 1042 FieldDescriptorProto::LABEL_OPTIONAL, 1043 FieldDescriptorProto::TYPE_INT32); 1044 AddExtension(&file, "ExtendableMessage", "bazFoo", 14, // Conflict 1045 FieldDescriptorProto::LABEL_OPTIONAL, 1046 FieldDescriptorProto::TYPE_INT32); 1047 AddExtension(&file, "ExtendableMessage", "bazbar", 15, // Conflict 1048 FieldDescriptorProto::LABEL_OPTIONAL, 1049 FieldDescriptorProto::TYPE_INT32); 1050 1051 file_ = pool_.BuildFile(file); 1052 ASSERT_TRUE(file_ != NULL); 1053 ASSERT_EQ(2, file_->message_type_count()); 1054 message_ = file_->message_type(1); 1055 ASSERT_EQ("TestMessage", message_->name()); 1056 ASSERT_EQ(5, message_->field_count()); 1057 ASSERT_EQ(5, message_->extension_count()); 1058 ASSERT_EQ(5, file_->extension_count()); 1059 } 1060 1061 DescriptorPool pool_; 1062 const FileDescriptor* file_; 1063 const Descriptor* message_; 1064 }; 1065 1066 TEST_F(StylizedFieldNamesTest, LowercaseName) { 1067 EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name()); 1068 EXPECT_EQ("foobar" , message_->field(1)->lowercase_name()); 1069 EXPECT_EQ("foobaz" , message_->field(2)->lowercase_name()); 1070 EXPECT_EQ("foofoo" , message_->field(3)->lowercase_name()); 1071 EXPECT_EQ("foobar" , message_->field(4)->lowercase_name()); 1072 1073 EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name()); 1074 EXPECT_EQ("barbar" , message_->extension(1)->lowercase_name()); 1075 EXPECT_EQ("barbaz" , message_->extension(2)->lowercase_name()); 1076 EXPECT_EQ("barfoo" , message_->extension(3)->lowercase_name()); 1077 EXPECT_EQ("barbar" , message_->extension(4)->lowercase_name()); 1078 1079 EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name()); 1080 EXPECT_EQ("bazbar" , file_->extension(1)->lowercase_name()); 1081 EXPECT_EQ("bazbaz" , file_->extension(2)->lowercase_name()); 1082 EXPECT_EQ("bazfoo" , file_->extension(3)->lowercase_name()); 1083 EXPECT_EQ("bazbar" , file_->extension(4)->lowercase_name()); 1084 } 1085 1086 TEST_F(StylizedFieldNamesTest, CamelcaseName) { 1087 EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name()); 1088 EXPECT_EQ("fooBar", message_->field(1)->camelcase_name()); 1089 EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name()); 1090 EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name()); 1091 EXPECT_EQ("foobar", message_->field(4)->camelcase_name()); 1092 1093 EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name()); 1094 EXPECT_EQ("barBar", message_->extension(1)->camelcase_name()); 1095 EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name()); 1096 EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name()); 1097 EXPECT_EQ("barbar", message_->extension(4)->camelcase_name()); 1098 1099 EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name()); 1100 EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name()); 1101 EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name()); 1102 EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name()); 1103 EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name()); 1104 } 1105 1106 TEST_F(StylizedFieldNamesTest, FindByLowercaseName) { 1107 EXPECT_EQ(message_->field(0), 1108 message_->FindFieldByLowercaseName("foo_foo")); 1109 EXPECT_EQ(message_->field(1), 1110 message_->FindFieldByLowercaseName("foobar")); 1111 EXPECT_EQ(message_->field(2), 1112 message_->FindFieldByLowercaseName("foobaz")); 1113 EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == NULL); 1114 EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == NULL); 1115 EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == NULL); 1116 EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == NULL); 1117 1118 EXPECT_EQ(message_->extension(0), 1119 message_->FindExtensionByLowercaseName("bar_foo")); 1120 EXPECT_EQ(message_->extension(1), 1121 message_->FindExtensionByLowercaseName("barbar")); 1122 EXPECT_EQ(message_->extension(2), 1123 message_->FindExtensionByLowercaseName("barbaz")); 1124 EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == NULL); 1125 EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == NULL); 1126 EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == NULL); 1127 EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == NULL); 1128 1129 EXPECT_EQ(file_->extension(0), 1130 file_->FindExtensionByLowercaseName("baz_foo")); 1131 EXPECT_EQ(file_->extension(1), 1132 file_->FindExtensionByLowercaseName("bazbar")); 1133 EXPECT_EQ(file_->extension(2), 1134 file_->FindExtensionByLowercaseName("bazbaz")); 1135 EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == NULL); 1136 EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == NULL); 1137 EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == NULL); 1138 } 1139 1140 TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) { 1141 EXPECT_EQ(message_->field(0), 1142 message_->FindFieldByCamelcaseName("fooFoo")); 1143 EXPECT_EQ(message_->field(1), 1144 message_->FindFieldByCamelcaseName("fooBar")); 1145 EXPECT_EQ(message_->field(2), 1146 message_->FindFieldByCamelcaseName("fooBaz")); 1147 EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == NULL); 1148 EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == NULL); 1149 EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == NULL); 1150 EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == NULL); 1151 1152 EXPECT_EQ(message_->extension(0), 1153 message_->FindExtensionByCamelcaseName("barFoo")); 1154 EXPECT_EQ(message_->extension(1), 1155 message_->FindExtensionByCamelcaseName("barBar")); 1156 EXPECT_EQ(message_->extension(2), 1157 message_->FindExtensionByCamelcaseName("barBaz")); 1158 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == NULL); 1159 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == NULL); 1160 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == NULL); 1161 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == NULL); 1162 1163 EXPECT_EQ(file_->extension(0), 1164 file_->FindExtensionByCamelcaseName("bazFoo")); 1165 EXPECT_EQ(file_->extension(1), 1166 file_->FindExtensionByCamelcaseName("bazBar")); 1167 EXPECT_EQ(file_->extension(2), 1168 file_->FindExtensionByCamelcaseName("bazBaz")); 1169 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == NULL); 1170 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == NULL); 1171 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == NULL); 1172 } 1173 1174 // =================================================================== 1175 1176 // Test enum descriptors. 1177 class EnumDescriptorTest : public testing::Test { 1178 protected: 1179 virtual void SetUp() { 1180 // Build descriptors for the following definitions: 1181 // 1182 // // in "foo.proto" 1183 // enum TestEnum { 1184 // FOO = 1; 1185 // BAR = 2; 1186 // } 1187 // 1188 // // in "bar.proto" 1189 // package corge.grault; 1190 // enum TestEnum2 { 1191 // FOO = 1; 1192 // BAZ = 3; 1193 // } 1194 // 1195 // TestEnum2 is primarily here to test FindValueByName and friends. 1196 // All enums created from the same DescriptorPool share the same lookup 1197 // table, so we need to insure that they don't interfere. 1198 1199 // TestEnum 1200 FileDescriptorProto foo_file; 1201 foo_file.set_name("foo.proto"); 1202 1203 EnumDescriptorProto* enum_proto = AddEnum(&foo_file, "TestEnum"); 1204 AddEnumValue(enum_proto, "FOO", 1); 1205 AddEnumValue(enum_proto, "BAR", 2); 1206 1207 // TestEnum2 1208 FileDescriptorProto bar_file; 1209 bar_file.set_name("bar.proto"); 1210 bar_file.set_package("corge.grault"); 1211 1212 EnumDescriptorProto* enum2_proto = AddEnum(&bar_file, "TestEnum2"); 1213 AddEnumValue(enum2_proto, "FOO", 1); 1214 AddEnumValue(enum2_proto, "BAZ", 3); 1215 1216 // Build the descriptors and get the pointers. 1217 foo_file_ = pool_.BuildFile(foo_file); 1218 ASSERT_TRUE(foo_file_ != NULL); 1219 1220 bar_file_ = pool_.BuildFile(bar_file); 1221 ASSERT_TRUE(bar_file_ != NULL); 1222 1223 ASSERT_EQ(1, foo_file_->enum_type_count()); 1224 enum_ = foo_file_->enum_type(0); 1225 1226 ASSERT_EQ(2, enum_->value_count()); 1227 foo_ = enum_->value(0); 1228 bar_ = enum_->value(1); 1229 1230 ASSERT_EQ(1, bar_file_->enum_type_count()); 1231 enum2_ = bar_file_->enum_type(0); 1232 1233 ASSERT_EQ(2, enum2_->value_count()); 1234 foo2_ = enum2_->value(0); 1235 baz2_ = enum2_->value(1); 1236 } 1237 1238 DescriptorPool pool_; 1239 1240 const FileDescriptor* foo_file_; 1241 const FileDescriptor* bar_file_; 1242 1243 const EnumDescriptor* enum_; 1244 const EnumDescriptor* enum2_; 1245 1246 const EnumValueDescriptor* foo_; 1247 const EnumValueDescriptor* bar_; 1248 1249 const EnumValueDescriptor* foo2_; 1250 const EnumValueDescriptor* baz2_; 1251 }; 1252 1253 TEST_F(EnumDescriptorTest, Name) { 1254 EXPECT_EQ("TestEnum", enum_->name()); 1255 EXPECT_EQ("TestEnum", enum_->full_name()); 1256 EXPECT_EQ(foo_file_, enum_->file()); 1257 1258 EXPECT_EQ("TestEnum2", enum2_->name()); 1259 EXPECT_EQ("corge.grault.TestEnum2", enum2_->full_name()); 1260 EXPECT_EQ(bar_file_, enum2_->file()); 1261 } 1262 1263 TEST_F(EnumDescriptorTest, ContainingType) { 1264 EXPECT_TRUE(enum_->containing_type() == NULL); 1265 EXPECT_TRUE(enum2_->containing_type() == NULL); 1266 } 1267 1268 TEST_F(EnumDescriptorTest, ValuesByIndex) { 1269 ASSERT_EQ(2, enum_->value_count()); 1270 EXPECT_EQ(foo_, enum_->value(0)); 1271 EXPECT_EQ(bar_, enum_->value(1)); 1272 } 1273 1274 TEST_F(EnumDescriptorTest, FindValueByName) { 1275 EXPECT_EQ(foo_ , enum_ ->FindValueByName("FOO")); 1276 EXPECT_EQ(bar_ , enum_ ->FindValueByName("BAR")); 1277 EXPECT_EQ(foo2_, enum2_->FindValueByName("FOO")); 1278 EXPECT_EQ(baz2_, enum2_->FindValueByName("BAZ")); 1279 1280 EXPECT_TRUE(enum_ ->FindValueByName("NO_SUCH_VALUE") == NULL); 1281 EXPECT_TRUE(enum_ ->FindValueByName("BAZ" ) == NULL); 1282 EXPECT_TRUE(enum2_->FindValueByName("BAR" ) == NULL); 1283 } 1284 1285 TEST_F(EnumDescriptorTest, FindValueByNumber) { 1286 EXPECT_EQ(foo_ , enum_ ->FindValueByNumber(1)); 1287 EXPECT_EQ(bar_ , enum_ ->FindValueByNumber(2)); 1288 EXPECT_EQ(foo2_, enum2_->FindValueByNumber(1)); 1289 EXPECT_EQ(baz2_, enum2_->FindValueByNumber(3)); 1290 1291 EXPECT_TRUE(enum_ ->FindValueByNumber(416) == NULL); 1292 EXPECT_TRUE(enum_ ->FindValueByNumber(3) == NULL); 1293 EXPECT_TRUE(enum2_->FindValueByNumber(2) == NULL); 1294 } 1295 1296 TEST_F(EnumDescriptorTest, ValueName) { 1297 EXPECT_EQ("FOO", foo_->name()); 1298 EXPECT_EQ("BAR", bar_->name()); 1299 } 1300 1301 TEST_F(EnumDescriptorTest, ValueFullName) { 1302 EXPECT_EQ("FOO", foo_->full_name()); 1303 EXPECT_EQ("BAR", bar_->full_name()); 1304 EXPECT_EQ("corge.grault.FOO", foo2_->full_name()); 1305 EXPECT_EQ("corge.grault.BAZ", baz2_->full_name()); 1306 } 1307 1308 TEST_F(EnumDescriptorTest, ValueIndex) { 1309 EXPECT_EQ(0, foo_->index()); 1310 EXPECT_EQ(1, bar_->index()); 1311 } 1312 1313 TEST_F(EnumDescriptorTest, ValueNumber) { 1314 EXPECT_EQ(1, foo_->number()); 1315 EXPECT_EQ(2, bar_->number()); 1316 } 1317 1318 TEST_F(EnumDescriptorTest, ValueType) { 1319 EXPECT_EQ(enum_ , foo_ ->type()); 1320 EXPECT_EQ(enum_ , bar_ ->type()); 1321 EXPECT_EQ(enum2_, foo2_->type()); 1322 EXPECT_EQ(enum2_, baz2_->type()); 1323 } 1324 1325 // =================================================================== 1326 1327 // Test service descriptors. 1328 class ServiceDescriptorTest : public testing::Test { 1329 protected: 1330 virtual void SetUp() { 1331 // Build descriptors for the following messages and service: 1332 // // in "foo.proto" 1333 // message FooRequest {} 1334 // message FooResponse {} 1335 // message BarRequest {} 1336 // message BarResponse {} 1337 // message BazRequest {} 1338 // message BazResponse {} 1339 // 1340 // service TestService { 1341 // rpc Foo(FooRequest) returns (FooResponse); 1342 // rpc Bar(BarRequest) returns (BarResponse); 1343 // } 1344 // 1345 // // in "bar.proto" 1346 // package corge.grault 1347 // service TestService2 { 1348 // rpc Foo(FooRequest) returns (FooResponse); 1349 // rpc Baz(BazRequest) returns (BazResponse); 1350 // } 1351 1352 FileDescriptorProto foo_file; 1353 foo_file.set_name("foo.proto"); 1354 1355 AddMessage(&foo_file, "FooRequest"); 1356 AddMessage(&foo_file, "FooResponse"); 1357 AddMessage(&foo_file, "BarRequest"); 1358 AddMessage(&foo_file, "BarResponse"); 1359 AddMessage(&foo_file, "BazRequest"); 1360 AddMessage(&foo_file, "BazResponse"); 1361 1362 ServiceDescriptorProto* service = AddService(&foo_file, "TestService"); 1363 AddMethod(service, "Foo", "FooRequest", "FooResponse"); 1364 AddMethod(service, "Bar", "BarRequest", "BarResponse"); 1365 1366 FileDescriptorProto bar_file; 1367 bar_file.set_name("bar.proto"); 1368 bar_file.set_package("corge.grault"); 1369 bar_file.add_dependency("foo.proto"); 1370 1371 ServiceDescriptorProto* service2 = AddService(&bar_file, "TestService2"); 1372 AddMethod(service2, "Foo", "FooRequest", "FooResponse"); 1373 AddMethod(service2, "Baz", "BazRequest", "BazResponse"); 1374 1375 // Build the descriptors and get the pointers. 1376 foo_file_ = pool_.BuildFile(foo_file); 1377 ASSERT_TRUE(foo_file_ != NULL); 1378 1379 bar_file_ = pool_.BuildFile(bar_file); 1380 ASSERT_TRUE(bar_file_ != NULL); 1381 1382 ASSERT_EQ(6, foo_file_->message_type_count()); 1383 foo_request_ = foo_file_->message_type(0); 1384 foo_response_ = foo_file_->message_type(1); 1385 bar_request_ = foo_file_->message_type(2); 1386 bar_response_ = foo_file_->message_type(3); 1387 baz_request_ = foo_file_->message_type(4); 1388 baz_response_ = foo_file_->message_type(5); 1389 1390 ASSERT_EQ(1, foo_file_->service_count()); 1391 service_ = foo_file_->service(0); 1392 1393 ASSERT_EQ(2, service_->method_count()); 1394 foo_ = service_->method(0); 1395 bar_ = service_->method(1); 1396 1397 ASSERT_EQ(1, bar_file_->service_count()); 1398 service2_ = bar_file_->service(0); 1399 1400 ASSERT_EQ(2, service2_->method_count()); 1401 foo2_ = service2_->method(0); 1402 baz2_ = service2_->method(1); 1403 } 1404 1405 DescriptorPool pool_; 1406 1407 const FileDescriptor* foo_file_; 1408 const FileDescriptor* bar_file_; 1409 1410 const Descriptor* foo_request_; 1411 const Descriptor* foo_response_; 1412 const Descriptor* bar_request_; 1413 const Descriptor* bar_response_; 1414 const Descriptor* baz_request_; 1415 const Descriptor* baz_response_; 1416 1417 const ServiceDescriptor* service_; 1418 const ServiceDescriptor* service2_; 1419 1420 const MethodDescriptor* foo_; 1421 const MethodDescriptor* bar_; 1422 1423 const MethodDescriptor* foo2_; 1424 const MethodDescriptor* baz2_; 1425 }; 1426 1427 TEST_F(ServiceDescriptorTest, Name) { 1428 EXPECT_EQ("TestService", service_->name()); 1429 EXPECT_EQ("TestService", service_->full_name()); 1430 EXPECT_EQ(foo_file_, service_->file()); 1431 1432 EXPECT_EQ("TestService2", service2_->name()); 1433 EXPECT_EQ("corge.grault.TestService2", service2_->full_name()); 1434 EXPECT_EQ(bar_file_, service2_->file()); 1435 } 1436 1437 TEST_F(ServiceDescriptorTest, MethodsByIndex) { 1438 ASSERT_EQ(2, service_->method_count()); 1439 EXPECT_EQ(foo_, service_->method(0)); 1440 EXPECT_EQ(bar_, service_->method(1)); 1441 } 1442 1443 TEST_F(ServiceDescriptorTest, FindMethodByName) { 1444 EXPECT_EQ(foo_ , service_ ->FindMethodByName("Foo")); 1445 EXPECT_EQ(bar_ , service_ ->FindMethodByName("Bar")); 1446 EXPECT_EQ(foo2_, service2_->FindMethodByName("Foo")); 1447 EXPECT_EQ(baz2_, service2_->FindMethodByName("Baz")); 1448 1449 EXPECT_TRUE(service_ ->FindMethodByName("NoSuchMethod") == NULL); 1450 EXPECT_TRUE(service_ ->FindMethodByName("Baz" ) == NULL); 1451 EXPECT_TRUE(service2_->FindMethodByName("Bar" ) == NULL); 1452 } 1453 1454 TEST_F(ServiceDescriptorTest, MethodName) { 1455 EXPECT_EQ("Foo", foo_->name()); 1456 EXPECT_EQ("Bar", bar_->name()); 1457 } 1458 1459 TEST_F(ServiceDescriptorTest, MethodFullName) { 1460 EXPECT_EQ("TestService.Foo", foo_->full_name()); 1461 EXPECT_EQ("TestService.Bar", bar_->full_name()); 1462 EXPECT_EQ("corge.grault.TestService2.Foo", foo2_->full_name()); 1463 EXPECT_EQ("corge.grault.TestService2.Baz", baz2_->full_name()); 1464 } 1465 1466 TEST_F(ServiceDescriptorTest, MethodIndex) { 1467 EXPECT_EQ(0, foo_->index()); 1468 EXPECT_EQ(1, bar_->index()); 1469 } 1470 1471 TEST_F(ServiceDescriptorTest, MethodParent) { 1472 EXPECT_EQ(service_, foo_->service()); 1473 EXPECT_EQ(service_, bar_->service()); 1474 } 1475 1476 TEST_F(ServiceDescriptorTest, MethodInputType) { 1477 EXPECT_EQ(foo_request_, foo_->input_type()); 1478 EXPECT_EQ(bar_request_, bar_->input_type()); 1479 } 1480 1481 TEST_F(ServiceDescriptorTest, MethodOutputType) { 1482 EXPECT_EQ(foo_response_, foo_->output_type()); 1483 EXPECT_EQ(bar_response_, bar_->output_type()); 1484 } 1485 1486 // =================================================================== 1487 1488 // Test nested types. 1489 class NestedDescriptorTest : public testing::Test { 1490 protected: 1491 virtual void SetUp() { 1492 // Build descriptors for the following definitions: 1493 // 1494 // // in "foo.proto" 1495 // message TestMessage { 1496 // message Foo {} 1497 // message Bar {} 1498 // enum Baz { A = 1; } 1499 // enum Qux { B = 1; } 1500 // } 1501 // 1502 // // in "bar.proto" 1503 // package corge.grault; 1504 // message TestMessage2 { 1505 // message Foo {} 1506 // message Baz {} 1507 // enum Qux { A = 1; } 1508 // enum Quux { C = 1; } 1509 // } 1510 // 1511 // TestMessage2 is primarily here to test FindNestedTypeByName and friends. 1512 // All messages created from the same DescriptorPool share the same lookup 1513 // table, so we need to insure that they don't interfere. 1514 // 1515 // We add enum values to the enums in order to test searching for enum 1516 // values across a message's scope. 1517 1518 FileDescriptorProto foo_file; 1519 foo_file.set_name("foo.proto"); 1520 1521 DescriptorProto* message = AddMessage(&foo_file, "TestMessage"); 1522 AddNestedMessage(message, "Foo"); 1523 AddNestedMessage(message, "Bar"); 1524 EnumDescriptorProto* baz = AddNestedEnum(message, "Baz"); 1525 AddEnumValue(baz, "A", 1); 1526 EnumDescriptorProto* qux = AddNestedEnum(message, "Qux"); 1527 AddEnumValue(qux, "B", 1); 1528 1529 FileDescriptorProto bar_file; 1530 bar_file.set_name("bar.proto"); 1531 bar_file.set_package("corge.grault"); 1532 1533 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2"); 1534 AddNestedMessage(message2, "Foo"); 1535 AddNestedMessage(message2, "Baz"); 1536 EnumDescriptorProto* qux2 = AddNestedEnum(message2, "Qux"); 1537 AddEnumValue(qux2, "A", 1); 1538 EnumDescriptorProto* quux2 = AddNestedEnum(message2, "Quux"); 1539 AddEnumValue(quux2, "C", 1); 1540 1541 // Build the descriptors and get the pointers. 1542 foo_file_ = pool_.BuildFile(foo_file); 1543 ASSERT_TRUE(foo_file_ != NULL); 1544 1545 bar_file_ = pool_.BuildFile(bar_file); 1546 ASSERT_TRUE(bar_file_ != NULL); 1547 1548 ASSERT_EQ(1, foo_file_->message_type_count()); 1549 message_ = foo_file_->message_type(0); 1550 1551 ASSERT_EQ(2, message_->nested_type_count()); 1552 foo_ = message_->nested_type(0); 1553 bar_ = message_->nested_type(1); 1554 1555 ASSERT_EQ(2, message_->enum_type_count()); 1556 baz_ = message_->enum_type(0); 1557 qux_ = message_->enum_type(1); 1558 1559 ASSERT_EQ(1, baz_->value_count()); 1560 a_ = baz_->value(0); 1561 ASSERT_EQ(1, qux_->value_count()); 1562 b_ = qux_->value(0); 1563 1564 ASSERT_EQ(1, bar_file_->message_type_count()); 1565 message2_ = bar_file_->message_type(0); 1566 1567 ASSERT_EQ(2, message2_->nested_type_count()); 1568 foo2_ = message2_->nested_type(0); 1569 baz2_ = message2_->nested_type(1); 1570 1571 ASSERT_EQ(2, message2_->enum_type_count()); 1572 qux2_ = message2_->enum_type(0); 1573 quux2_ = message2_->enum_type(1); 1574 1575 ASSERT_EQ(1, qux2_->value_count()); 1576 a2_ = qux2_->value(0); 1577 ASSERT_EQ(1, quux2_->value_count()); 1578 c2_ = quux2_->value(0); 1579 } 1580 1581 DescriptorPool pool_; 1582 1583 const FileDescriptor* foo_file_; 1584 const FileDescriptor* bar_file_; 1585 1586 const Descriptor* message_; 1587 const Descriptor* message2_; 1588 1589 const Descriptor* foo_; 1590 const Descriptor* bar_; 1591 const EnumDescriptor* baz_; 1592 const EnumDescriptor* qux_; 1593 const EnumValueDescriptor* a_; 1594 const EnumValueDescriptor* b_; 1595 1596 const Descriptor* foo2_; 1597 const Descriptor* baz2_; 1598 const EnumDescriptor* qux2_; 1599 const EnumDescriptor* quux2_; 1600 const EnumValueDescriptor* a2_; 1601 const EnumValueDescriptor* c2_; 1602 }; 1603 1604 TEST_F(NestedDescriptorTest, MessageName) { 1605 EXPECT_EQ("Foo", foo_ ->name()); 1606 EXPECT_EQ("Bar", bar_ ->name()); 1607 EXPECT_EQ("Foo", foo2_->name()); 1608 EXPECT_EQ("Baz", baz2_->name()); 1609 1610 EXPECT_EQ("TestMessage.Foo", foo_->full_name()); 1611 EXPECT_EQ("TestMessage.Bar", bar_->full_name()); 1612 EXPECT_EQ("corge.grault.TestMessage2.Foo", foo2_->full_name()); 1613 EXPECT_EQ("corge.grault.TestMessage2.Baz", baz2_->full_name()); 1614 } 1615 1616 TEST_F(NestedDescriptorTest, MessageContainingType) { 1617 EXPECT_EQ(message_ , foo_ ->containing_type()); 1618 EXPECT_EQ(message_ , bar_ ->containing_type()); 1619 EXPECT_EQ(message2_, foo2_->containing_type()); 1620 EXPECT_EQ(message2_, baz2_->containing_type()); 1621 } 1622 1623 TEST_F(NestedDescriptorTest, NestedMessagesByIndex) { 1624 ASSERT_EQ(2, message_->nested_type_count()); 1625 EXPECT_EQ(foo_, message_->nested_type(0)); 1626 EXPECT_EQ(bar_, message_->nested_type(1)); 1627 } 1628 1629 TEST_F(NestedDescriptorTest, FindFieldByNameDoesntFindNestedTypes) { 1630 EXPECT_TRUE(message_->FindFieldByName("Foo") == NULL); 1631 EXPECT_TRUE(message_->FindFieldByName("Qux") == NULL); 1632 EXPECT_TRUE(message_->FindExtensionByName("Foo") == NULL); 1633 EXPECT_TRUE(message_->FindExtensionByName("Qux") == NULL); 1634 } 1635 1636 TEST_F(NestedDescriptorTest, FindNestedTypeByName) { 1637 EXPECT_EQ(foo_ , message_ ->FindNestedTypeByName("Foo")); 1638 EXPECT_EQ(bar_ , message_ ->FindNestedTypeByName("Bar")); 1639 EXPECT_EQ(foo2_, message2_->FindNestedTypeByName("Foo")); 1640 EXPECT_EQ(baz2_, message2_->FindNestedTypeByName("Baz")); 1641 1642 EXPECT_TRUE(message_ ->FindNestedTypeByName("NoSuchType") == NULL); 1643 EXPECT_TRUE(message_ ->FindNestedTypeByName("Baz" ) == NULL); 1644 EXPECT_TRUE(message2_->FindNestedTypeByName("Bar" ) == NULL); 1645 1646 EXPECT_TRUE(message_->FindNestedTypeByName("Qux") == NULL); 1647 } 1648 1649 TEST_F(NestedDescriptorTest, EnumName) { 1650 EXPECT_EQ("Baz" , baz_ ->name()); 1651 EXPECT_EQ("Qux" , qux_ ->name()); 1652 EXPECT_EQ("Qux" , qux2_->name()); 1653 EXPECT_EQ("Quux", quux2_->name()); 1654 1655 EXPECT_EQ("TestMessage.Baz", baz_->full_name()); 1656 EXPECT_EQ("TestMessage.Qux", qux_->full_name()); 1657 EXPECT_EQ("corge.grault.TestMessage2.Qux" , qux2_ ->full_name()); 1658 EXPECT_EQ("corge.grault.TestMessage2.Quux", quux2_->full_name()); 1659 } 1660 1661 TEST_F(NestedDescriptorTest, EnumContainingType) { 1662 EXPECT_EQ(message_ , baz_ ->containing_type()); 1663 EXPECT_EQ(message_ , qux_ ->containing_type()); 1664 EXPECT_EQ(message2_, qux2_ ->containing_type()); 1665 EXPECT_EQ(message2_, quux2_->containing_type()); 1666 } 1667 1668 TEST_F(NestedDescriptorTest, NestedEnumsByIndex) { 1669 ASSERT_EQ(2, message_->nested_type_count()); 1670 EXPECT_EQ(foo_, message_->nested_type(0)); 1671 EXPECT_EQ(bar_, message_->nested_type(1)); 1672 } 1673 1674 TEST_F(NestedDescriptorTest, FindEnumTypeByName) { 1675 EXPECT_EQ(baz_ , message_ ->FindEnumTypeByName("Baz" )); 1676 EXPECT_EQ(qux_ , message_ ->FindEnumTypeByName("Qux" )); 1677 EXPECT_EQ(qux2_ , message2_->FindEnumTypeByName("Qux" )); 1678 EXPECT_EQ(quux2_, message2_->FindEnumTypeByName("Quux")); 1679 1680 EXPECT_TRUE(message_ ->FindEnumTypeByName("NoSuchType") == NULL); 1681 EXPECT_TRUE(message_ ->FindEnumTypeByName("Quux" ) == NULL); 1682 EXPECT_TRUE(message2_->FindEnumTypeByName("Baz" ) == NULL); 1683 1684 EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == NULL); 1685 } 1686 1687 TEST_F(NestedDescriptorTest, FindEnumValueByName) { 1688 EXPECT_EQ(a_ , message_ ->FindEnumValueByName("A")); 1689 EXPECT_EQ(b_ , message_ ->FindEnumValueByName("B")); 1690 EXPECT_EQ(a2_, message2_->FindEnumValueByName("A")); 1691 EXPECT_EQ(c2_, message2_->FindEnumValueByName("C")); 1692 1693 EXPECT_TRUE(message_ ->FindEnumValueByName("NO_SUCH_VALUE") == NULL); 1694 EXPECT_TRUE(message_ ->FindEnumValueByName("C" ) == NULL); 1695 EXPECT_TRUE(message2_->FindEnumValueByName("B" ) == NULL); 1696 1697 EXPECT_TRUE(message_->FindEnumValueByName("Foo") == NULL); 1698 } 1699 1700 // =================================================================== 1701 1702 // Test extensions. 1703 class ExtensionDescriptorTest : public testing::Test { 1704 protected: 1705 virtual void SetUp() { 1706 // Build descriptors for the following definitions: 1707 // 1708 // enum Baz {} 1709 // message Qux {} 1710 // 1711 // message Foo { 1712 // extensions 10 to 19; 1713 // extensions 30 to 39; 1714 // } 1715 // extends Foo with optional int32 foo_int32 = 10; 1716 // extends Foo with repeated TestEnum foo_enum = 19; 1717 // message Bar { 1718 // extends Foo with optional Qux foo_message = 30; 1719 // // (using Qux as the group type) 1720 // extends Foo with repeated group foo_group = 39; 1721 // } 1722 1723 FileDescriptorProto foo_file; 1724 foo_file.set_name("foo.proto"); 1725 1726 AddEmptyEnum(&foo_file, "Baz"); 1727 AddMessage(&foo_file, "Qux"); 1728 1729 DescriptorProto* foo = AddMessage(&foo_file, "Foo"); 1730 AddExtensionRange(foo, 10, 20); 1731 AddExtensionRange(foo, 30, 40); 1732 1733 AddExtension(&foo_file, "Foo", "foo_int32", 10, 1734 FieldDescriptorProto::LABEL_OPTIONAL, 1735 FieldDescriptorProto::TYPE_INT32); 1736 AddExtension(&foo_file, "Foo", "foo_enum", 19, 1737 FieldDescriptorProto::LABEL_REPEATED, 1738 FieldDescriptorProto::TYPE_ENUM) 1739 ->set_type_name("Baz"); 1740 1741 DescriptorProto* bar = AddMessage(&foo_file, "Bar"); 1742 AddNestedExtension(bar, "Foo", "foo_message", 30, 1743 FieldDescriptorProto::LABEL_OPTIONAL, 1744 FieldDescriptorProto::TYPE_MESSAGE) 1745 ->set_type_name("Qux"); 1746 AddNestedExtension(bar, "Foo", "foo_group", 39, 1747 FieldDescriptorProto::LABEL_REPEATED, 1748 FieldDescriptorProto::TYPE_GROUP) 1749 ->set_type_name("Qux"); 1750 1751 // Build the descriptors and get the pointers. 1752 foo_file_ = pool_.BuildFile(foo_file); 1753 ASSERT_TRUE(foo_file_ != NULL); 1754 1755 ASSERT_EQ(1, foo_file_->enum_type_count()); 1756 baz_ = foo_file_->enum_type(0); 1757 1758 ASSERT_EQ(3, foo_file_->message_type_count()); 1759 qux_ = foo_file_->message_type(0); 1760 foo_ = foo_file_->message_type(1); 1761 bar_ = foo_file_->message_type(2); 1762 } 1763 1764 DescriptorPool pool_; 1765 1766 const FileDescriptor* foo_file_; 1767 1768 const Descriptor* foo_; 1769 const Descriptor* bar_; 1770 const EnumDescriptor* baz_; 1771 const Descriptor* qux_; 1772 }; 1773 1774 TEST_F(ExtensionDescriptorTest, ExtensionRanges) { 1775 EXPECT_EQ(0, bar_->extension_range_count()); 1776 ASSERT_EQ(2, foo_->extension_range_count()); 1777 1778 EXPECT_EQ(10, foo_->extension_range(0)->start); 1779 EXPECT_EQ(30, foo_->extension_range(1)->start); 1780 1781 EXPECT_EQ(20, foo_->extension_range(0)->end); 1782 EXPECT_EQ(40, foo_->extension_range(1)->end); 1783 }; 1784 1785 TEST_F(ExtensionDescriptorTest, Extensions) { 1786 EXPECT_EQ(0, foo_->extension_count()); 1787 ASSERT_EQ(2, foo_file_->extension_count()); 1788 ASSERT_EQ(2, bar_->extension_count()); 1789 1790 EXPECT_TRUE(foo_file_->extension(0)->is_extension()); 1791 EXPECT_TRUE(foo_file_->extension(1)->is_extension()); 1792 EXPECT_TRUE(bar_->extension(0)->is_extension()); 1793 EXPECT_TRUE(bar_->extension(1)->is_extension()); 1794 1795 EXPECT_EQ("foo_int32" , foo_file_->extension(0)->name()); 1796 EXPECT_EQ("foo_enum" , foo_file_->extension(1)->name()); 1797 EXPECT_EQ("foo_message", bar_->extension(0)->name()); 1798 EXPECT_EQ("foo_group" , bar_->extension(1)->name()); 1799 1800 EXPECT_EQ(10, foo_file_->extension(0)->number()); 1801 EXPECT_EQ(19, foo_file_->extension(1)->number()); 1802 EXPECT_EQ(30, bar_->extension(0)->number()); 1803 EXPECT_EQ(39, bar_->extension(1)->number()); 1804 1805 EXPECT_EQ(FieldDescriptor::TYPE_INT32 , foo_file_->extension(0)->type()); 1806 EXPECT_EQ(FieldDescriptor::TYPE_ENUM , foo_file_->extension(1)->type()); 1807 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_->extension(0)->type()); 1808 EXPECT_EQ(FieldDescriptor::TYPE_GROUP , bar_->extension(1)->type()); 1809 1810 EXPECT_EQ(baz_, foo_file_->extension(1)->enum_type()); 1811 EXPECT_EQ(qux_, bar_->extension(0)->message_type()); 1812 EXPECT_EQ(qux_, bar_->extension(1)->message_type()); 1813 1814 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, foo_file_->extension(0)->label()); 1815 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, foo_file_->extension(1)->label()); 1816 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->extension(0)->label()); 1817 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, bar_->extension(1)->label()); 1818 1819 EXPECT_EQ(foo_, foo_file_->extension(0)->containing_type()); 1820 EXPECT_EQ(foo_, foo_file_->extension(1)->containing_type()); 1821 EXPECT_EQ(foo_, bar_->extension(0)->containing_type()); 1822 EXPECT_EQ(foo_, bar_->extension(1)->containing_type()); 1823 1824 EXPECT_TRUE(foo_file_->extension(0)->extension_scope() == NULL); 1825 EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == NULL); 1826 EXPECT_EQ(bar_, bar_->extension(0)->extension_scope()); 1827 EXPECT_EQ(bar_, bar_->extension(1)->extension_scope()); 1828 }; 1829 1830 TEST_F(ExtensionDescriptorTest, IsExtensionNumber) { 1831 EXPECT_FALSE(foo_->IsExtensionNumber( 9)); 1832 EXPECT_TRUE (foo_->IsExtensionNumber(10)); 1833 EXPECT_TRUE (foo_->IsExtensionNumber(19)); 1834 EXPECT_FALSE(foo_->IsExtensionNumber(20)); 1835 EXPECT_FALSE(foo_->IsExtensionNumber(29)); 1836 EXPECT_TRUE (foo_->IsExtensionNumber(30)); 1837 EXPECT_TRUE (foo_->IsExtensionNumber(39)); 1838 EXPECT_FALSE(foo_->IsExtensionNumber(40)); 1839 } 1840 1841 TEST_F(ExtensionDescriptorTest, FindExtensionByName) { 1842 // Note that FileDescriptor::FindExtensionByName() is tested by 1843 // FileDescriptorTest. 1844 ASSERT_EQ(2, bar_->extension_count()); 1845 1846 EXPECT_EQ(bar_->extension(0), bar_->FindExtensionByName("foo_message")); 1847 EXPECT_EQ(bar_->extension(1), bar_->FindExtensionByName("foo_group" )); 1848 1849 EXPECT_TRUE(bar_->FindExtensionByName("no_such_extension") == NULL); 1850 EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == NULL); 1851 EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == NULL); 1852 } 1853 1854 TEST_F(ExtensionDescriptorTest, FindAllExtensions) { 1855 vector<const FieldDescriptor*> extensions; 1856 pool_.FindAllExtensions(foo_, &extensions); 1857 ASSERT_EQ(4, extensions.size()); 1858 EXPECT_EQ(10, extensions[0]->number()); 1859 EXPECT_EQ(19, extensions[1]->number()); 1860 EXPECT_EQ(30, extensions[2]->number()); 1861 EXPECT_EQ(39, extensions[3]->number()); 1862 } 1863 1864 TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) { 1865 DescriptorPool pool; 1866 FileDescriptorProto file_proto; 1867 // Add "google/protobuf/descriptor.proto". 1868 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 1869 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 1870 // Add "foo.proto": 1871 // import "google/protobuf/descriptor.proto"; 1872 // extend google.protobuf.FieldOptions { 1873 // optional int32 option1 = 1000; 1874 // } 1875 file_proto.Clear(); 1876 file_proto.set_name("foo.proto"); 1877 file_proto.add_dependency("google/protobuf/descriptor.proto"); 1878 AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000, 1879 FieldDescriptorProto::LABEL_OPTIONAL, 1880 FieldDescriptorProto::TYPE_INT32); 1881 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 1882 // Add "bar.proto": 1883 // import "google/protobuf/descriptor.proto"; 1884 // extend google.protobuf.FieldOptions { 1885 // optional int32 option2 = 1000; 1886 // } 1887 file_proto.Clear(); 1888 file_proto.set_name("bar.proto"); 1889 file_proto.add_dependency("google/protobuf/descriptor.proto"); 1890 AddExtension(&file_proto, "google.protobuf.FieldOptions", "option2", 1000, 1891 FieldDescriptorProto::LABEL_OPTIONAL, 1892 FieldDescriptorProto::TYPE_INT32); 1893 // Currently we only generate a warning for conflicting extension numbers. 1894 // TODO(xiaofeng): Change it to an error. 1895 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 1896 } 1897 1898 // =================================================================== 1899 1900 // Test reserved fields. 1901 class ReservedDescriptorTest : public testing::Test { 1902 protected: 1903 virtual void SetUp() { 1904 // Build descriptors for the following definitions: 1905 // 1906 // message Foo { 1907 // reserved 2, 9 to 11, 15; 1908 // reserved "foo", "bar"; 1909 // } 1910 1911 FileDescriptorProto foo_file; 1912 foo_file.set_name("foo.proto"); 1913 1914 DescriptorProto* foo = AddMessage(&foo_file, "Foo"); 1915 AddReservedRange(foo, 2, 3); 1916 AddReservedRange(foo, 9, 12); 1917 AddReservedRange(foo, 15, 16); 1918 1919 foo->add_reserved_name("foo"); 1920 foo->add_reserved_name("bar"); 1921 1922 // Build the descriptors and get the pointers. 1923 foo_file_ = pool_.BuildFile(foo_file); 1924 ASSERT_TRUE(foo_file_ != NULL); 1925 1926 ASSERT_EQ(1, foo_file_->message_type_count()); 1927 foo_ = foo_file_->message_type(0); 1928 } 1929 1930 DescriptorPool pool_; 1931 const FileDescriptor* foo_file_; 1932 const Descriptor* foo_; 1933 }; 1934 1935 TEST_F(ReservedDescriptorTest, ReservedRanges) { 1936 ASSERT_EQ(3, foo_->reserved_range_count()); 1937 1938 EXPECT_EQ(2, foo_->reserved_range(0)->start); 1939 EXPECT_EQ(3, foo_->reserved_range(0)->end); 1940 1941 EXPECT_EQ(9, foo_->reserved_range(1)->start); 1942 EXPECT_EQ(12, foo_->reserved_range(1)->end); 1943 1944 EXPECT_EQ(15, foo_->reserved_range(2)->start); 1945 EXPECT_EQ(16, foo_->reserved_range(2)->end); 1946 }; 1947 1948 TEST_F(ReservedDescriptorTest, IsReservedNumber) { 1949 EXPECT_FALSE(foo_->IsReservedNumber(1)); 1950 EXPECT_TRUE (foo_->IsReservedNumber(2)); 1951 EXPECT_FALSE(foo_->IsReservedNumber(3)); 1952 EXPECT_FALSE(foo_->IsReservedNumber(8)); 1953 EXPECT_TRUE (foo_->IsReservedNumber(9)); 1954 EXPECT_TRUE (foo_->IsReservedNumber(10)); 1955 EXPECT_TRUE (foo_->IsReservedNumber(11)); 1956 EXPECT_FALSE(foo_->IsReservedNumber(12)); 1957 EXPECT_FALSE(foo_->IsReservedNumber(13)); 1958 EXPECT_FALSE(foo_->IsReservedNumber(14)); 1959 EXPECT_TRUE (foo_->IsReservedNumber(15)); 1960 EXPECT_FALSE(foo_->IsReservedNumber(16)); 1961 }; 1962 1963 TEST_F(ReservedDescriptorTest, ReservedNames) { 1964 ASSERT_EQ(2, foo_->reserved_name_count()); 1965 1966 EXPECT_EQ("foo", foo_->reserved_name(0)); 1967 EXPECT_EQ("bar", foo_->reserved_name(1)); 1968 }; 1969 1970 TEST_F(ReservedDescriptorTest, IsReservedName) { 1971 EXPECT_TRUE (foo_->IsReservedName("foo")); 1972 EXPECT_TRUE (foo_->IsReservedName("bar")); 1973 EXPECT_FALSE(foo_->IsReservedName("baz")); 1974 }; 1975 1976 // =================================================================== 1977 1978 class MiscTest : public testing::Test { 1979 protected: 1980 // Function which makes a field descriptor of the given type. 1981 const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) { 1982 FileDescriptorProto file_proto; 1983 file_proto.set_name("foo.proto"); 1984 AddEmptyEnum(&file_proto, "DummyEnum"); 1985 1986 DescriptorProto* message = AddMessage(&file_proto, "TestMessage"); 1987 FieldDescriptorProto* field = 1988 AddField(message, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL, 1989 static_cast<FieldDescriptorProto::Type>(static_cast<int>(type))); 1990 1991 if (type == FieldDescriptor::TYPE_MESSAGE || 1992 type == FieldDescriptor::TYPE_GROUP) { 1993 field->set_type_name("TestMessage"); 1994 } else if (type == FieldDescriptor::TYPE_ENUM) { 1995 field->set_type_name("DummyEnum"); 1996 } 1997 1998 // Build the descriptors and get the pointers. 1999 pool_.reset(new DescriptorPool()); 2000 const FileDescriptor* file = pool_->BuildFile(file_proto); 2001 2002 if (file != NULL && 2003 file->message_type_count() == 1 && 2004 file->message_type(0)->field_count() == 1) { 2005 return file->message_type(0)->field(0); 2006 } else { 2007 return NULL; 2008 } 2009 } 2010 2011 const char* GetTypeNameForFieldType(FieldDescriptor::Type type) { 2012 const FieldDescriptor* field = GetFieldDescriptorOfType(type); 2013 return field != NULL ? field->type_name() : ""; 2014 } 2015 2016 FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) { 2017 const FieldDescriptor* field = GetFieldDescriptorOfType(type); 2018 return field != NULL ? field->cpp_type() : 2019 static_cast<FieldDescriptor::CppType>(0); 2020 } 2021 2022 const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) { 2023 const FieldDescriptor* field = GetFieldDescriptorOfType(type); 2024 return field != NULL ? field->cpp_type_name() : ""; 2025 } 2026 2027 const Descriptor* GetMessageDescriptorForFieldType( 2028 FieldDescriptor::Type type) { 2029 const FieldDescriptor* field = GetFieldDescriptorOfType(type); 2030 return field != NULL ? field->message_type() : NULL; 2031 } 2032 2033 const EnumDescriptor* GetEnumDescriptorForFieldType( 2034 FieldDescriptor::Type type) { 2035 const FieldDescriptor* field = GetFieldDescriptorOfType(type); 2036 return field != NULL ? field->enum_type() : NULL; 2037 } 2038 2039 google::protobuf::scoped_ptr<DescriptorPool> pool_; 2040 }; 2041 2042 TEST_F(MiscTest, TypeNames) { 2043 // Test that correct type names are returned. 2044 2045 typedef FieldDescriptor FD; // avoid ugly line wrapping 2046 2047 EXPECT_STREQ("double" , GetTypeNameForFieldType(FD::TYPE_DOUBLE )); 2048 EXPECT_STREQ("float" , GetTypeNameForFieldType(FD::TYPE_FLOAT )); 2049 EXPECT_STREQ("int64" , GetTypeNameForFieldType(FD::TYPE_INT64 )); 2050 EXPECT_STREQ("uint64" , GetTypeNameForFieldType(FD::TYPE_UINT64 )); 2051 EXPECT_STREQ("int32" , GetTypeNameForFieldType(FD::TYPE_INT32 )); 2052 EXPECT_STREQ("fixed64" , GetTypeNameForFieldType(FD::TYPE_FIXED64 )); 2053 EXPECT_STREQ("fixed32" , GetTypeNameForFieldType(FD::TYPE_FIXED32 )); 2054 EXPECT_STREQ("bool" , GetTypeNameForFieldType(FD::TYPE_BOOL )); 2055 EXPECT_STREQ("string" , GetTypeNameForFieldType(FD::TYPE_STRING )); 2056 EXPECT_STREQ("group" , GetTypeNameForFieldType(FD::TYPE_GROUP )); 2057 EXPECT_STREQ("message" , GetTypeNameForFieldType(FD::TYPE_MESSAGE )); 2058 EXPECT_STREQ("bytes" , GetTypeNameForFieldType(FD::TYPE_BYTES )); 2059 EXPECT_STREQ("uint32" , GetTypeNameForFieldType(FD::TYPE_UINT32 )); 2060 EXPECT_STREQ("enum" , GetTypeNameForFieldType(FD::TYPE_ENUM )); 2061 EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32)); 2062 EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64)); 2063 EXPECT_STREQ("sint32" , GetTypeNameForFieldType(FD::TYPE_SINT32 )); 2064 EXPECT_STREQ("sint64" , GetTypeNameForFieldType(FD::TYPE_SINT64 )); 2065 } 2066 2067 TEST_F(MiscTest, StaticTypeNames) { 2068 // Test that correct type names are returned. 2069 2070 typedef FieldDescriptor FD; // avoid ugly line wrapping 2071 2072 EXPECT_STREQ("double" , FD::TypeName(FD::TYPE_DOUBLE )); 2073 EXPECT_STREQ("float" , FD::TypeName(FD::TYPE_FLOAT )); 2074 EXPECT_STREQ("int64" , FD::TypeName(FD::TYPE_INT64 )); 2075 EXPECT_STREQ("uint64" , FD::TypeName(FD::TYPE_UINT64 )); 2076 EXPECT_STREQ("int32" , FD::TypeName(FD::TYPE_INT32 )); 2077 EXPECT_STREQ("fixed64" , FD::TypeName(FD::TYPE_FIXED64 )); 2078 EXPECT_STREQ("fixed32" , FD::TypeName(FD::TYPE_FIXED32 )); 2079 EXPECT_STREQ("bool" , FD::TypeName(FD::TYPE_BOOL )); 2080 EXPECT_STREQ("string" , FD::TypeName(FD::TYPE_STRING )); 2081 EXPECT_STREQ("group" , FD::TypeName(FD::TYPE_GROUP )); 2082 EXPECT_STREQ("message" , FD::TypeName(FD::TYPE_MESSAGE )); 2083 EXPECT_STREQ("bytes" , FD::TypeName(FD::TYPE_BYTES )); 2084 EXPECT_STREQ("uint32" , FD::TypeName(FD::TYPE_UINT32 )); 2085 EXPECT_STREQ("enum" , FD::TypeName(FD::TYPE_ENUM )); 2086 EXPECT_STREQ("sfixed32", FD::TypeName(FD::TYPE_SFIXED32)); 2087 EXPECT_STREQ("sfixed64", FD::TypeName(FD::TYPE_SFIXED64)); 2088 EXPECT_STREQ("sint32" , FD::TypeName(FD::TYPE_SINT32 )); 2089 EXPECT_STREQ("sint64" , FD::TypeName(FD::TYPE_SINT64 )); 2090 } 2091 2092 TEST_F(MiscTest, CppTypes) { 2093 // Test that CPP types are assigned correctly. 2094 2095 typedef FieldDescriptor FD; // avoid ugly line wrapping 2096 2097 EXPECT_EQ(FD::CPPTYPE_DOUBLE , GetCppTypeForFieldType(FD::TYPE_DOUBLE )); 2098 EXPECT_EQ(FD::CPPTYPE_FLOAT , GetCppTypeForFieldType(FD::TYPE_FLOAT )); 2099 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_INT64 )); 2100 EXPECT_EQ(FD::CPPTYPE_UINT64 , GetCppTypeForFieldType(FD::TYPE_UINT64 )); 2101 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_INT32 )); 2102 EXPECT_EQ(FD::CPPTYPE_UINT64 , GetCppTypeForFieldType(FD::TYPE_FIXED64 )); 2103 EXPECT_EQ(FD::CPPTYPE_UINT32 , GetCppTypeForFieldType(FD::TYPE_FIXED32 )); 2104 EXPECT_EQ(FD::CPPTYPE_BOOL , GetCppTypeForFieldType(FD::TYPE_BOOL )); 2105 EXPECT_EQ(FD::CPPTYPE_STRING , GetCppTypeForFieldType(FD::TYPE_STRING )); 2106 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_GROUP )); 2107 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_MESSAGE )); 2108 EXPECT_EQ(FD::CPPTYPE_STRING , GetCppTypeForFieldType(FD::TYPE_BYTES )); 2109 EXPECT_EQ(FD::CPPTYPE_UINT32 , GetCppTypeForFieldType(FD::TYPE_UINT32 )); 2110 EXPECT_EQ(FD::CPPTYPE_ENUM , GetCppTypeForFieldType(FD::TYPE_ENUM )); 2111 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_SFIXED32)); 2112 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SFIXED64)); 2113 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_SINT32 )); 2114 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SINT64 )); 2115 } 2116 2117 TEST_F(MiscTest, CppTypeNames) { 2118 // Test that correct CPP type names are returned. 2119 2120 typedef FieldDescriptor FD; // avoid ugly line wrapping 2121 2122 EXPECT_STREQ("double" , GetCppTypeNameForFieldType(FD::TYPE_DOUBLE )); 2123 EXPECT_STREQ("float" , GetCppTypeNameForFieldType(FD::TYPE_FLOAT )); 2124 EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_INT64 )); 2125 EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_UINT64 )); 2126 EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_INT32 )); 2127 EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_FIXED64 )); 2128 EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_FIXED32 )); 2129 EXPECT_STREQ("bool" , GetCppTypeNameForFieldType(FD::TYPE_BOOL )); 2130 EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_STRING )); 2131 EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP )); 2132 EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE )); 2133 EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_BYTES )); 2134 EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_UINT32 )); 2135 EXPECT_STREQ("enum" , GetCppTypeNameForFieldType(FD::TYPE_ENUM )); 2136 EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED32)); 2137 EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED64)); 2138 EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SINT32 )); 2139 EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SINT64 )); 2140 } 2141 2142 TEST_F(MiscTest, StaticCppTypeNames) { 2143 // Test that correct CPP type names are returned. 2144 2145 typedef FieldDescriptor FD; // avoid ugly line wrapping 2146 2147 EXPECT_STREQ("int32" , FD::CppTypeName(FD::CPPTYPE_INT32 )); 2148 EXPECT_STREQ("int64" , FD::CppTypeName(FD::CPPTYPE_INT64 )); 2149 EXPECT_STREQ("uint32" , FD::CppTypeName(FD::CPPTYPE_UINT32 )); 2150 EXPECT_STREQ("uint64" , FD::CppTypeName(FD::CPPTYPE_UINT64 )); 2151 EXPECT_STREQ("double" , FD::CppTypeName(FD::CPPTYPE_DOUBLE )); 2152 EXPECT_STREQ("float" , FD::CppTypeName(FD::CPPTYPE_FLOAT )); 2153 EXPECT_STREQ("bool" , FD::CppTypeName(FD::CPPTYPE_BOOL )); 2154 EXPECT_STREQ("enum" , FD::CppTypeName(FD::CPPTYPE_ENUM )); 2155 EXPECT_STREQ("string" , FD::CppTypeName(FD::CPPTYPE_STRING )); 2156 EXPECT_STREQ("message", FD::CppTypeName(FD::CPPTYPE_MESSAGE)); 2157 } 2158 2159 TEST_F(MiscTest, MessageType) { 2160 // Test that message_type() is NULL for non-aggregate fields 2161 2162 typedef FieldDescriptor FD; // avoid ugly line wrapping 2163 2164 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_DOUBLE )); 2165 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_FLOAT )); 2166 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_INT64 )); 2167 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_UINT64 )); 2168 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_INT32 )); 2169 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_FIXED64 )); 2170 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_FIXED32 )); 2171 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_BOOL )); 2172 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_STRING )); 2173 EXPECT_TRUE(NULL != GetMessageDescriptorForFieldType(FD::TYPE_GROUP )); 2174 EXPECT_TRUE(NULL != GetMessageDescriptorForFieldType(FD::TYPE_MESSAGE )); 2175 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_BYTES )); 2176 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_UINT32 )); 2177 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_ENUM )); 2178 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED32)); 2179 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED64)); 2180 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SINT32 )); 2181 EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SINT64 )); 2182 } 2183 2184 TEST_F(MiscTest, EnumType) { 2185 // Test that enum_type() is NULL for non-enum fields 2186 2187 typedef FieldDescriptor FD; // avoid ugly line wrapping 2188 2189 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_DOUBLE )); 2190 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_FLOAT )); 2191 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_INT64 )); 2192 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_UINT64 )); 2193 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_INT32 )); 2194 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_FIXED64 )); 2195 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_FIXED32 )); 2196 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_BOOL )); 2197 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_STRING )); 2198 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_GROUP )); 2199 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_MESSAGE )); 2200 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_BYTES )); 2201 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_UINT32 )); 2202 EXPECT_TRUE(NULL != GetEnumDescriptorForFieldType(FD::TYPE_ENUM )); 2203 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED32)); 2204 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED64)); 2205 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SINT32 )); 2206 EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SINT64 )); 2207 } 2208 2209 2210 TEST_F(MiscTest, DefaultValues) { 2211 // Test that setting default values works. 2212 FileDescriptorProto file_proto; 2213 file_proto.set_name("foo.proto"); 2214 2215 EnumDescriptorProto* enum_type_proto = AddEnum(&file_proto, "DummyEnum"); 2216 AddEnumValue(enum_type_proto, "A", 1); 2217 AddEnumValue(enum_type_proto, "B", 2); 2218 2219 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage"); 2220 2221 typedef FieldDescriptorProto FD; // avoid ugly line wrapping 2222 const FD::Label label = FD::LABEL_OPTIONAL; 2223 2224 // Create fields of every CPP type with default values. 2225 AddField(message_proto, "int32" , 1, label, FD::TYPE_INT32 ) 2226 ->set_default_value("-1"); 2227 AddField(message_proto, "int64" , 2, label, FD::TYPE_INT64 ) 2228 ->set_default_value("-1000000000000"); 2229 AddField(message_proto, "uint32", 3, label, FD::TYPE_UINT32) 2230 ->set_default_value("42"); 2231 AddField(message_proto, "uint64", 4, label, FD::TYPE_UINT64) 2232 ->set_default_value("2000000000000"); 2233 AddField(message_proto, "float" , 5, label, FD::TYPE_FLOAT ) 2234 ->set_default_value("4.5"); 2235 AddField(message_proto, "double", 6, label, FD::TYPE_DOUBLE) 2236 ->set_default_value("10e100"); 2237 AddField(message_proto, "bool" , 7, label, FD::TYPE_BOOL ) 2238 ->set_default_value("true"); 2239 AddField(message_proto, "string", 8, label, FD::TYPE_STRING) 2240 ->set_default_value("hello"); 2241 AddField(message_proto, "data" , 9, label, FD::TYPE_BYTES ) 2242 ->set_default_value("\\001\\002\\003"); 2243 2244 FieldDescriptorProto* enum_field = 2245 AddField(message_proto, "enum", 10, label, FD::TYPE_ENUM); 2246 enum_field->set_type_name("DummyEnum"); 2247 enum_field->set_default_value("B"); 2248 2249 // Strings are allowed to have empty defaults. (At one point, due to 2250 // a bug, empty defaults for strings were rejected. Oops.) 2251 AddField(message_proto, "empty_string", 11, label, FD::TYPE_STRING) 2252 ->set_default_value(""); 2253 2254 // Add a second set of fields with implicit defalut values. 2255 AddField(message_proto, "implicit_int32" , 21, label, FD::TYPE_INT32 ); 2256 AddField(message_proto, "implicit_int64" , 22, label, FD::TYPE_INT64 ); 2257 AddField(message_proto, "implicit_uint32", 23, label, FD::TYPE_UINT32); 2258 AddField(message_proto, "implicit_uint64", 24, label, FD::TYPE_UINT64); 2259 AddField(message_proto, "implicit_float" , 25, label, FD::TYPE_FLOAT ); 2260 AddField(message_proto, "implicit_double", 26, label, FD::TYPE_DOUBLE); 2261 AddField(message_proto, "implicit_bool" , 27, label, FD::TYPE_BOOL ); 2262 AddField(message_proto, "implicit_string", 28, label, FD::TYPE_STRING); 2263 AddField(message_proto, "implicit_data" , 29, label, FD::TYPE_BYTES ); 2264 AddField(message_proto, "implicit_enum" , 30, label, FD::TYPE_ENUM) 2265 ->set_type_name("DummyEnum"); 2266 2267 // Build it. 2268 DescriptorPool pool; 2269 const FileDescriptor* file = pool.BuildFile(file_proto); 2270 ASSERT_TRUE(file != NULL); 2271 2272 ASSERT_EQ(1, file->enum_type_count()); 2273 const EnumDescriptor* enum_type = file->enum_type(0); 2274 ASSERT_EQ(2, enum_type->value_count()); 2275 const EnumValueDescriptor* enum_value_a = enum_type->value(0); 2276 const EnumValueDescriptor* enum_value_b = enum_type->value(1); 2277 2278 ASSERT_EQ(1, file->message_type_count()); 2279 const Descriptor* message = file->message_type(0); 2280 2281 ASSERT_EQ(21, message->field_count()); 2282 2283 // Check the default values. 2284 ASSERT_TRUE(message->field(0)->has_default_value()); 2285 ASSERT_TRUE(message->field(1)->has_default_value()); 2286 ASSERT_TRUE(message->field(2)->has_default_value()); 2287 ASSERT_TRUE(message->field(3)->has_default_value()); 2288 ASSERT_TRUE(message->field(4)->has_default_value()); 2289 ASSERT_TRUE(message->field(5)->has_default_value()); 2290 ASSERT_TRUE(message->field(6)->has_default_value()); 2291 ASSERT_TRUE(message->field(7)->has_default_value()); 2292 ASSERT_TRUE(message->field(8)->has_default_value()); 2293 ASSERT_TRUE(message->field(9)->has_default_value()); 2294 ASSERT_TRUE(message->field(10)->has_default_value()); 2295 2296 EXPECT_EQ(-1 , message->field(0)->default_value_int32 ()); 2297 EXPECT_EQ(-GOOGLE_ULONGLONG(1000000000000), 2298 message->field(1)->default_value_int64 ()); 2299 EXPECT_EQ(42 , message->field(2)->default_value_uint32()); 2300 EXPECT_EQ(GOOGLE_ULONGLONG(2000000000000), 2301 message->field(3)->default_value_uint64()); 2302 EXPECT_EQ(4.5 , message->field(4)->default_value_float ()); 2303 EXPECT_EQ(10e100 , message->field(5)->default_value_double()); 2304 EXPECT_TRUE( message->field(6)->default_value_bool ()); 2305 EXPECT_EQ("hello" , message->field(7)->default_value_string()); 2306 EXPECT_EQ("\001\002\003" , message->field(8)->default_value_string()); 2307 EXPECT_EQ(enum_value_b , message->field(9)->default_value_enum ()); 2308 EXPECT_EQ("" , message->field(10)->default_value_string()); 2309 2310 ASSERT_FALSE(message->field(11)->has_default_value()); 2311 ASSERT_FALSE(message->field(12)->has_default_value()); 2312 ASSERT_FALSE(message->field(13)->has_default_value()); 2313 ASSERT_FALSE(message->field(14)->has_default_value()); 2314 ASSERT_FALSE(message->field(15)->has_default_value()); 2315 ASSERT_FALSE(message->field(16)->has_default_value()); 2316 ASSERT_FALSE(message->field(17)->has_default_value()); 2317 ASSERT_FALSE(message->field(18)->has_default_value()); 2318 ASSERT_FALSE(message->field(19)->has_default_value()); 2319 ASSERT_FALSE(message->field(20)->has_default_value()); 2320 2321 EXPECT_EQ(0 , message->field(11)->default_value_int32 ()); 2322 EXPECT_EQ(0 , message->field(12)->default_value_int64 ()); 2323 EXPECT_EQ(0 , message->field(13)->default_value_uint32()); 2324 EXPECT_EQ(0 , message->field(14)->default_value_uint64()); 2325 EXPECT_EQ(0.0f , message->field(15)->default_value_float ()); 2326 EXPECT_EQ(0.0 , message->field(16)->default_value_double()); 2327 EXPECT_FALSE( message->field(17)->default_value_bool ()); 2328 EXPECT_EQ("" , message->field(18)->default_value_string()); 2329 EXPECT_EQ("" , message->field(19)->default_value_string()); 2330 EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum()); 2331 } 2332 2333 TEST_F(MiscTest, FieldOptions) { 2334 // Try setting field options. 2335 2336 FileDescriptorProto file_proto; 2337 file_proto.set_name("foo.proto"); 2338 2339 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage"); 2340 AddField(message_proto, "foo", 1, 2341 FieldDescriptorProto::LABEL_OPTIONAL, 2342 FieldDescriptorProto::TYPE_INT32); 2343 FieldDescriptorProto* bar_proto = 2344 AddField(message_proto, "bar", 2, 2345 FieldDescriptorProto::LABEL_OPTIONAL, 2346 FieldDescriptorProto::TYPE_INT32); 2347 2348 FieldOptions* options = bar_proto->mutable_options(); 2349 options->set_ctype(FieldOptions::CORD); 2350 2351 // Build the descriptors and get the pointers. 2352 DescriptorPool pool; 2353 const FileDescriptor* file = pool.BuildFile(file_proto); 2354 ASSERT_TRUE(file != NULL); 2355 2356 ASSERT_EQ(1, file->message_type_count()); 2357 const Descriptor* message = file->message_type(0); 2358 2359 ASSERT_EQ(2, message->field_count()); 2360 const FieldDescriptor* foo = message->field(0); 2361 const FieldDescriptor* bar = message->field(1); 2362 2363 // "foo" had no options set, so it should return the default options. 2364 EXPECT_EQ(&FieldOptions::default_instance(), &foo->options()); 2365 2366 // "bar" had options set. 2367 EXPECT_NE(&FieldOptions::default_instance(), options); 2368 EXPECT_TRUE(bar->options().has_ctype()); 2369 EXPECT_EQ(FieldOptions::CORD, bar->options().ctype()); 2370 } 2371 2372 // =================================================================== 2373 enum DescriptorPoolMode { 2374 NO_DATABASE, 2375 FALLBACK_DATABASE 2376 }; 2377 2378 class AllowUnknownDependenciesTest 2379 : public testing::TestWithParam<DescriptorPoolMode> { 2380 protected: 2381 DescriptorPoolMode mode() { 2382 return GetParam(); 2383 } 2384 2385 virtual void SetUp() { 2386 FileDescriptorProto foo_proto, bar_proto; 2387 2388 switch (mode()) { 2389 case NO_DATABASE: 2390 pool_.reset(new DescriptorPool); 2391 break; 2392 case FALLBACK_DATABASE: 2393 pool_.reset(new DescriptorPool(&db_)); 2394 break; 2395 } 2396 2397 pool_->AllowUnknownDependencies(); 2398 2399 ASSERT_TRUE(TextFormat::ParseFromString( 2400 "name: 'foo.proto'" 2401 "dependency: 'bar.proto'" 2402 "dependency: 'baz.proto'" 2403 "message_type {" 2404 " name: 'Foo'" 2405 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }" 2406 " field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }" 2407 " field { name:'qux' number:3 label:LABEL_OPTIONAL" 2408 " type_name: '.corge.Qux'" 2409 " type: TYPE_ENUM" 2410 " options {" 2411 " uninterpreted_option {" 2412 " name {" 2413 " name_part: 'grault'" 2414 " is_extension: true" 2415 " }" 2416 " positive_int_value: 1234" 2417 " }" 2418 " }" 2419 " }" 2420 "}", 2421 &foo_proto)); 2422 ASSERT_TRUE(TextFormat::ParseFromString( 2423 "name: 'bar.proto'" 2424 "message_type { name: 'Bar' }", 2425 &bar_proto)); 2426 2427 // Collect pointers to stuff. 2428 bar_file_ = BuildFile(bar_proto); 2429 ASSERT_TRUE(bar_file_ != NULL); 2430 2431 ASSERT_EQ(1, bar_file_->message_type_count()); 2432 bar_type_ = bar_file_->message_type(0); 2433 2434 foo_file_ = BuildFile(foo_proto); 2435 ASSERT_TRUE(foo_file_ != NULL); 2436 2437 ASSERT_EQ(1, foo_file_->message_type_count()); 2438 foo_type_ = foo_file_->message_type(0); 2439 2440 ASSERT_EQ(3, foo_type_->field_count()); 2441 bar_field_ = foo_type_->field(0); 2442 baz_field_ = foo_type_->field(1); 2443 qux_field_ = foo_type_->field(2); 2444 } 2445 2446 const FileDescriptor* BuildFile(const FileDescriptorProto& proto) { 2447 switch (mode()) { 2448 case NO_DATABASE: 2449 return pool_->BuildFile(proto); 2450 break; 2451 case FALLBACK_DATABASE: { 2452 EXPECT_TRUE(db_.Add(proto)); 2453 return pool_->FindFileByName(proto.name()); 2454 } 2455 } 2456 GOOGLE_LOG(FATAL) << "Can't get here."; 2457 return NULL; 2458 } 2459 2460 const FileDescriptor* bar_file_; 2461 const Descriptor* bar_type_; 2462 const FileDescriptor* foo_file_; 2463 const Descriptor* foo_type_; 2464 const FieldDescriptor* bar_field_; 2465 const FieldDescriptor* baz_field_; 2466 const FieldDescriptor* qux_field_; 2467 2468 SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode. 2469 google::protobuf::scoped_ptr<DescriptorPool> pool_; 2470 }; 2471 2472 TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) { 2473 ASSERT_EQ(2, foo_file_->dependency_count()); 2474 EXPECT_EQ(bar_file_, foo_file_->dependency(0)); 2475 EXPECT_FALSE(bar_file_->is_placeholder()); 2476 2477 const FileDescriptor* baz_file = foo_file_->dependency(1); 2478 EXPECT_EQ("baz.proto", baz_file->name()); 2479 EXPECT_EQ(0, baz_file->message_type_count()); 2480 EXPECT_TRUE(baz_file->is_placeholder()); 2481 2482 // Placeholder files should not be findable. 2483 EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name())); 2484 EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == NULL); 2485 2486 // Copy*To should not crash for placeholder files. 2487 FileDescriptorProto baz_file_proto; 2488 baz_file->CopyTo(&baz_file_proto); 2489 baz_file->CopySourceCodeInfoTo(&baz_file_proto); 2490 EXPECT_FALSE(baz_file_proto.has_source_code_info()); 2491 } 2492 2493 TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) { 2494 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type()); 2495 EXPECT_EQ(bar_type_, bar_field_->message_type()); 2496 EXPECT_FALSE(bar_type_->is_placeholder()); 2497 2498 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type()); 2499 const Descriptor* baz_type = baz_field_->message_type(); 2500 EXPECT_EQ("Baz", baz_type->name()); 2501 EXPECT_EQ("Baz", baz_type->full_name()); 2502 EXPECT_EQ(0, baz_type->extension_range_count()); 2503 EXPECT_TRUE(baz_type->is_placeholder()); 2504 2505 ASSERT_EQ(FieldDescriptor::TYPE_ENUM, qux_field_->type()); 2506 const EnumDescriptor* qux_type = qux_field_->enum_type(); 2507 EXPECT_EQ("Qux", qux_type->name()); 2508 EXPECT_EQ("corge.Qux", qux_type->full_name()); 2509 EXPECT_TRUE(qux_type->is_placeholder()); 2510 2511 // Placeholder types should not be findable. 2512 EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name())); 2513 EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == NULL); 2514 EXPECT_TRUE(pool_->FindEnumTypeByName(qux_type->full_name()) == NULL); 2515 } 2516 2517 TEST_P(AllowUnknownDependenciesTest, CopyTo) { 2518 // FieldDescriptor::CopyTo() should write non-fully-qualified type names 2519 // for placeholder types which were not originally fully-qualified. 2520 FieldDescriptorProto proto; 2521 2522 // Bar is not a placeholder, so it is fully-qualified. 2523 bar_field_->CopyTo(&proto); 2524 EXPECT_EQ(".Bar", proto.type_name()); 2525 EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type()); 2526 2527 // Baz is an unqualified placeholder. 2528 proto.Clear(); 2529 baz_field_->CopyTo(&proto); 2530 EXPECT_EQ("Baz", proto.type_name()); 2531 EXPECT_FALSE(proto.has_type()); 2532 2533 // Qux is a fully-qualified placeholder. 2534 proto.Clear(); 2535 qux_field_->CopyTo(&proto); 2536 EXPECT_EQ(".corge.Qux", proto.type_name()); 2537 EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type()); 2538 } 2539 2540 TEST_P(AllowUnknownDependenciesTest, CustomOptions) { 2541 // Qux should still have the uninterpreted option attached. 2542 ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size()); 2543 const UninterpretedOption& option = 2544 qux_field_->options().uninterpreted_option(0); 2545 ASSERT_EQ(1, option.name_size()); 2546 EXPECT_EQ("grault", option.name(0).name_part()); 2547 } 2548 2549 TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) { 2550 // Test that we can extend an unknown type. This is slightly tricky because 2551 // it means that the placeholder type must have an extension range. 2552 2553 FileDescriptorProto extension_proto; 2554 2555 ASSERT_TRUE(TextFormat::ParseFromString( 2556 "name: 'extension.proto'" 2557 "extension { extendee: 'UnknownType' name:'some_extension' number:123" 2558 " label:LABEL_OPTIONAL type:TYPE_INT32 }", 2559 &extension_proto)); 2560 const FileDescriptor* file = BuildFile(extension_proto); 2561 2562 ASSERT_TRUE(file != NULL); 2563 2564 ASSERT_EQ(1, file->extension_count()); 2565 const Descriptor* extendee = file->extension(0)->containing_type(); 2566 EXPECT_EQ("UnknownType", extendee->name()); 2567 EXPECT_TRUE(extendee->is_placeholder()); 2568 ASSERT_EQ(1, extendee->extension_range_count()); 2569 EXPECT_EQ(1, extendee->extension_range(0)->start); 2570 EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end); 2571 } 2572 2573 TEST_P(AllowUnknownDependenciesTest, CustomOption) { 2574 // Test that we can use a custom option without having parsed 2575 // descriptor.proto. 2576 2577 FileDescriptorProto option_proto; 2578 2579 ASSERT_TRUE(TextFormat::ParseFromString( 2580 "name: \"unknown_custom_options.proto\" " 2581 "dependency: \"google/protobuf/descriptor.proto\" " 2582 "extension { " 2583 " extendee: \"google.protobuf.FileOptions\" " 2584 " name: \"some_option\" " 2585 " number: 123456 " 2586 " label: LABEL_OPTIONAL " 2587 " type: TYPE_INT32 " 2588 "} " 2589 "options { " 2590 " uninterpreted_option { " 2591 " name { " 2592 " name_part: \"some_option\" " 2593 " is_extension: true " 2594 " } " 2595 " positive_int_value: 1234 " 2596 " } " 2597 " uninterpreted_option { " 2598 " name { " 2599 " name_part: \"unknown_option\" " 2600 " is_extension: true " 2601 " } " 2602 " positive_int_value: 1234 " 2603 " } " 2604 " uninterpreted_option { " 2605 " name { " 2606 " name_part: \"optimize_for\" " 2607 " is_extension: false " 2608 " } " 2609 " identifier_value: \"SPEED\" " 2610 " } " 2611 "}", 2612 &option_proto)); 2613 2614 const FileDescriptor* file = BuildFile(option_proto); 2615 ASSERT_TRUE(file != NULL); 2616 2617 // Verify that no extension options were set, but they were left as 2618 // uninterpreted_options. 2619 vector<const FieldDescriptor*> fields; 2620 file->options().GetReflection()->ListFields(file->options(), &fields); 2621 ASSERT_EQ(2, fields.size()); 2622 EXPECT_TRUE(file->options().has_optimize_for()); 2623 EXPECT_EQ(2, file->options().uninterpreted_option_size()); 2624 } 2625 2626 TEST_P(AllowUnknownDependenciesTest, 2627 UndeclaredDependencyTriggersBuildOfDependency) { 2628 // Crazy case: suppose foo.proto refers to a symbol without declaring the 2629 // dependency that finds it. In the event that the pool is backed by a 2630 // DescriptorDatabase, the pool will attempt to find the symbol in the 2631 // database. If successful, it will build the undeclared dependency to verify 2632 // that the file does indeed contain the symbol. If that file fails to build, 2633 // then its descriptors must be rolled back. However, we still want foo.proto 2634 // to build successfully, since we are allowing unknown dependencies. 2635 2636 FileDescriptorProto undeclared_dep_proto; 2637 // We make this file fail to build by giving it two fields with tag 1. 2638 ASSERT_TRUE(TextFormat::ParseFromString( 2639 "name: \"invalid_file_as_undeclared_dep.proto\" " 2640 "package: \"undeclared\" " 2641 "message_type: { " 2642 " name: \"Quux\" " 2643 " field { " 2644 " name:'qux' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 " 2645 " }" 2646 " field { " 2647 " name:'quux' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 " 2648 " }" 2649 "}", 2650 &undeclared_dep_proto)); 2651 // We can't use the BuildFile() helper because we don't actually want to build 2652 // it into the descriptor pool in the fallback database case: it just needs to 2653 // be sitting in the database so that it gets built during the building of 2654 // test.proto below. 2655 switch (mode()) { 2656 case NO_DATABASE: { 2657 ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == NULL); 2658 break; 2659 } 2660 case FALLBACK_DATABASE: { 2661 ASSERT_TRUE(db_.Add(undeclared_dep_proto)); 2662 } 2663 } 2664 2665 FileDescriptorProto test_proto; 2666 ASSERT_TRUE(TextFormat::ParseFromString( 2667 "name: \"test.proto\" " 2668 "message_type: { " 2669 " name: \"Corge\" " 2670 " field { " 2671 " name:'quux' number:1 label: LABEL_OPTIONAL " 2672 " type_name:'undeclared.Quux' type: TYPE_MESSAGE " 2673 " }" 2674 "}", 2675 &test_proto)); 2676 2677 const FileDescriptor* file = BuildFile(test_proto); 2678 ASSERT_TRUE(file != NULL); 2679 GOOGLE_LOG(INFO) << file->DebugString(); 2680 2681 EXPECT_EQ(0, file->dependency_count()); 2682 ASSERT_EQ(1, file->message_type_count()); 2683 const Descriptor* corge_desc = file->message_type(0); 2684 ASSERT_EQ("Corge", corge_desc->name()); 2685 ASSERT_EQ(1, corge_desc->field_count()); 2686 EXPECT_FALSE(corge_desc->is_placeholder()); 2687 2688 const FieldDescriptor* quux_field = corge_desc->field(0); 2689 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, quux_field->type()); 2690 ASSERT_EQ("Quux", quux_field->message_type()->name()); 2691 ASSERT_EQ("undeclared.Quux", quux_field->message_type()->full_name()); 2692 EXPECT_TRUE(quux_field->message_type()->is_placeholder()); 2693 // The place holder type should not be findable. 2694 ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Quux") == NULL); 2695 } 2696 2697 INSTANTIATE_TEST_CASE_P(DatabaseSource, 2698 AllowUnknownDependenciesTest, 2699 testing::Values(NO_DATABASE, FALLBACK_DATABASE)); 2700 2701 // =================================================================== 2702 2703 TEST(CustomOptions, OptionLocations) { 2704 const Descriptor* message = 2705 protobuf_unittest::TestMessageWithCustomOptions::descriptor(); 2706 const FileDescriptor* file = message->file(); 2707 const FieldDescriptor* field = message->FindFieldByName("field1"); 2708 const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum"); 2709 // TODO(benjy): Support EnumValue options, once the compiler does. 2710 const ServiceDescriptor* service = 2711 file->FindServiceByName("TestServiceWithCustomOptions"); 2712 const MethodDescriptor* method = service->FindMethodByName("Foo"); 2713 2714 EXPECT_EQ(GOOGLE_LONGLONG(9876543210), 2715 file->options().GetExtension(protobuf_unittest::file_opt1)); 2716 EXPECT_EQ(-56, 2717 message->options().GetExtension(protobuf_unittest::message_opt1)); 2718 EXPECT_EQ(GOOGLE_LONGLONG(8765432109), 2719 field->options().GetExtension(protobuf_unittest::field_opt1)); 2720 EXPECT_EQ(42, // Check that we get the default for an option we don't set. 2721 field->options().GetExtension(protobuf_unittest::field_opt2)); 2722 EXPECT_EQ(-789, 2723 enm->options().GetExtension(protobuf_unittest::enum_opt1)); 2724 EXPECT_EQ(123, 2725 enm->value(1)->options().GetExtension( 2726 protobuf_unittest::enum_value_opt1)); 2727 EXPECT_EQ(GOOGLE_LONGLONG(-9876543210), 2728 service->options().GetExtension(protobuf_unittest::service_opt1)); 2729 EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2, 2730 method->options().GetExtension(protobuf_unittest::method_opt1)); 2731 2732 // See that the regular options went through unscathed. 2733 EXPECT_TRUE(message->options().has_message_set_wire_format()); 2734 EXPECT_EQ(FieldOptions::CORD, field->options().ctype()); 2735 } 2736 2737 TEST(CustomOptions, OptionTypes) { 2738 const MessageOptions* options = NULL; 2739 2740 options = 2741 &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options(); 2742 EXPECT_EQ(false , options->GetExtension(protobuf_unittest::bool_opt)); 2743 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt)); 2744 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt)); 2745 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::uint32_opt)); 2746 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::uint64_opt)); 2747 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sint32_opt)); 2748 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sint64_opt)); 2749 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::fixed32_opt)); 2750 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::fixed64_opt)); 2751 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sfixed32_opt)); 2752 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sfixed64_opt)); 2753 2754 options = 2755 &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options(); 2756 EXPECT_EQ(true , options->GetExtension(protobuf_unittest::bool_opt)); 2757 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::int32_opt)); 2758 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::int64_opt)); 2759 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt)); 2760 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::uint64_opt)); 2761 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::sint32_opt)); 2762 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::sint64_opt)); 2763 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::fixed32_opt)); 2764 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::fixed64_opt)); 2765 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::sfixed32_opt)); 2766 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::sfixed64_opt)); 2767 2768 options = 2769 &protobuf_unittest::CustomOptionOtherValues::descriptor()->options(); 2770 EXPECT_EQ(-100, options->GetExtension(protobuf_unittest::int32_opt)); 2771 EXPECT_FLOAT_EQ(12.3456789, 2772 options->GetExtension(protobuf_unittest::float_opt)); 2773 EXPECT_DOUBLE_EQ(1.234567890123456789, 2774 options->GetExtension(protobuf_unittest::double_opt)); 2775 EXPECT_EQ("Hello, \"World\"", 2776 options->GetExtension(protobuf_unittest::string_opt)); 2777 2778 EXPECT_EQ(string("Hello\0World", 11), 2779 options->GetExtension(protobuf_unittest::bytes_opt)); 2780 2781 EXPECT_EQ(protobuf_unittest::DummyMessageContainingEnum::TEST_OPTION_ENUM_TYPE2, 2782 options->GetExtension(protobuf_unittest::enum_opt)); 2783 2784 options = 2785 &protobuf_unittest::SettingRealsFromPositiveInts::descriptor()->options(); 2786 EXPECT_FLOAT_EQ(12, options->GetExtension(protobuf_unittest::float_opt)); 2787 EXPECT_DOUBLE_EQ(154, options->GetExtension(protobuf_unittest::double_opt)); 2788 2789 options = 2790 &protobuf_unittest::SettingRealsFromNegativeInts::descriptor()->options(); 2791 EXPECT_FLOAT_EQ(-12, options->GetExtension(protobuf_unittest::float_opt)); 2792 EXPECT_DOUBLE_EQ(-154, options->GetExtension(protobuf_unittest::double_opt)); 2793 } 2794 2795 TEST(CustomOptions, ComplexExtensionOptions) { 2796 const MessageOptions* options = 2797 &protobuf_unittest::VariousComplexOptions::descriptor()->options(); 2798 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).foo(), 42); 2799 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1). 2800 GetExtension(protobuf_unittest::quux), 324); 2801 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1). 2802 GetExtension(protobuf_unittest::corge).qux(), 876); 2803 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).baz(), 987); 2804 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2). 2805 GetExtension(protobuf_unittest::grault), 654); 2806 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().foo(), 2807 743); 2808 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar(). 2809 GetExtension(protobuf_unittest::quux), 1999); 2810 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar(). 2811 GetExtension(protobuf_unittest::corge).qux(), 2008); 2812 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2). 2813 GetExtension(protobuf_unittest::garply).foo(), 741); 2814 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2). 2815 GetExtension(protobuf_unittest::garply). 2816 GetExtension(protobuf_unittest::quux), 1998); 2817 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2). 2818 GetExtension(protobuf_unittest::garply). 2819 GetExtension(protobuf_unittest::corge).qux(), 2121); 2820 EXPECT_EQ(options->GetExtension( 2821 protobuf_unittest::ComplexOptionType2::ComplexOptionType4::complex_opt4). 2822 waldo(), 1971); 2823 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2). 2824 fred().waldo(), 321); 2825 EXPECT_EQ(9, options->GetExtension(protobuf_unittest::complex_opt3).qux()); 2826 EXPECT_EQ(22, options->GetExtension(protobuf_unittest::complex_opt3). 2827 complexoptiontype5().plugh()); 2828 EXPECT_EQ(24, options->GetExtension(protobuf_unittest::complexopt6).xyzzy()); 2829 } 2830 2831 TEST(CustomOptions, OptionsFromOtherFile) { 2832 // Test that to use a custom option, we only need to import the file 2833 // defining the option; we do not also have to import descriptor.proto. 2834 DescriptorPool pool; 2835 2836 FileDescriptorProto file_proto; 2837 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 2838 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 2839 2840 protobuf_unittest::TestMessageWithCustomOptions::descriptor() 2841 ->file()->CopyTo(&file_proto); 2842 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 2843 2844 ASSERT_TRUE(TextFormat::ParseFromString( 2845 "name: \"custom_options_import.proto\" " 2846 "package: \"protobuf_unittest\" " 2847 "dependency: \"google/protobuf/unittest_custom_options.proto\" " 2848 "options { " 2849 " uninterpreted_option { " 2850 " name { " 2851 " name_part: \"file_opt1\" " 2852 " is_extension: true " 2853 " } " 2854 " positive_int_value: 1234 " 2855 " } " 2856 // Test a non-extension option too. (At one point this failed due to a 2857 // bug.) 2858 " uninterpreted_option { " 2859 " name { " 2860 " name_part: \"java_package\" " 2861 " is_extension: false " 2862 " } " 2863 " string_value: \"foo\" " 2864 " } " 2865 // Test that enum-typed options still work too. (At one point this also 2866 // failed due to a bug.) 2867 " uninterpreted_option { " 2868 " name { " 2869 " name_part: \"optimize_for\" " 2870 " is_extension: false " 2871 " } " 2872 " identifier_value: \"SPEED\" " 2873 " } " 2874 "}" 2875 , 2876 &file_proto)); 2877 2878 const FileDescriptor* file = pool.BuildFile(file_proto); 2879 ASSERT_TRUE(file != NULL); 2880 EXPECT_EQ(1234, file->options().GetExtension(protobuf_unittest::file_opt1)); 2881 EXPECT_TRUE(file->options().has_java_package()); 2882 EXPECT_EQ("foo", file->options().java_package()); 2883 EXPECT_TRUE(file->options().has_optimize_for()); 2884 EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for()); 2885 } 2886 2887 TEST(CustomOptions, MessageOptionThreeFieldsSet) { 2888 // This tests a bug which previously existed in custom options parsing. The 2889 // bug occurred when you defined a custom option with message type and then 2890 // set three fields of that option on a single definition (see the example 2891 // below). The bug is a bit hard to explain, so check the change history if 2892 // you want to know more. 2893 DescriptorPool pool; 2894 2895 FileDescriptorProto file_proto; 2896 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 2897 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 2898 2899 protobuf_unittest::TestMessageWithCustomOptions::descriptor() 2900 ->file()->CopyTo(&file_proto); 2901 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 2902 2903 // The following represents the definition: 2904 // 2905 // import "google/protobuf/unittest_custom_options.proto" 2906 // package protobuf_unittest; 2907 // message Foo { 2908 // option (complex_opt1).foo = 1234; 2909 // option (complex_opt1).foo2 = 1234; 2910 // option (complex_opt1).foo3 = 1234; 2911 // } 2912 ASSERT_TRUE(TextFormat::ParseFromString( 2913 "name: \"custom_options_import.proto\" " 2914 "package: \"protobuf_unittest\" " 2915 "dependency: \"google/protobuf/unittest_custom_options.proto\" " 2916 "message_type { " 2917 " name: \"Foo\" " 2918 " options { " 2919 " uninterpreted_option { " 2920 " name { " 2921 " name_part: \"complex_opt1\" " 2922 " is_extension: true " 2923 " } " 2924 " name { " 2925 " name_part: \"foo\" " 2926 " is_extension: false " 2927 " } " 2928 " positive_int_value: 1234 " 2929 " } " 2930 " uninterpreted_option { " 2931 " name { " 2932 " name_part: \"complex_opt1\" " 2933 " is_extension: true " 2934 " } " 2935 " name { " 2936 " name_part: \"foo2\" " 2937 " is_extension: false " 2938 " } " 2939 " positive_int_value: 1234 " 2940 " } " 2941 " uninterpreted_option { " 2942 " name { " 2943 " name_part: \"complex_opt1\" " 2944 " is_extension: true " 2945 " } " 2946 " name { " 2947 " name_part: \"foo3\" " 2948 " is_extension: false " 2949 " } " 2950 " positive_int_value: 1234 " 2951 " } " 2952 " } " 2953 "}", 2954 &file_proto)); 2955 2956 const FileDescriptor* file = pool.BuildFile(file_proto); 2957 ASSERT_TRUE(file != NULL); 2958 ASSERT_EQ(1, file->message_type_count()); 2959 2960 const MessageOptions& options = file->message_type(0)->options(); 2961 EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo()); 2962 } 2963 2964 TEST(CustomOptions, MessageOptionRepeatedLeafFieldSet) { 2965 // This test verifies that repeated fields in custom options can be 2966 // given multiple values by repeating the option with a different value. 2967 // This test checks repeated leaf values. Each repeated custom value 2968 // appears in a different uninterpreted_option, which will be concatenated 2969 // when they are merged into the final option value. 2970 DescriptorPool pool; 2971 2972 FileDescriptorProto file_proto; 2973 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 2974 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 2975 2976 protobuf_unittest::TestMessageWithCustomOptions::descriptor() 2977 ->file()->CopyTo(&file_proto); 2978 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 2979 2980 // The following represents the definition: 2981 // 2982 // import "google/protobuf/unittest_custom_options.proto" 2983 // package protobuf_unittest; 2984 // message Foo { 2985 // option (complex_opt1).foo4 = 12; 2986 // option (complex_opt1).foo4 = 34; 2987 // option (complex_opt1).foo4 = 56; 2988 // } 2989 ASSERT_TRUE(TextFormat::ParseFromString( 2990 "name: \"custom_options_import.proto\" " 2991 "package: \"protobuf_unittest\" " 2992 "dependency: \"google/protobuf/unittest_custom_options.proto\" " 2993 "message_type { " 2994 " name: \"Foo\" " 2995 " options { " 2996 " uninterpreted_option { " 2997 " name { " 2998 " name_part: \"complex_opt1\" " 2999 " is_extension: true " 3000 " } " 3001 " name { " 3002 " name_part: \"foo4\" " 3003 " is_extension: false " 3004 " } " 3005 " positive_int_value: 12 " 3006 " } " 3007 " uninterpreted_option { " 3008 " name { " 3009 " name_part: \"complex_opt1\" " 3010 " is_extension: true " 3011 " } " 3012 " name { " 3013 " name_part: \"foo4\" " 3014 " is_extension: false " 3015 " } " 3016 " positive_int_value: 34 " 3017 " } " 3018 " uninterpreted_option { " 3019 " name { " 3020 " name_part: \"complex_opt1\" " 3021 " is_extension: true " 3022 " } " 3023 " name { " 3024 " name_part: \"foo4\" " 3025 " is_extension: false " 3026 " } " 3027 " positive_int_value: 56 " 3028 " } " 3029 " } " 3030 "}", 3031 &file_proto)); 3032 3033 const FileDescriptor* file = pool.BuildFile(file_proto); 3034 ASSERT_TRUE(file != NULL); 3035 ASSERT_EQ(1, file->message_type_count()); 3036 3037 const MessageOptions& options = file->message_type(0)->options(); 3038 EXPECT_EQ(3, options.GetExtension(protobuf_unittest::complex_opt1).foo4_size()); 3039 EXPECT_EQ(12, options.GetExtension(protobuf_unittest::complex_opt1).foo4(0)); 3040 EXPECT_EQ(34, options.GetExtension(protobuf_unittest::complex_opt1).foo4(1)); 3041 EXPECT_EQ(56, options.GetExtension(protobuf_unittest::complex_opt1).foo4(2)); 3042 } 3043 3044 TEST(CustomOptions, MessageOptionRepeatedMsgFieldSet) { 3045 // This test verifies that repeated fields in custom options can be 3046 // given multiple values by repeating the option with a different value. 3047 // This test checks repeated message values. Each repeated custom value 3048 // appears in a different uninterpreted_option, which will be concatenated 3049 // when they are merged into the final option value. 3050 DescriptorPool pool; 3051 3052 FileDescriptorProto file_proto; 3053 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 3054 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 3055 3056 protobuf_unittest::TestMessageWithCustomOptions::descriptor() 3057 ->file()->CopyTo(&file_proto); 3058 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 3059 3060 // The following represents the definition: 3061 // 3062 // import "google/protobuf/unittest_custom_options.proto" 3063 // package protobuf_unittest; 3064 // message Foo { 3065 // option (complex_opt2).barney = {waldo: 1}; 3066 // option (complex_opt2).barney = {waldo: 10}; 3067 // option (complex_opt2).barney = {waldo: 100}; 3068 // } 3069 ASSERT_TRUE(TextFormat::ParseFromString( 3070 "name: \"custom_options_import.proto\" " 3071 "package: \"protobuf_unittest\" " 3072 "dependency: \"google/protobuf/unittest_custom_options.proto\" " 3073 "message_type { " 3074 " name: \"Foo\" " 3075 " options { " 3076 " uninterpreted_option { " 3077 " name { " 3078 " name_part: \"complex_opt2\" " 3079 " is_extension: true " 3080 " } " 3081 " name { " 3082 " name_part: \"barney\" " 3083 " is_extension: false " 3084 " } " 3085 " aggregate_value: \"waldo: 1\" " 3086 " } " 3087 " uninterpreted_option { " 3088 " name { " 3089 " name_part: \"complex_opt2\" " 3090 " is_extension: true " 3091 " } " 3092 " name { " 3093 " name_part: \"barney\" " 3094 " is_extension: false " 3095 " } " 3096 " aggregate_value: \"waldo: 10\" " 3097 " } " 3098 " uninterpreted_option { " 3099 " name { " 3100 " name_part: \"complex_opt2\" " 3101 " is_extension: true " 3102 " } " 3103 " name { " 3104 " name_part: \"barney\" " 3105 " is_extension: false " 3106 " } " 3107 " aggregate_value: \"waldo: 100\" " 3108 " } " 3109 " } " 3110 "}", 3111 &file_proto)); 3112 3113 const FileDescriptor* file = pool.BuildFile(file_proto); 3114 ASSERT_TRUE(file != NULL); 3115 ASSERT_EQ(1, file->message_type_count()); 3116 3117 const MessageOptions& options = file->message_type(0)->options(); 3118 EXPECT_EQ(3, options.GetExtension( 3119 protobuf_unittest::complex_opt2).barney_size()); 3120 EXPECT_EQ(1,options.GetExtension( 3121 protobuf_unittest::complex_opt2).barney(0).waldo()); 3122 EXPECT_EQ(10, options.GetExtension( 3123 protobuf_unittest::complex_opt2).barney(1).waldo()); 3124 EXPECT_EQ(100, options.GetExtension( 3125 protobuf_unittest::complex_opt2).barney(2).waldo()); 3126 } 3127 3128 // Check that aggregate options were parsed and saved correctly in 3129 // the appropriate descriptors. 3130 TEST(CustomOptions, AggregateOptions) { 3131 const Descriptor* msg = protobuf_unittest::AggregateMessage::descriptor(); 3132 const FileDescriptor* file = msg->file(); 3133 const FieldDescriptor* field = msg->FindFieldByName("fieldname"); 3134 const EnumDescriptor* enumd = file->FindEnumTypeByName("AggregateEnum"); 3135 const EnumValueDescriptor* enumv = enumd->FindValueByName("VALUE"); 3136 const ServiceDescriptor* service = file->FindServiceByName( 3137 "AggregateService"); 3138 const MethodDescriptor* method = service->FindMethodByName("Method"); 3139 3140 // Tests for the different types of data embedded in fileopt 3141 const protobuf_unittest::Aggregate& file_options = 3142 file->options().GetExtension(protobuf_unittest::fileopt); 3143 EXPECT_EQ(100, file_options.i()); 3144 EXPECT_EQ("FileAnnotation", file_options.s()); 3145 EXPECT_EQ("NestedFileAnnotation", file_options.sub().s()); 3146 EXPECT_EQ("FileExtensionAnnotation", 3147 file_options.file().GetExtension(protobuf_unittest::fileopt).s()); 3148 EXPECT_EQ("EmbeddedMessageSetElement", 3149 file_options.mset().GetExtension( 3150 protobuf_unittest::AggregateMessageSetElement 3151 ::message_set_extension).s()); 3152 3153 // Simple tests for all the other types of annotations 3154 EXPECT_EQ("MessageAnnotation", 3155 msg->options().GetExtension(protobuf_unittest::msgopt).s()); 3156 EXPECT_EQ("FieldAnnotation", 3157 field->options().GetExtension(protobuf_unittest::fieldopt).s()); 3158 EXPECT_EQ("EnumAnnotation", 3159 enumd->options().GetExtension(protobuf_unittest::enumopt).s()); 3160 EXPECT_EQ("EnumValueAnnotation", 3161 enumv->options().GetExtension(protobuf_unittest::enumvalopt).s()); 3162 EXPECT_EQ("ServiceAnnotation", 3163 service->options().GetExtension(protobuf_unittest::serviceopt).s()); 3164 EXPECT_EQ("MethodAnnotation", 3165 method->options().GetExtension(protobuf_unittest::methodopt).s()); 3166 } 3167 3168 TEST(CustomOptions, UnusedImportWarning) { 3169 DescriptorPool pool; 3170 3171 FileDescriptorProto file_proto; 3172 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 3173 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 3174 3175 protobuf_unittest::TestMessageWithCustomOptions::descriptor() 3176 ->file()->CopyTo(&file_proto); 3177 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 3178 3179 pool.AddUnusedImportTrackFile("custom_options_import.proto"); 3180 ASSERT_TRUE(TextFormat::ParseFromString( 3181 "name: \"custom_options_import.proto\" " 3182 "package: \"protobuf_unittest\" " 3183 "dependency: \"google/protobuf/unittest_custom_options.proto\" ", 3184 &file_proto)); 3185 3186 MockErrorCollector error_collector; 3187 EXPECT_TRUE(pool.BuildFileCollectingErrors(file_proto, &error_collector)); 3188 EXPECT_EQ("", error_collector.warning_text_); 3189 } 3190 3191 // Verifies that proto files can correctly be parsed, even if the 3192 // custom options defined in the file are incompatible with those 3193 // compiled in the binary. See http://b/19276250. 3194 TEST(CustomOptions, OptionsWithRequiredEnums) { 3195 DescriptorPool pool; 3196 3197 FileDescriptorProto file_proto; 3198 MessageOptions::descriptor()->file()->CopyTo(&file_proto); 3199 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 3200 3201 // Create a new file descriptor proto containing a subset of the 3202 // messages defined in google/protobuf/unittest_custom_options.proto. 3203 file_proto.Clear(); 3204 file_proto.set_name("unittest_custom_options.proto"); 3205 file_proto.set_package("protobuf_unittest"); 3206 file_proto.add_dependency("google/protobuf/descriptor.proto"); 3207 3208 // Add the "required_enum_opt" extension. 3209 FieldDescriptorProto* extension = file_proto.add_extension(); 3210 protobuf_unittest::OldOptionType::descriptor()->file() 3211 ->FindExtensionByName("required_enum_opt")->CopyTo(extension); 3212 3213 // Add a test message that uses the "required_enum_opt" option. 3214 DescriptorProto* test_message_type = file_proto.add_message_type(); 3215 protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor() 3216 ->CopyTo(test_message_type); 3217 3218 // Instruct the extension to use NewOptionType instead of 3219 // OldOptionType, and add the descriptor of NewOptionType. 3220 extension->set_type_name(".protobuf_unittest.NewOptionType"); 3221 DescriptorProto* new_option_type = file_proto.add_message_type(); 3222 protobuf_unittest::NewOptionType::descriptor() 3223 ->CopyTo(new_option_type); 3224 3225 // Replace the value of the "required_enum_opt" option used in the 3226 // test message with an enum value that only exists in NewOptionType. 3227 ASSERT_TRUE(TextFormat::ParseFromString( 3228 "uninterpreted_option { " 3229 " name { " 3230 " name_part: 'required_enum_opt' " 3231 " is_extension: true " 3232 " } " 3233 " aggregate_value: 'value: NEW_VALUE' " 3234 "}", 3235 test_message_type->mutable_options())); 3236 3237 // Add the file descriptor to the pool. 3238 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 3239 3240 // Find the test message. 3241 const Descriptor* test_message = pool.FindMessageTypeByName( 3242 "protobuf_unittest.TestMessageWithRequiredEnumOption"); 3243 ASSERT_TRUE(test_message != NULL); 3244 3245 const MessageOptions& options = test_message->options(); 3246 // Extract the "required_enum_opt" option. Since the binary does not 3247 // know that the extension was updated, this will still return an 3248 // OldOptionType message. 3249 ASSERT_TRUE( 3250 options.HasExtension(protobuf_unittest::required_enum_opt)); 3251 const protobuf_unittest::OldOptionType& old_enum_opt = 3252 options.GetExtension(protobuf_unittest::required_enum_opt); 3253 3254 // Confirm that the required enum field is missing. 3255 EXPECT_FALSE(old_enum_opt.IsInitialized()); 3256 EXPECT_FALSE(old_enum_opt.has_value()); 3257 3258 string buf; 3259 // Verify that the required enum field does show up when the option 3260 // is re-parsed as a NewOptionType message; 3261 protobuf_unittest::NewOptionType new_enum_opt; 3262 EXPECT_TRUE(old_enum_opt.AppendPartialToString(&buf)); 3263 EXPECT_TRUE(new_enum_opt.ParseFromString(buf)); 3264 EXPECT_EQ(protobuf_unittest::NewOptionType::NEW_VALUE, new_enum_opt.value()); 3265 } 3266 3267 // =================================================================== 3268 3269 class ValidationErrorTest : public testing::Test { 3270 protected: 3271 // Parse file_text as a FileDescriptorProto in text format and add it 3272 // to the DescriptorPool. Expect no errors. 3273 const FileDescriptor* BuildFile(const string& file_text) { 3274 FileDescriptorProto file_proto; 3275 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); 3276 return GOOGLE_CHECK_NOTNULL(pool_.BuildFile(file_proto)); 3277 } 3278 3279 // Parse file_text as a FileDescriptorProto in text format and add it 3280 // to the DescriptorPool. Expect errors to be produced which match the 3281 // given error text. 3282 void BuildFileWithErrors(const string& file_text, 3283 const string& expected_errors) { 3284 FileDescriptorProto file_proto; 3285 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); 3286 3287 MockErrorCollector error_collector; 3288 EXPECT_TRUE( 3289 pool_.BuildFileCollectingErrors(file_proto, &error_collector) == NULL); 3290 EXPECT_EQ(expected_errors, error_collector.text_); 3291 } 3292 3293 // Parse file_text as a FileDescriptorProto in text format and add it 3294 // to the DescriptorPool. Expect errors to be produced which match the 3295 // given warning text. 3296 void BuildFileWithWarnings(const string& file_text, 3297 const string& expected_warnings) { 3298 FileDescriptorProto file_proto; 3299 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); 3300 3301 MockErrorCollector error_collector; 3302 EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector)); 3303 EXPECT_EQ(expected_warnings, error_collector.warning_text_); 3304 } 3305 3306 // Builds some already-parsed file in our test pool. 3307 void BuildFileInTestPool(const FileDescriptor* file) { 3308 FileDescriptorProto file_proto; 3309 file->CopyTo(&file_proto); 3310 ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL); 3311 } 3312 3313 // Build descriptor.proto in our test pool. This allows us to extend it in 3314 // the test pool, so we can test custom options. 3315 void BuildDescriptorMessagesInTestPool() { 3316 BuildFileInTestPool(DescriptorProto::descriptor()->file()); 3317 } 3318 3319 DescriptorPool pool_; 3320 }; 3321 3322 TEST_F(ValidationErrorTest, AlreadyDefined) { 3323 BuildFileWithErrors( 3324 "name: \"foo.proto\" " 3325 "message_type { name: \"Foo\" }" 3326 "message_type { name: \"Foo\" }", 3327 3328 "foo.proto: Foo: NAME: \"Foo\" is already defined.\n"); 3329 } 3330 3331 TEST_F(ValidationErrorTest, AlreadyDefinedInPackage) { 3332 BuildFileWithErrors( 3333 "name: \"foo.proto\" " 3334 "package: \"foo.bar\" " 3335 "message_type { name: \"Foo\" }" 3336 "message_type { name: \"Foo\" }", 3337 3338 "foo.proto: foo.bar.Foo: NAME: \"Foo\" is already defined in " 3339 "\"foo.bar\".\n"); 3340 } 3341 3342 TEST_F(ValidationErrorTest, AlreadyDefinedInOtherFile) { 3343 BuildFile( 3344 "name: \"foo.proto\" " 3345 "message_type { name: \"Foo\" }"); 3346 3347 BuildFileWithErrors( 3348 "name: \"bar.proto\" " 3349 "message_type { name: \"Foo\" }", 3350 3351 "bar.proto: Foo: NAME: \"Foo\" is already defined in file " 3352 "\"foo.proto\".\n"); 3353 } 3354 3355 TEST_F(ValidationErrorTest, PackageAlreadyDefined) { 3356 BuildFile( 3357 "name: \"foo.proto\" " 3358 "message_type { name: \"foo\" }"); 3359 BuildFileWithErrors( 3360 "name: \"bar.proto\" " 3361 "package: \"foo.bar\"", 3362 3363 "bar.proto: foo: NAME: \"foo\" is already defined (as something other " 3364 "than a package) in file \"foo.proto\".\n"); 3365 } 3366 3367 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) { 3368 BuildFileWithErrors( 3369 "name: \"foo.proto\" " 3370 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } " 3371 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ", 3372 3373 "foo.proto: FOO: NAME: \"FOO\" is already defined.\n" 3374 "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, " 3375 "meaning that enum values are siblings of their type, not children of " 3376 "it. Therefore, \"FOO\" must be unique within the global scope, not " 3377 "just within \"Bar\".\n"); 3378 } 3379 3380 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) { 3381 BuildFileWithErrors( 3382 "name: \"foo.proto\" " 3383 "package: \"pkg\" " 3384 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } " 3385 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ", 3386 3387 "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n" 3388 "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, " 3389 "meaning that enum values are siblings of their type, not children of " 3390 "it. Therefore, \"FOO\" must be unique within \"pkg\", not just within " 3391 "\"Bar\".\n"); 3392 } 3393 3394 TEST_F(ValidationErrorTest, MissingName) { 3395 BuildFileWithErrors( 3396 "name: \"foo.proto\" " 3397 "message_type { }", 3398 3399 "foo.proto: : NAME: Missing name.\n"); 3400 } 3401 3402 TEST_F(ValidationErrorTest, InvalidName) { 3403 BuildFileWithErrors( 3404 "name: \"foo.proto\" " 3405 "message_type { name: \"$\" }", 3406 3407 "foo.proto: $: NAME: \"$\" is not a valid identifier.\n"); 3408 } 3409 3410 TEST_F(ValidationErrorTest, InvalidPackageName) { 3411 BuildFileWithErrors( 3412 "name: \"foo.proto\" " 3413 "package: \"foo.$\"", 3414 3415 "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n"); 3416 } 3417 3418 TEST_F(ValidationErrorTest, MissingFileName) { 3419 BuildFileWithErrors( 3420 "", 3421 3422 ": : OTHER: Missing field: FileDescriptorProto.name.\n"); 3423 } 3424 3425 TEST_F(ValidationErrorTest, DupeDependency) { 3426 BuildFile("name: \"foo.proto\""); 3427 BuildFileWithErrors( 3428 "name: \"bar.proto\" " 3429 "dependency: \"foo.proto\" " 3430 "dependency: \"foo.proto\" ", 3431 3432 "bar.proto: bar.proto: OTHER: Import \"foo.proto\" was listed twice.\n"); 3433 } 3434 3435 TEST_F(ValidationErrorTest, UnknownDependency) { 3436 BuildFileWithErrors( 3437 "name: \"bar.proto\" " 3438 "dependency: \"foo.proto\" ", 3439 3440 "bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n"); 3441 } 3442 3443 TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) { 3444 BuildFile("name: \"foo.proto\""); 3445 BuildFileWithErrors( 3446 "name: \"bar.proto\" " 3447 "dependency: \"foo.proto\" " 3448 "public_dependency: 1", 3449 "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n"); 3450 } 3451 3452 TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) { 3453 // Used to crash: If we depend on a non-existent file and then refer to a 3454 // package defined in a file that we didn't import, and that package is 3455 // nested within a parent package which this file is also in, and we don't 3456 // include that parent package in the name (i.e. we do a relative lookup)... 3457 // Yes, really. 3458 BuildFile( 3459 "name: 'foo.proto' " 3460 "package: 'outer.foo' "); 3461 BuildFileWithErrors( 3462 "name: 'bar.proto' " 3463 "dependency: 'baz.proto' " 3464 "package: 'outer.bar' " 3465 "message_type { " 3466 " name: 'Bar' " 3467 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }" 3468 "}", 3469 3470 "bar.proto: bar.proto: OTHER: Import \"baz.proto\" has not been loaded.\n" 3471 "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined in " 3472 "\"foo.proto\", which is not imported by \"bar.proto\". To use it here, " 3473 "please add the necessary import.\n"); 3474 } 3475 3476 TEST_F(ValidationErrorTest, DupeFile) { 3477 BuildFile( 3478 "name: \"foo.proto\" " 3479 "message_type { name: \"Foo\" }"); 3480 // Note: We should *not* get redundant errors about "Foo" already being 3481 // defined. 3482 BuildFileWithErrors( 3483 "name: \"foo.proto\" " 3484 "message_type { name: \"Foo\" } " 3485 // Add another type so that the files aren't identical (in which case there 3486 // would be no error). 3487 "enum_type { name: \"Bar\" }", 3488 3489 "foo.proto: foo.proto: OTHER: A file with this name is already in the " 3490 "pool.\n"); 3491 } 3492 3493 TEST_F(ValidationErrorTest, FieldInExtensionRange) { 3494 BuildFileWithErrors( 3495 "name: \"foo.proto\" " 3496 "message_type {" 3497 " name: \"Foo\"" 3498 " field { name: \"foo\" number: 9 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3499 " field { name: \"bar\" number: 10 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3500 " field { name: \"baz\" number: 19 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3501 " field { name: \"qux\" number: 20 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3502 " extension_range { start: 10 end: 20 }" 3503 "}", 3504 3505 "foo.proto: Foo.bar: NUMBER: Extension range 10 to 19 includes field " 3506 "\"bar\" (10).\n" 3507 "foo.proto: Foo.baz: NUMBER: Extension range 10 to 19 includes field " 3508 "\"baz\" (19).\n"); 3509 } 3510 3511 TEST_F(ValidationErrorTest, OverlappingExtensionRanges) { 3512 BuildFileWithErrors( 3513 "name: \"foo.proto\" " 3514 "message_type {" 3515 " name: \"Foo\"" 3516 " extension_range { start: 10 end: 20 }" 3517 " extension_range { start: 20 end: 30 }" 3518 " extension_range { start: 19 end: 21 }" 3519 "}", 3520 3521 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with " 3522 "already-defined range 10 to 19.\n" 3523 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with " 3524 "already-defined range 20 to 29.\n"); 3525 } 3526 3527 TEST_F(ValidationErrorTest, ReservedFieldError) { 3528 BuildFileWithErrors( 3529 "name: \"foo.proto\" " 3530 "message_type {" 3531 " name: \"Foo\"" 3532 " field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3533 " reserved_range { start: 10 end: 20 }" 3534 "}", 3535 3536 "foo.proto: Foo.foo: NUMBER: Field \"foo\" uses reserved number 15.\n"); 3537 } 3538 3539 TEST_F(ValidationErrorTest, ReservedExtensionRangeError) { 3540 BuildFileWithErrors( 3541 "name: \"foo.proto\" " 3542 "message_type {" 3543 " name: \"Foo\"" 3544 " extension_range { start: 10 end: 20 }" 3545 " reserved_range { start: 5 end: 15 }" 3546 "}", 3547 3548 "foo.proto: Foo: NUMBER: Extension range 10 to 19" 3549 " overlaps with reserved range 5 to 14.\n"); 3550 } 3551 3552 TEST_F(ValidationErrorTest, ReservedExtensionRangeAdjacent) { 3553 BuildFile( 3554 "name: \"foo.proto\" " 3555 "message_type {" 3556 " name: \"Foo\"" 3557 " extension_range { start: 10 end: 20 }" 3558 " reserved_range { start: 5 end: 10 }" 3559 "}"); 3560 } 3561 3562 TEST_F(ValidationErrorTest, ReservedRangeOverlap) { 3563 BuildFileWithErrors( 3564 "name: \"foo.proto\" " 3565 "message_type {" 3566 " name: \"Foo\"" 3567 " reserved_range { start: 10 end: 20 }" 3568 " reserved_range { start: 5 end: 15 }" 3569 "}", 3570 3571 "foo.proto: Foo: NUMBER: Reserved range 5 to 14" 3572 " overlaps with already-defined range 10 to 19.\n"); 3573 } 3574 3575 TEST_F(ValidationErrorTest, ReservedNameError) { 3576 BuildFileWithErrors( 3577 "name: \"foo.proto\" " 3578 "message_type {" 3579 " name: \"Foo\"" 3580 " field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3581 " field { name: \"bar\" number: 16 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3582 " field { name: \"baz\" number: 17 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3583 " reserved_name: \"foo\"" 3584 " reserved_name: \"bar\"" 3585 "}", 3586 3587 "foo.proto: Foo.foo: NAME: Field name \"foo\" is reserved.\n" 3588 "foo.proto: Foo.bar: NAME: Field name \"bar\" is reserved.\n"); 3589 } 3590 3591 TEST_F(ValidationErrorTest, ReservedNameRedundant) { 3592 BuildFileWithErrors( 3593 "name: \"foo.proto\" " 3594 "message_type {" 3595 " name: \"Foo\"" 3596 " reserved_name: \"foo\"" 3597 " reserved_name: \"foo\"" 3598 "}", 3599 3600 "foo.proto: foo: NAME: Field name \"foo\" is reserved multiple times.\n"); 3601 } 3602 3603 TEST_F(ValidationErrorTest, ReservedFieldsDebugString) { 3604 const FileDescriptor* file = BuildFile( 3605 "name: \"foo.proto\" " 3606 "message_type {" 3607 " name: \"Foo\"" 3608 " reserved_name: \"foo\"" 3609 " reserved_name: \"bar\"" 3610 " reserved_range { start: 5 end: 6 }" 3611 " reserved_range { start: 10 end: 20 }" 3612 "}"); 3613 3614 ASSERT_EQ( 3615 "syntax = \"proto2\";\n\n" 3616 "message Foo {\n" 3617 " reserved 5, 10 to 19;\n" 3618 " reserved \"foo\", \"bar\";\n" 3619 "}\n\n", 3620 file->DebugString()); 3621 } 3622 3623 TEST_F(ValidationErrorTest, InvalidDefaults) { 3624 BuildFileWithErrors( 3625 "name: \"foo.proto\" " 3626 "message_type {" 3627 " name: \"Foo\"" 3628 3629 // Invalid number. 3630 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32" 3631 " default_value: \"abc\" }" 3632 3633 // Empty default value. 3634 " field { name: \"bar\" number: 2 label: LABEL_OPTIONAL type: TYPE_INT32" 3635 " default_value: \"\" }" 3636 3637 // Invalid boolean. 3638 " field { name: \"baz\" number: 3 label: LABEL_OPTIONAL type: TYPE_BOOL" 3639 " default_value: \"abc\" }" 3640 3641 // Messages can't have defaults. 3642 " field { name: \"qux\" number: 4 label: LABEL_OPTIONAL type: TYPE_MESSAGE" 3643 " default_value: \"abc\" type_name: \"Foo\" }" 3644 3645 // Same thing, but we don't know that this field has message type until 3646 // we look up the type name. 3647 " field { name: \"quux\" number: 5 label: LABEL_OPTIONAL" 3648 " default_value: \"abc\" type_name: \"Foo\" }" 3649 3650 // Repeateds can't have defaults. 3651 " field { name: \"corge\" number: 6 label: LABEL_REPEATED type: TYPE_INT32" 3652 " default_value: \"1\" }" 3653 "}", 3654 3655 "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value \"abc\".\n" 3656 "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value \"\".\n" 3657 "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or " 3658 "false.\n" 3659 "foo.proto: Foo.qux: DEFAULT_VALUE: Messages can't have default values.\n" 3660 "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default " 3661 "values.\n" 3662 // This ends up being reported later because the error is detected at 3663 // cross-linking time. 3664 "foo.proto: Foo.quux: DEFAULT_VALUE: Messages can't have default " 3665 "values.\n"); 3666 } 3667 3668 TEST_F(ValidationErrorTest, NegativeFieldNumber) { 3669 BuildFileWithErrors( 3670 "name: \"foo.proto\" " 3671 "message_type {" 3672 " name: \"Foo\"" 3673 " field { name: \"foo\" number: -1 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3674 "}", 3675 3676 "foo.proto: Foo.foo: NUMBER: Field numbers must be positive integers.\n"); 3677 } 3678 3679 TEST_F(ValidationErrorTest, HugeFieldNumber) { 3680 BuildFileWithErrors( 3681 "name: \"foo.proto\" " 3682 "message_type {" 3683 " name: \"Foo\"" 3684 " field { name: \"foo\" number: 0x70000000 " 3685 " label:LABEL_OPTIONAL type:TYPE_INT32 }" 3686 "}", 3687 3688 "foo.proto: Foo.foo: NUMBER: Field numbers cannot be greater than " 3689 "536870911.\n"); 3690 } 3691 3692 TEST_F(ValidationErrorTest, ReservedFieldNumber) { 3693 BuildFileWithErrors( 3694 "name: \"foo.proto\" " 3695 "message_type {" 3696 " name: \"Foo\"" 3697 " field {name:\"foo\" number: 18999 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3698 " field {name:\"bar\" number: 19000 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3699 " field {name:\"baz\" number: 19999 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3700 " field {name:\"qux\" number: 20000 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3701 "}", 3702 3703 "foo.proto: Foo.bar: NUMBER: Field numbers 19000 through 19999 are " 3704 "reserved for the protocol buffer library implementation.\n" 3705 "foo.proto: Foo.baz: NUMBER: Field numbers 19000 through 19999 are " 3706 "reserved for the protocol buffer library implementation.\n"); 3707 } 3708 3709 TEST_F(ValidationErrorTest, ExtensionMissingExtendee) { 3710 BuildFileWithErrors( 3711 "name: \"foo.proto\" " 3712 "message_type {" 3713 " name: \"Foo\"" 3714 " extension { name: \"foo\" number: 1 label: LABEL_OPTIONAL" 3715 " type_name: \"Foo\" }" 3716 "}", 3717 3718 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee not set for " 3719 "extension field.\n"); 3720 } 3721 3722 TEST_F(ValidationErrorTest, NonExtensionWithExtendee) { 3723 BuildFileWithErrors( 3724 "name: \"foo.proto\" " 3725 "message_type {" 3726 " name: \"Bar\"" 3727 " extension_range { start: 1 end: 2 }" 3728 "}" 3729 "message_type {" 3730 " name: \"Foo\"" 3731 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL" 3732 " type_name: \"Foo\" extendee: \"Bar\" }" 3733 "}", 3734 3735 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee set for " 3736 "non-extension field.\n"); 3737 } 3738 3739 TEST_F(ValidationErrorTest, FieldOneofIndexTooLarge) { 3740 BuildFileWithErrors( 3741 "name: \"foo.proto\" " 3742 "message_type {" 3743 " name: \"Foo\"" 3744 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 " 3745 " oneof_index: 1 }" 3746 " field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 " 3747 " oneof_index: 0 }" 3748 " oneof_decl { name:\"bar\" }" 3749 "}", 3750 3751 "foo.proto: Foo.foo: OTHER: FieldDescriptorProto.oneof_index 1 is out of " 3752 "range for type \"Foo\".\n"); 3753 } 3754 3755 TEST_F(ValidationErrorTest, FieldOneofIndexNegative) { 3756 BuildFileWithErrors( 3757 "name: \"foo.proto\" " 3758 "message_type {" 3759 " name: \"Foo\"" 3760 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 " 3761 " oneof_index: -1 }" 3762 " field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 " 3763 " oneof_index: 0 }" 3764 " oneof_decl { name:\"bar\" }" 3765 "}", 3766 3767 "foo.proto: Foo.foo: OTHER: FieldDescriptorProto.oneof_index -1 is out of " 3768 "range for type \"Foo\".\n"); 3769 } 3770 3771 TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { 3772 // Fields belonging to the same oneof must be defined consecutively. 3773 BuildFileWithErrors( 3774 "name: \"foo.proto\" " 3775 "message_type {" 3776 " name: \"Foo\"" 3777 " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " 3778 " oneof_index: 0 }" 3779 " field { name:\"bar\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3780 " field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 " 3781 " oneof_index: 0 }" 3782 " oneof_decl { name:\"foos\" }" 3783 "}", 3784 3785 "foo.proto: Foo.bar: OTHER: Fields in the same oneof must be defined " 3786 "consecutively. \"bar\" cannot be defined before the completion of the " 3787 "\"foos\" oneof definition.\n"); 3788 3789 // Prevent interleaved fields, which belong to different oneofs. 3790 BuildFileWithErrors( 3791 "name: \"foo2.proto\" " 3792 "message_type {" 3793 " name: \"Foo2\"" 3794 " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " 3795 " oneof_index: 0 }" 3796 " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 " 3797 " oneof_index: 1 }" 3798 " field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 " 3799 " oneof_index: 0 }" 3800 " field { name:\"bar2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 " 3801 " oneof_index: 1 }" 3802 " oneof_decl { name:\"foos\" }" 3803 " oneof_decl { name:\"bars\" }" 3804 "}", 3805 "foo2.proto: Foo2.bar1: OTHER: Fields in the same oneof must be defined " 3806 "consecutively. \"bar1\" cannot be defined before the completion of the " 3807 "\"foos\" oneof definition.\n" 3808 "foo2.proto: Foo2.foo2: OTHER: Fields in the same oneof must be defined " 3809 "consecutively. \"foo2\" cannot be defined before the completion of the " 3810 "\"bars\" oneof definition.\n"); 3811 3812 // Another case for normal fields and different oneof fields interleave. 3813 BuildFileWithErrors( 3814 "name: \"foo3.proto\" " 3815 "message_type {" 3816 " name: \"Foo3\"" 3817 " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " 3818 " oneof_index: 0 }" 3819 " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 " 3820 " oneof_index: 1 }" 3821 " field { name:\"baz\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3822 " field { name:\"foo2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 " 3823 " oneof_index: 0 }" 3824 " oneof_decl { name:\"foos\" }" 3825 " oneof_decl { name:\"bars\" }" 3826 "}", 3827 "foo3.proto: Foo3.baz: OTHER: Fields in the same oneof must be defined " 3828 "consecutively. \"baz\" cannot be defined before the completion of the " 3829 "\"foos\" oneof definition.\n"); 3830 } 3831 3832 TEST_F(ValidationErrorTest, FieldNumberConflict) { 3833 BuildFileWithErrors( 3834 "name: \"foo.proto\" " 3835 "message_type {" 3836 " name: \"Foo\"" 3837 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3838 " field { name: \"bar\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3839 "}", 3840 3841 "foo.proto: Foo.bar: NUMBER: Field number 1 has already been used in " 3842 "\"Foo\" by field \"foo\".\n"); 3843 } 3844 3845 TEST_F(ValidationErrorTest, BadMessageSetExtensionType) { 3846 BuildFileWithErrors( 3847 "name: \"foo.proto\" " 3848 "message_type {" 3849 " name: \"MessageSet\"" 3850 " options { message_set_wire_format: true }" 3851 " extension_range { start: 4 end: 5 }" 3852 "}" 3853 "message_type {" 3854 " name: \"Foo\"" 3855 " extension { name:\"foo\" number:4 label:LABEL_OPTIONAL type:TYPE_INT32" 3856 " extendee: \"MessageSet\" }" 3857 "}", 3858 3859 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional " 3860 "messages.\n"); 3861 } 3862 3863 TEST_F(ValidationErrorTest, BadMessageSetExtensionLabel) { 3864 BuildFileWithErrors( 3865 "name: \"foo.proto\" " 3866 "message_type {" 3867 " name: \"MessageSet\"" 3868 " options { message_set_wire_format: true }" 3869 " extension_range { start: 4 end: 5 }" 3870 "}" 3871 "message_type {" 3872 " name: \"Foo\"" 3873 " extension { name:\"foo\" number:4 label:LABEL_REPEATED type:TYPE_MESSAGE" 3874 " type_name: \"Foo\" extendee: \"MessageSet\" }" 3875 "}", 3876 3877 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional " 3878 "messages.\n"); 3879 } 3880 3881 TEST_F(ValidationErrorTest, FieldInMessageSet) { 3882 BuildFileWithErrors( 3883 "name: \"foo.proto\" " 3884 "message_type {" 3885 " name: \"Foo\"" 3886 " options { message_set_wire_format: true }" 3887 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }" 3888 "}", 3889 3890 "foo.proto: Foo.foo: NAME: MessageSets cannot have fields, only " 3891 "extensions.\n"); 3892 } 3893 3894 TEST_F(ValidationErrorTest, NegativeExtensionRangeNumber) { 3895 BuildFileWithErrors( 3896 "name: \"foo.proto\" " 3897 "message_type {" 3898 " name: \"Foo\"" 3899 " extension_range { start: -10 end: -1 }" 3900 "}", 3901 3902 "foo.proto: Foo: NUMBER: Extension numbers must be positive integers.\n"); 3903 } 3904 3905 TEST_F(ValidationErrorTest, HugeExtensionRangeNumber) { 3906 BuildFileWithErrors( 3907 "name: \"foo.proto\" " 3908 "message_type {" 3909 " name: \"Foo\"" 3910 " extension_range { start: 1 end: 0x70000000 }" 3911 "}", 3912 3913 "foo.proto: Foo: NUMBER: Extension numbers cannot be greater than " 3914 "536870911.\n"); 3915 } 3916 3917 TEST_F(ValidationErrorTest, ExtensionRangeEndBeforeStart) { 3918 BuildFileWithErrors( 3919 "name: \"foo.proto\" " 3920 "message_type {" 3921 " name: \"Foo\"" 3922 " extension_range { start: 10 end: 10 }" 3923 " extension_range { start: 10 end: 5 }" 3924 "}", 3925 3926 "foo.proto: Foo: NUMBER: Extension range end number must be greater than " 3927 "start number.\n" 3928 "foo.proto: Foo: NUMBER: Extension range end number must be greater than " 3929 "start number.\n"); 3930 } 3931 3932 TEST_F(ValidationErrorTest, EmptyEnum) { 3933 BuildFileWithErrors( 3934 "name: \"foo.proto\" " 3935 "enum_type { name: \"Foo\" }" 3936 // Also use the empty enum in a message to make sure there are no crashes 3937 // during validation (possible if the code attempts to derive a default 3938 // value for the field). 3939 "message_type {" 3940 " name: \"Bar\"" 3941 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type_name:\"Foo\" }" 3942 " field { name: \"bar\" number: 2 label:LABEL_OPTIONAL type_name:\"Foo\" " 3943 " default_value: \"NO_SUCH_VALUE\" }" 3944 "}", 3945 3946 "foo.proto: Foo: NAME: Enums must contain at least one value.\n" 3947 "foo.proto: Bar.bar: DEFAULT_VALUE: Enum type \"Foo\" has no value named " 3948 "\"NO_SUCH_VALUE\".\n"); 3949 } 3950 3951 TEST_F(ValidationErrorTest, UndefinedExtendee) { 3952 BuildFileWithErrors( 3953 "name: \"foo.proto\" " 3954 "message_type {" 3955 " name: \"Foo\"" 3956 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32" 3957 " extendee: \"Bar\" }" 3958 "}", 3959 3960 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not defined.\n"); 3961 } 3962 3963 TEST_F(ValidationErrorTest, NonMessageExtendee) { 3964 BuildFileWithErrors( 3965 "name: \"foo.proto\" " 3966 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } }" 3967 "message_type {" 3968 " name: \"Foo\"" 3969 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32" 3970 " extendee: \"Bar\" }" 3971 "}", 3972 3973 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not a message type.\n"); 3974 } 3975 3976 TEST_F(ValidationErrorTest, NotAnExtensionNumber) { 3977 BuildFileWithErrors( 3978 "name: \"foo.proto\" " 3979 "message_type {" 3980 " name: \"Bar\"" 3981 "}" 3982 "message_type {" 3983 " name: \"Foo\"" 3984 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32" 3985 " extendee: \"Bar\" }" 3986 "}", 3987 3988 "foo.proto: Foo.foo: NUMBER: \"Bar\" does not declare 1 as an extension " 3989 "number.\n"); 3990 } 3991 3992 TEST_F(ValidationErrorTest, RequiredExtension) { 3993 BuildFileWithErrors( 3994 "name: \"foo.proto\" " 3995 "message_type {" 3996 " name: \"Bar\"" 3997 " extension_range { start: 1000 end: 10000 }" 3998 "}" 3999 "message_type {" 4000 " name: \"Foo\"" 4001 " extension {" 4002 " name:\"foo\"" 4003 " number:1000" 4004 " label:LABEL_REQUIRED" 4005 " type:TYPE_INT32" 4006 " extendee: \"Bar\"" 4007 " }" 4008 "}", 4009 4010 "foo.proto: Foo.foo: TYPE: Message extensions cannot have required " 4011 "fields.\n"); 4012 } 4013 4014 TEST_F(ValidationErrorTest, UndefinedFieldType) { 4015 BuildFileWithErrors( 4016 "name: \"foo.proto\" " 4017 "message_type {" 4018 " name: \"Foo\"" 4019 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4020 "}", 4021 4022 "foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n"); 4023 } 4024 4025 TEST_F(ValidationErrorTest, UndefinedFieldTypeWithDefault) { 4026 // See b/12533582. Previously this failed because the default value was not 4027 // accepted by the parser, which assumed an enum type, leading to an unclear 4028 // error message. We want this input to yield a validation error instead, 4029 // since the unknown type is the primary problem. 4030 BuildFileWithErrors( 4031 "name: \"foo.proto\" " 4032 "message_type {" 4033 " name: \"Foo\"" 4034 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"int\" " 4035 " default_value:\"1\" }" 4036 "}", 4037 4038 "foo.proto: Foo.foo: TYPE: \"int\" is not defined.\n"); 4039 } 4040 4041 TEST_F(ValidationErrorTest, UndefinedNestedFieldType) { 4042 BuildFileWithErrors( 4043 "name: \"foo.proto\" " 4044 "message_type {" 4045 " name: \"Foo\"" 4046 " nested_type { name:\"Baz\" }" 4047 " field { name:\"foo\" number:1" 4048 " label:LABEL_OPTIONAL" 4049 " type_name:\"Foo.Baz.Bar\" }" 4050 "}", 4051 4052 "foo.proto: Foo.foo: TYPE: \"Foo.Baz.Bar\" is not defined.\n"); 4053 } 4054 4055 TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) { 4056 BuildFile( 4057 "name: \"bar.proto\" " 4058 "message_type { name: \"Bar\" } "); 4059 4060 BuildFileWithErrors( 4061 "name: \"foo.proto\" " 4062 "message_type {" 4063 " name: \"Foo\"" 4064 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4065 "}", 4066 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", " 4067 "which is not imported by \"foo.proto\". To use it here, please add the " 4068 "necessary import.\n"); 4069 } 4070 4071 TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) { 4072 // Test for hidden dependencies. 4073 // 4074 // // bar.proto 4075 // message Bar{} 4076 // 4077 // // forward.proto 4078 // import "bar.proto" 4079 // 4080 // // foo.proto 4081 // import "forward.proto" 4082 // message Foo { 4083 // optional Bar foo = 1; // Error, needs to import bar.proto explicitly. 4084 // } 4085 // 4086 BuildFile( 4087 "name: \"bar.proto\" " 4088 "message_type { name: \"Bar\" }"); 4089 4090 BuildFile( 4091 "name: \"forward.proto\"" 4092 "dependency: \"bar.proto\""); 4093 4094 BuildFileWithErrors( 4095 "name: \"foo.proto\" " 4096 "dependency: \"forward.proto\" " 4097 "message_type {" 4098 " name: \"Foo\"" 4099 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4100 "}", 4101 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", " 4102 "which is not imported by \"foo.proto\". To use it here, please add the " 4103 "necessary import.\n"); 4104 } 4105 4106 TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) { 4107 // Test for public dependencies. 4108 // 4109 // // bar.proto 4110 // message Bar{} 4111 // 4112 // // forward.proto 4113 // import public "bar.proto" 4114 // 4115 // // foo.proto 4116 // import "forward.proto" 4117 // message Foo { 4118 // optional Bar foo = 1; // Correct. "bar.proto" is public imported into 4119 // // forward.proto, so when "foo.proto" imports 4120 // // "forward.proto", it imports "bar.proto" too. 4121 // } 4122 // 4123 BuildFile( 4124 "name: \"bar.proto\" " 4125 "message_type { name: \"Bar\" }"); 4126 4127 BuildFile( 4128 "name: \"forward.proto\"" 4129 "dependency: \"bar.proto\" " 4130 "public_dependency: 0"); 4131 4132 BuildFile( 4133 "name: \"foo.proto\" " 4134 "dependency: \"forward.proto\" " 4135 "message_type {" 4136 " name: \"Foo\"" 4137 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4138 "}"); 4139 } 4140 4141 TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) { 4142 // Test for public dependencies. 4143 // 4144 // // bar.proto 4145 // message Bar{} 4146 // 4147 // // forward.proto 4148 // import public "bar.proto" 4149 // 4150 // // forward2.proto 4151 // import public "forward.proto" 4152 // 4153 // // foo.proto 4154 // import "forward2.proto" 4155 // message Foo { 4156 // optional Bar foo = 1; // Correct, public imports are transitive. 4157 // } 4158 // 4159 BuildFile( 4160 "name: \"bar.proto\" " 4161 "message_type { name: \"Bar\" }"); 4162 4163 BuildFile( 4164 "name: \"forward.proto\"" 4165 "dependency: \"bar.proto\" " 4166 "public_dependency: 0"); 4167 4168 BuildFile( 4169 "name: \"forward2.proto\"" 4170 "dependency: \"forward.proto\" " 4171 "public_dependency: 0"); 4172 4173 BuildFile( 4174 "name: \"foo.proto\" " 4175 "dependency: \"forward2.proto\" " 4176 "message_type {" 4177 " name: \"Foo\"" 4178 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4179 "}"); 4180 } 4181 4182 TEST_F(ValidationErrorTest, 4183 FieldTypeDefinedInPrivateDependencyOfPublicDependency) { 4184 // Test for public dependencies. 4185 // 4186 // // bar.proto 4187 // message Bar{} 4188 // 4189 // // forward.proto 4190 // import "bar.proto" 4191 // 4192 // // forward2.proto 4193 // import public "forward.proto" 4194 // 4195 // // foo.proto 4196 // import "forward2.proto" 4197 // message Foo { 4198 // optional Bar foo = 1; // Error, the "bar.proto" is not public imported 4199 // // into "forward.proto", so will not be imported 4200 // // into either "forward2.proto" or "foo.proto". 4201 // } 4202 // 4203 BuildFile( 4204 "name: \"bar.proto\" " 4205 "message_type { name: \"Bar\" }"); 4206 4207 BuildFile( 4208 "name: \"forward.proto\"" 4209 "dependency: \"bar.proto\""); 4210 4211 BuildFile( 4212 "name: \"forward2.proto\"" 4213 "dependency: \"forward.proto\" " 4214 "public_dependency: 0"); 4215 4216 BuildFileWithErrors( 4217 "name: \"foo.proto\" " 4218 "dependency: \"forward2.proto\" " 4219 "message_type {" 4220 " name: \"Foo\"" 4221 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4222 "}", 4223 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", " 4224 "which is not imported by \"foo.proto\". To use it here, please add the " 4225 "necessary import.\n"); 4226 } 4227 4228 4229 TEST_F(ValidationErrorTest, SearchMostLocalFirst) { 4230 // The following should produce an error that Bar.Baz is resolved but 4231 // not defined: 4232 // message Bar { message Baz {} } 4233 // message Foo { 4234 // message Bar { 4235 // // Placing "message Baz{}" here, or removing Foo.Bar altogether, 4236 // // would fix the error. 4237 // } 4238 // optional Bar.Baz baz = 1; 4239 // } 4240 // An one point the lookup code incorrectly did not produce an error in this 4241 // case, because when looking for Bar.Baz, it would try "Foo.Bar.Baz" first, 4242 // fail, and ten try "Bar.Baz" and succeed, even though "Bar" should actually 4243 // refer to the inner Bar, not the outer one. 4244 BuildFileWithErrors( 4245 "name: \"foo.proto\" " 4246 "message_type {" 4247 " name: \"Bar\"" 4248 " nested_type { name: \"Baz\" }" 4249 "}" 4250 "message_type {" 4251 " name: \"Foo\"" 4252 " nested_type { name: \"Bar\" }" 4253 " field { name:\"baz\" number:1 label:LABEL_OPTIONAL" 4254 " type_name:\"Bar.Baz\" }" 4255 "}", 4256 4257 "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is resolved to \"Foo.Bar.Baz\"," 4258 " which is not defined. The innermost scope is searched first in name " 4259 "resolution. Consider using a leading '.'(i.e., \".Bar.Baz\") to start " 4260 "from the outermost scope.\n"); 4261 } 4262 4263 TEST_F(ValidationErrorTest, SearchMostLocalFirst2) { 4264 // This test would find the most local "Bar" first, and does, but 4265 // proceeds to find the outer one because the inner one's not an 4266 // aggregate. 4267 BuildFile( 4268 "name: \"foo.proto\" " 4269 "message_type {" 4270 " name: \"Bar\"" 4271 " nested_type { name: \"Baz\" }" 4272 "}" 4273 "message_type {" 4274 " name: \"Foo\"" 4275 " field { name: \"Bar\" number:1 type:TYPE_BYTES } " 4276 " field { name:\"baz\" number:2 label:LABEL_OPTIONAL" 4277 " type_name:\"Bar.Baz\" }" 4278 "}"); 4279 } 4280 4281 TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) { 4282 // Imagine we have the following: 4283 // 4284 // foo.proto: 4285 // package foo.bar; 4286 // bar.proto: 4287 // package foo.bar; 4288 // import "foo.proto"; 4289 // message Bar {} 4290 // baz.proto: 4291 // package foo; 4292 // import "bar.proto" 4293 // message Baz { optional bar.Bar qux = 1; } 4294 // 4295 // When validating baz.proto, we will look up "bar.Bar". As part of this 4296 // lookup, we first lookup "bar" then try to find "Bar" within it. "bar" 4297 // should resolve to "foo.bar". Note, though, that "foo.bar" was originally 4298 // defined in foo.proto, which is not a direct dependency of baz.proto. The 4299 // implementation of FindSymbol() normally only returns symbols in direct 4300 // dependencies, not indirect ones. This test insures that this does not 4301 // prevent it from finding "foo.bar". 4302 4303 BuildFile( 4304 "name: \"foo.proto\" " 4305 "package: \"foo.bar\" "); 4306 BuildFile( 4307 "name: \"bar.proto\" " 4308 "package: \"foo.bar\" " 4309 "dependency: \"foo.proto\" " 4310 "message_type { name: \"Bar\" }"); 4311 BuildFile( 4312 "name: \"baz.proto\" " 4313 "package: \"foo\" " 4314 "dependency: \"bar.proto\" " 4315 "message_type { " 4316 " name: \"Baz\" " 4317 " field { name:\"qux\" number:1 label:LABEL_OPTIONAL " 4318 " type_name:\"bar.Bar\" }" 4319 "}"); 4320 } 4321 4322 TEST_F(ValidationErrorTest, FieldTypeNotAType) { 4323 BuildFileWithErrors( 4324 "name: \"foo.proto\" " 4325 "message_type {" 4326 " name: \"Foo\"" 4327 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL " 4328 " type_name:\".Foo.bar\" }" 4329 " field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" 4330 "}", 4331 4332 "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n"); 4333 } 4334 4335 TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) { 4336 BuildFileWithErrors( 4337 "name: \"foo.proto\" " 4338 "message_type {" 4339 " nested_type {" 4340 " name: \"Bar\"" 4341 " field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" 4342 " }" 4343 " name: \"Foo\"" 4344 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL " 4345 " type_name:\"Bar.Baz\" }" 4346 "}", 4347 "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n"); 4348 } 4349 4350 TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) { 4351 BuildFile( 4352 "name: \"foo.proto\" " 4353 "message_type {" 4354 " name: \"Bar\"" 4355 "}" 4356 "message_type {" 4357 " name: \"Foo\"" 4358 " field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" 4359 "}"); 4360 } 4361 4362 TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) { 4363 BuildFileWithErrors( 4364 "name: \"foo.proto\" " 4365 "message_type { name: \"Bar\" } " 4366 "message_type {" 4367 " name: \"Foo\"" 4368 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM" 4369 " type_name:\"Bar\" }" 4370 "}", 4371 4372 "foo.proto: Foo.foo: TYPE: \"Bar\" is not an enum type.\n"); 4373 } 4374 4375 TEST_F(ValidationErrorTest, MessageFieldTypeIsEnum) { 4376 BuildFileWithErrors( 4377 "name: \"foo.proto\" " 4378 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } " 4379 "message_type {" 4380 " name: \"Foo\"" 4381 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE" 4382 " type_name:\"Bar\" }" 4383 "}", 4384 4385 "foo.proto: Foo.foo: TYPE: \"Bar\" is not a message type.\n"); 4386 } 4387 4388 TEST_F(ValidationErrorTest, BadEnumDefaultValue) { 4389 BuildFileWithErrors( 4390 "name: \"foo.proto\" " 4391 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } " 4392 "message_type {" 4393 " name: \"Foo\"" 4394 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\"" 4395 " default_value:\"NO_SUCH_VALUE\" }" 4396 "}", 4397 4398 "foo.proto: Foo.foo: DEFAULT_VALUE: Enum type \"Bar\" has no value named " 4399 "\"NO_SUCH_VALUE\".\n"); 4400 } 4401 4402 TEST_F(ValidationErrorTest, EnumDefaultValueIsInteger) { 4403 BuildFileWithErrors( 4404 "name: \"foo.proto\" " 4405 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } " 4406 "message_type {" 4407 " name: \"Foo\"" 4408 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\"" 4409 " default_value:\"0\" }" 4410 "}", 4411 4412 "foo.proto: Foo.foo: DEFAULT_VALUE: Default value for an enum field must " 4413 "be an identifier.\n"); 4414 } 4415 4416 TEST_F(ValidationErrorTest, PrimitiveWithTypeName) { 4417 BuildFileWithErrors( 4418 "name: \"foo.proto\" " 4419 "message_type {" 4420 " name: \"Foo\"" 4421 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32" 4422 " type_name:\"Foo\" }" 4423 "}", 4424 4425 "foo.proto: Foo.foo: TYPE: Field with primitive type has type_name.\n"); 4426 } 4427 4428 TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) { 4429 BuildFileWithErrors( 4430 "name: \"foo.proto\" " 4431 "message_type {" 4432 " name: \"Foo\"" 4433 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE }" 4434 "}", 4435 4436 "foo.proto: Foo.foo: TYPE: Field with message or enum type missing " 4437 "type_name.\n"); 4438 } 4439 4440 TEST_F(ValidationErrorTest, OneofWithNoFields) { 4441 BuildFileWithErrors( 4442 "name: \"foo.proto\" " 4443 "message_type {" 4444 " name: \"Foo\"" 4445 " oneof_decl { name:\"bar\" }" 4446 "}", 4447 4448 "foo.proto: Foo.bar: NAME: Oneof must have at least one field.\n"); 4449 } 4450 4451 TEST_F(ValidationErrorTest, OneofLabelMismatch) { 4452 BuildFileWithErrors( 4453 "name: \"foo.proto\" " 4454 "message_type {" 4455 " name: \"Foo\"" 4456 " field { name:\"foo\" number:1 label:LABEL_REPEATED type:TYPE_INT32 " 4457 " oneof_index:0 }" 4458 " oneof_decl { name:\"bar\" }" 4459 "}", 4460 4461 "foo.proto: Foo.foo: NAME: Fields of oneofs must themselves have label " 4462 "LABEL_OPTIONAL.\n"); 4463 } 4464 4465 TEST_F(ValidationErrorTest, InputTypeNotDefined) { 4466 BuildFileWithErrors( 4467 "name: \"foo.proto\" " 4468 "message_type { name: \"Foo\" } " 4469 "service {" 4470 " name: \"TestService\"" 4471 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }" 4472 "}", 4473 4474 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n" 4475 ); 4476 } 4477 4478 TEST_F(ValidationErrorTest, InputTypeNotAMessage) { 4479 BuildFileWithErrors( 4480 "name: \"foo.proto\" " 4481 "message_type { name: \"Foo\" } " 4482 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } " 4483 "service {" 4484 " name: \"TestService\"" 4485 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }" 4486 "}", 4487 4488 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n" 4489 ); 4490 } 4491 4492 TEST_F(ValidationErrorTest, OutputTypeNotDefined) { 4493 BuildFileWithErrors( 4494 "name: \"foo.proto\" " 4495 "message_type { name: \"Foo\" } " 4496 "service {" 4497 " name: \"TestService\"" 4498 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }" 4499 "}", 4500 4501 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n" 4502 ); 4503 } 4504 4505 TEST_F(ValidationErrorTest, OutputTypeNotAMessage) { 4506 BuildFileWithErrors( 4507 "name: \"foo.proto\" " 4508 "message_type { name: \"Foo\" } " 4509 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } " 4510 "service {" 4511 " name: \"TestService\"" 4512 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }" 4513 "}", 4514 4515 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n" 4516 ); 4517 } 4518 4519 4520 TEST_F(ValidationErrorTest, IllegalPackedField) { 4521 BuildFileWithErrors( 4522 "name: \"foo.proto\" " 4523 "message_type {\n" 4524 " name: \"Foo\"" 4525 " field { name:\"packed_string\" number:1 label:LABEL_REPEATED " 4526 " type:TYPE_STRING " 4527 " options { uninterpreted_option {" 4528 " name { name_part: \"packed\" is_extension: false }" 4529 " identifier_value: \"true\" }}}\n" 4530 " field { name:\"packed_message\" number:3 label:LABEL_REPEATED " 4531 " type_name: \"Foo\"" 4532 " options { uninterpreted_option {" 4533 " name { name_part: \"packed\" is_extension: false }" 4534 " identifier_value: \"true\" }}}\n" 4535 " field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL " 4536 " type:TYPE_INT32 " 4537 " options { uninterpreted_option {" 4538 " name { name_part: \"packed\" is_extension: false }" 4539 " identifier_value: \"true\" }}}\n" 4540 "}", 4541 4542 "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be " 4543 "specified for repeated primitive fields.\n" 4544 "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be " 4545 "specified for repeated primitive fields.\n" 4546 "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be " 4547 "specified for repeated primitive fields.\n" 4548 ); 4549 } 4550 4551 TEST_F(ValidationErrorTest, OptionWrongType) { 4552 BuildFileWithErrors( 4553 "name: \"foo.proto\" " 4554 "message_type { " 4555 " name: \"TestMessage\" " 4556 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING " 4557 " options { uninterpreted_option { name { name_part: \"ctype\" " 4558 " is_extension: false }" 4559 " positive_int_value: 1 }" 4560 " }" 4561 " }" 4562 "}\n", 4563 4564 "foo.proto: TestMessage.foo: OPTION_VALUE: Value must be identifier for " 4565 "enum-valued option \"google.protobuf.FieldOptions.ctype\".\n"); 4566 } 4567 4568 TEST_F(ValidationErrorTest, OptionExtendsAtomicType) { 4569 BuildFileWithErrors( 4570 "name: \"foo.proto\" " 4571 "message_type { " 4572 " name: \"TestMessage\" " 4573 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING " 4574 " options { uninterpreted_option { name { name_part: \"ctype\" " 4575 " is_extension: false }" 4576 " name { name_part: \"foo\" " 4577 " is_extension: true }" 4578 " positive_int_value: 1 }" 4579 " }" 4580 " }" 4581 "}\n", 4582 4583 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" is an " 4584 "atomic type, not a message.\n"); 4585 } 4586 4587 TEST_F(ValidationErrorTest, DupOption) { 4588 BuildFileWithErrors( 4589 "name: \"foo.proto\" " 4590 "message_type { " 4591 " name: \"TestMessage\" " 4592 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32 " 4593 " options { uninterpreted_option { name { name_part: \"ctype\" " 4594 " is_extension: false }" 4595 " identifier_value: \"CORD\" }" 4596 " uninterpreted_option { name { name_part: \"ctype\" " 4597 " is_extension: false }" 4598 " identifier_value: \"CORD\" }" 4599 " }" 4600 " }" 4601 "}\n", 4602 4603 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" was " 4604 "already set.\n"); 4605 } 4606 4607 TEST_F(ValidationErrorTest, InvalidOptionName) { 4608 BuildFileWithErrors( 4609 "name: \"foo.proto\" " 4610 "message_type { " 4611 " name: \"TestMessage\" " 4612 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL " 4613 " options { uninterpreted_option { " 4614 " name { name_part: \"uninterpreted_option\" " 4615 " is_extension: false }" 4616 " positive_int_value: 1 " 4617 " }" 4618 " }" 4619 " }" 4620 "}\n", 4621 4622 "foo.proto: TestMessage.foo: OPTION_NAME: Option must not use " 4623 "reserved name \"uninterpreted_option\".\n"); 4624 } 4625 4626 TEST_F(ValidationErrorTest, RepeatedMessageOption) { 4627 BuildDescriptorMessagesInTestPool(); 4628 4629 BuildFileWithErrors( 4630 "name: \"foo.proto\" " 4631 "dependency: \"google/protobuf/descriptor.proto\" " 4632 "message_type: { name: \"Bar\" field: { " 4633 " name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } " 4634 "} " 4635 "extension { name: \"bar\" number: 7672757 label: LABEL_REPEATED " 4636 " type: TYPE_MESSAGE type_name: \"Bar\" " 4637 " extendee: \"google.protobuf.FileOptions\" }" 4638 "options { uninterpreted_option { name { name_part: \"bar\" " 4639 " is_extension: true } " 4640 " name { name_part: \"foo\" " 4641 " is_extension: false } " 4642 " positive_int_value: 1 } }", 4643 4644 "foo.proto: foo.proto: OPTION_NAME: Option field \"(bar)\" is a " 4645 "repeated message. Repeated message options must be initialized " 4646 "using an aggregate value.\n"); 4647 } 4648 4649 TEST_F(ValidationErrorTest, ResolveUndefinedOption) { 4650 // The following should produce an eror that baz.bar is resolved but not 4651 // defined. 4652 // foo.proto: 4653 // package baz 4654 // import google/protobuf/descriptor.proto 4655 // message Bar { optional int32 foo = 1; } 4656 // extend FileOptions { optional Bar bar = 7672757; } 4657 // 4658 // qux.proto: 4659 // package qux.baz 4660 // option (baz.bar).foo = 1; 4661 // 4662 // Although "baz.bar" is already defined, the lookup code will try 4663 // "qux.baz.bar", since it's the match from the innermost scope, which will 4664 // cause a symbol not defined error. 4665 BuildDescriptorMessagesInTestPool(); 4666 4667 BuildFile( 4668 "name: \"foo.proto\" " 4669 "package: \"baz\" " 4670 "dependency: \"google/protobuf/descriptor.proto\" " 4671 "message_type: { name: \"Bar\" field: { " 4672 " name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } " 4673 "} " 4674 "extension { name: \"bar\" number: 7672757 label: LABEL_OPTIONAL " 4675 " type: TYPE_MESSAGE type_name: \"Bar\" " 4676 " extendee: \"google.protobuf.FileOptions\" }"); 4677 4678 BuildFileWithErrors( 4679 "name: \"qux.proto\" " 4680 "package: \"qux.baz\" " 4681 "options { uninterpreted_option { name { name_part: \"baz.bar\" " 4682 " is_extension: true } " 4683 " name { name_part: \"foo\" " 4684 " is_extension: false } " 4685 " positive_int_value: 1 } }", 4686 4687 "qux.proto: qux.proto: OPTION_NAME: Option \"(baz.bar)\" is resolved to " 4688 "\"(qux.baz.bar)\"," 4689 " which is not defined. The innermost scope is searched first in name " 4690 "resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\") to start " 4691 "from the outermost scope.\n"); 4692 } 4693 4694 TEST_F(ValidationErrorTest, UnknownOption) { 4695 BuildFileWithErrors( 4696 "name: \"qux.proto\" " 4697 "package: \"qux.baz\" " 4698 "options { uninterpreted_option { name { name_part: \"baaz.bar\" " 4699 " is_extension: true } " 4700 " name { name_part: \"foo\" " 4701 " is_extension: false } " 4702 " positive_int_value: 1 } }", 4703 4704 "qux.proto: qux.proto: OPTION_NAME: Option \"(baaz.bar)\" unknown.\n"); 4705 } 4706 4707 TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) { 4708 BuildDescriptorMessagesInTestPool(); 4709 4710 BuildFileWithErrors( 4711 "name: \"foo.proto\" " 4712 "dependency: \"google/protobuf/descriptor.proto\" " 4713 "extension { name: \"foo1\" number: 7672757 label: LABEL_OPTIONAL " 4714 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }" 4715 "extension { name: \"foo2\" number: 7672757 label: LABEL_OPTIONAL " 4716 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }", 4717 4718 "foo.proto: foo2: NUMBER: Extension number 7672757 has already been used " 4719 "in \"google.protobuf.FieldOptions\" by extension \"foo1\".\n"); 4720 } 4721 4722 TEST_F(ValidationErrorTest, Int32OptionValueOutOfPositiveRange) { 4723 BuildDescriptorMessagesInTestPool(); 4724 4725 BuildFileWithErrors( 4726 "name: \"foo.proto\" " 4727 "dependency: \"google/protobuf/descriptor.proto\" " 4728 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4729 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }" 4730 "options { uninterpreted_option { name { name_part: \"foo\" " 4731 " is_extension: true } " 4732 " positive_int_value: 0x80000000 } " 4733 "}", 4734 4735 "foo.proto: foo.proto: OPTION_VALUE: Value out of range " 4736 "for int32 option \"foo\".\n"); 4737 } 4738 4739 TEST_F(ValidationErrorTest, Int32OptionValueOutOfNegativeRange) { 4740 BuildDescriptorMessagesInTestPool(); 4741 4742 BuildFileWithErrors( 4743 "name: \"foo.proto\" " 4744 "dependency: \"google/protobuf/descriptor.proto\" " 4745 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4746 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }" 4747 "options { uninterpreted_option { name { name_part: \"foo\" " 4748 " is_extension: true } " 4749 " negative_int_value: -0x80000001 } " 4750 "}", 4751 4752 "foo.proto: foo.proto: OPTION_VALUE: Value out of range " 4753 "for int32 option \"foo\".\n"); 4754 } 4755 4756 TEST_F(ValidationErrorTest, Int32OptionValueIsNotPositiveInt) { 4757 BuildDescriptorMessagesInTestPool(); 4758 4759 BuildFileWithErrors( 4760 "name: \"foo.proto\" " 4761 "dependency: \"google/protobuf/descriptor.proto\" " 4762 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4763 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }" 4764 "options { uninterpreted_option { name { name_part: \"foo\" " 4765 " is_extension: true } " 4766 " string_value: \"5\" } }", 4767 4768 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer " 4769 "for int32 option \"foo\".\n"); 4770 } 4771 4772 TEST_F(ValidationErrorTest, Int64OptionValueOutOfRange) { 4773 BuildDescriptorMessagesInTestPool(); 4774 4775 BuildFileWithErrors( 4776 "name: \"foo.proto\" " 4777 "dependency: \"google/protobuf/descriptor.proto\" " 4778 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4779 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }" 4780 "options { uninterpreted_option { name { name_part: \"foo\" " 4781 " is_extension: true } " 4782 " positive_int_value: 0x8000000000000000 } " 4783 "}", 4784 4785 "foo.proto: foo.proto: OPTION_VALUE: Value out of range " 4786 "for int64 option \"foo\".\n"); 4787 } 4788 4789 TEST_F(ValidationErrorTest, Int64OptionValueIsNotPositiveInt) { 4790 BuildDescriptorMessagesInTestPool(); 4791 4792 BuildFileWithErrors( 4793 "name: \"foo.proto\" " 4794 "dependency: \"google/protobuf/descriptor.proto\" " 4795 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4796 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }" 4797 "options { uninterpreted_option { name { name_part: \"foo\" " 4798 " is_extension: true } " 4799 " identifier_value: \"5\" } }", 4800 4801 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer " 4802 "for int64 option \"foo\".\n"); 4803 } 4804 4805 TEST_F(ValidationErrorTest, UInt32OptionValueOutOfRange) { 4806 BuildDescriptorMessagesInTestPool(); 4807 4808 BuildFileWithErrors( 4809 "name: \"foo.proto\" " 4810 "dependency: \"google/protobuf/descriptor.proto\" " 4811 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4812 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }" 4813 "options { uninterpreted_option { name { name_part: \"foo\" " 4814 " is_extension: true } " 4815 " positive_int_value: 0x100000000 } }", 4816 4817 "foo.proto: foo.proto: OPTION_VALUE: Value out of range " 4818 "for uint32 option \"foo\".\n"); 4819 } 4820 4821 TEST_F(ValidationErrorTest, UInt32OptionValueIsNotPositiveInt) { 4822 BuildDescriptorMessagesInTestPool(); 4823 4824 BuildFileWithErrors( 4825 "name: \"foo.proto\" " 4826 "dependency: \"google/protobuf/descriptor.proto\" " 4827 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4828 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }" 4829 "options { uninterpreted_option { name { name_part: \"foo\" " 4830 " is_extension: true } " 4831 " double_value: -5.6 } }", 4832 4833 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer " 4834 "for uint32 option \"foo\".\n"); 4835 } 4836 4837 TEST_F(ValidationErrorTest, UInt64OptionValueIsNotPositiveInt) { 4838 BuildDescriptorMessagesInTestPool(); 4839 4840 BuildFileWithErrors( 4841 "name: \"foo.proto\" " 4842 "dependency: \"google/protobuf/descriptor.proto\" " 4843 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4844 " type: TYPE_UINT64 extendee: \"google.protobuf.FileOptions\" }" 4845 "options { uninterpreted_option { name { name_part: \"foo\" " 4846 " is_extension: true } " 4847 " negative_int_value: -5 } }", 4848 4849 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer " 4850 "for uint64 option \"foo\".\n"); 4851 } 4852 4853 TEST_F(ValidationErrorTest, FloatOptionValueIsNotNumber) { 4854 BuildDescriptorMessagesInTestPool(); 4855 4856 BuildFileWithErrors( 4857 "name: \"foo.proto\" " 4858 "dependency: \"google/protobuf/descriptor.proto\" " 4859 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4860 " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }" 4861 "options { uninterpreted_option { name { name_part: \"foo\" " 4862 " is_extension: true } " 4863 " string_value: \"bar\" } }", 4864 4865 "foo.proto: foo.proto: OPTION_VALUE: Value must be number " 4866 "for float option \"foo\".\n"); 4867 } 4868 4869 TEST_F(ValidationErrorTest, DoubleOptionValueIsNotNumber) { 4870 BuildDescriptorMessagesInTestPool(); 4871 4872 BuildFileWithErrors( 4873 "name: \"foo.proto\" " 4874 "dependency: \"google/protobuf/descriptor.proto\" " 4875 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4876 " type: TYPE_DOUBLE extendee: \"google.protobuf.FileOptions\" }" 4877 "options { uninterpreted_option { name { name_part: \"foo\" " 4878 " is_extension: true } " 4879 " string_value: \"bar\" } }", 4880 4881 "foo.proto: foo.proto: OPTION_VALUE: Value must be number " 4882 "for double option \"foo\".\n"); 4883 } 4884 4885 TEST_F(ValidationErrorTest, BoolOptionValueIsNotTrueOrFalse) { 4886 BuildDescriptorMessagesInTestPool(); 4887 4888 BuildFileWithErrors( 4889 "name: \"foo.proto\" " 4890 "dependency: \"google/protobuf/descriptor.proto\" " 4891 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4892 " type: TYPE_BOOL extendee: \"google.protobuf.FileOptions\" }" 4893 "options { uninterpreted_option { name { name_part: \"foo\" " 4894 " is_extension: true } " 4895 " identifier_value: \"bar\" } }", 4896 4897 "foo.proto: foo.proto: OPTION_VALUE: Value must be \"true\" or \"false\" " 4898 "for boolean option \"foo\".\n"); 4899 } 4900 4901 TEST_F(ValidationErrorTest, EnumOptionValueIsNotIdentifier) { 4902 BuildDescriptorMessagesInTestPool(); 4903 4904 BuildFileWithErrors( 4905 "name: \"foo.proto\" " 4906 "dependency: \"google/protobuf/descriptor.proto\" " 4907 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } " 4908 " value { name: \"BAZ\" number: 2 } }" 4909 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4910 " type: TYPE_ENUM type_name: \"FooEnum\" " 4911 " extendee: \"google.protobuf.FileOptions\" }" 4912 "options { uninterpreted_option { name { name_part: \"foo\" " 4913 " is_extension: true } " 4914 " string_value: \"QUUX\" } }", 4915 4916 "foo.proto: foo.proto: OPTION_VALUE: Value must be identifier for " 4917 "enum-valued option \"foo\".\n"); 4918 } 4919 4920 TEST_F(ValidationErrorTest, EnumOptionValueIsNotEnumValueName) { 4921 BuildDescriptorMessagesInTestPool(); 4922 4923 BuildFileWithErrors( 4924 "name: \"foo.proto\" " 4925 "dependency: \"google/protobuf/descriptor.proto\" " 4926 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } " 4927 " value { name: \"BAZ\" number: 2 } }" 4928 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4929 " type: TYPE_ENUM type_name: \"FooEnum\" " 4930 " extendee: \"google.protobuf.FileOptions\" }" 4931 "options { uninterpreted_option { name { name_part: \"foo\" " 4932 " is_extension: true } " 4933 " identifier_value: \"QUUX\" } }", 4934 4935 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum\" has no value " 4936 "named \"QUUX\" for option \"foo\".\n"); 4937 } 4938 4939 TEST_F(ValidationErrorTest, EnumOptionValueIsSiblingEnumValueName) { 4940 BuildDescriptorMessagesInTestPool(); 4941 4942 BuildFileWithErrors( 4943 "name: \"foo.proto\" " 4944 "dependency: \"google/protobuf/descriptor.proto\" " 4945 "enum_type { name: \"FooEnum1\" value { name: \"BAR\" number: 1 } " 4946 " value { name: \"BAZ\" number: 2 } }" 4947 "enum_type { name: \"FooEnum2\" value { name: \"QUX\" number: 1 } " 4948 " value { name: \"QUUX\" number: 2 } }" 4949 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4950 " type: TYPE_ENUM type_name: \"FooEnum1\" " 4951 " extendee: \"google.protobuf.FileOptions\" }" 4952 "options { uninterpreted_option { name { name_part: \"foo\" " 4953 " is_extension: true } " 4954 " identifier_value: \"QUUX\" } }", 4955 4956 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum1\" has no value " 4957 "named \"QUUX\" for option \"foo\". This appears to be a value from a " 4958 "sibling type.\n"); 4959 } 4960 4961 TEST_F(ValidationErrorTest, StringOptionValueIsNotString) { 4962 BuildDescriptorMessagesInTestPool(); 4963 4964 BuildFileWithErrors( 4965 "name: \"foo.proto\" " 4966 "dependency: \"google/protobuf/descriptor.proto\" " 4967 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 4968 " type: TYPE_STRING extendee: \"google.protobuf.FileOptions\" }" 4969 "options { uninterpreted_option { name { name_part: \"foo\" " 4970 " is_extension: true } " 4971 " identifier_value: \"QUUX\" } }", 4972 4973 "foo.proto: foo.proto: OPTION_VALUE: Value must be quoted string for " 4974 "string option \"foo\".\n"); 4975 } 4976 4977 TEST_F(ValidationErrorTest, DuplicateExtensionFieldNumber) { 4978 BuildDescriptorMessagesInTestPool(); 4979 4980 BuildFile( 4981 "name: \"foo.proto\" " 4982 "dependency: \"google/protobuf/descriptor.proto\" " 4983 "extension { name: \"option1\" number: 1000 label: LABEL_OPTIONAL " 4984 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"); 4985 4986 BuildFileWithWarnings( 4987 "name: \"bar.proto\" " 4988 "dependency: \"google/protobuf/descriptor.proto\" " 4989 "extension { name: \"option2\" number: 1000 label: LABEL_OPTIONAL " 4990 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }", 4991 "bar.proto: option2: NUMBER: Extension number 1000 has already been used " 4992 "in \"google.protobuf.FileOptions\" by extension \"option1\" defined in " 4993 "foo.proto.\n"); 4994 } 4995 4996 // Helper function for tests that check for aggregate value parsing 4997 // errors. The "value" argument is embedded inside the 4998 // "uninterpreted_option" portion of the result. 4999 static string EmbedAggregateValue(const char* value) { 5000 return strings::Substitute( 5001 "name: \"foo.proto\" " 5002 "dependency: \"google/protobuf/descriptor.proto\" " 5003 "message_type { name: \"Foo\" } " 5004 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL " 5005 " type: TYPE_MESSAGE type_name: \"Foo\" " 5006 " extendee: \"google.protobuf.FileOptions\" }" 5007 "options { uninterpreted_option { name { name_part: \"foo\" " 5008 " is_extension: true } " 5009 " $0 } }", 5010 value); 5011 } 5012 5013 TEST_F(ValidationErrorTest, AggregateValueNotFound) { 5014 BuildDescriptorMessagesInTestPool(); 5015 5016 BuildFileWithErrors( 5017 EmbedAggregateValue("string_value: \"\""), 5018 "foo.proto: foo.proto: OPTION_VALUE: Option \"foo\" is a message. " 5019 "To set the entire message, use syntax like " 5020 "\"foo = { <proto text format> }\". To set fields within it, use " 5021 "syntax like \"foo.foo = value\".\n"); 5022 } 5023 5024 TEST_F(ValidationErrorTest, AggregateValueParseError) { 5025 BuildDescriptorMessagesInTestPool(); 5026 5027 BuildFileWithErrors( 5028 EmbedAggregateValue("aggregate_value: \"1+2\""), 5029 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option " 5030 "value for \"foo\": Expected identifier.\n"); 5031 } 5032 5033 TEST_F(ValidationErrorTest, AggregateValueUnknownFields) { 5034 BuildDescriptorMessagesInTestPool(); 5035 5036 BuildFileWithErrors( 5037 EmbedAggregateValue("aggregate_value: \"x:100\""), 5038 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option " 5039 "value for \"foo\": Message type \"Foo\" has no field named \"x\".\n"); 5040 } 5041 5042 TEST_F(ValidationErrorTest, NotLiteImportsLite) { 5043 BuildFile( 5044 "name: \"bar.proto\" " 5045 "options { optimize_for: LITE_RUNTIME } "); 5046 5047 BuildFileWithErrors( 5048 "name: \"foo.proto\" " 5049 "dependency: \"bar.proto\" ", 5050 5051 "foo.proto: foo.proto: OTHER: Files that do not use optimize_for = " 5052 "LITE_RUNTIME cannot import files which do use this option. This file " 5053 "is not lite, but it imports \"bar.proto\" which is.\n"); 5054 } 5055 5056 TEST_F(ValidationErrorTest, LiteExtendsNotLite) { 5057 BuildFile( 5058 "name: \"bar.proto\" " 5059 "message_type: {" 5060 " name: \"Bar\"" 5061 " extension_range { start: 1 end: 1000 }" 5062 "}"); 5063 5064 BuildFileWithErrors( 5065 "name: \"foo.proto\" " 5066 "dependency: \"bar.proto\" " 5067 "options { optimize_for: LITE_RUNTIME } " 5068 "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL " 5069 " type: TYPE_INT32 extendee: \"Bar\" }", 5070 5071 "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be " 5072 "declared in non-lite files. Note that you cannot extend a non-lite " 5073 "type to contain a lite type, but the reverse is allowed.\n"); 5074 } 5075 5076 TEST_F(ValidationErrorTest, NoLiteServices) { 5077 BuildFileWithErrors( 5078 "name: \"foo.proto\" " 5079 "options {" 5080 " optimize_for: LITE_RUNTIME" 5081 " cc_generic_services: true" 5082 " java_generic_services: true" 5083 "} " 5084 "service { name: \"Foo\" }", 5085 5086 "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot " 5087 "define services unless you set both options cc_generic_services and " 5088 "java_generic_sevices to false.\n"); 5089 5090 BuildFile( 5091 "name: \"bar.proto\" " 5092 "options {" 5093 " optimize_for: LITE_RUNTIME" 5094 " cc_generic_services: false" 5095 " java_generic_services: false" 5096 "} " 5097 "service { name: \"Bar\" }"); 5098 } 5099 5100 TEST_F(ValidationErrorTest, RollbackAfterError) { 5101 // Build a file which contains every kind of construct but references an 5102 // undefined type. All these constructs will be added to the symbol table 5103 // before the undefined type error is noticed. The DescriptorPool will then 5104 // have to roll everything back. 5105 BuildFileWithErrors( 5106 "name: \"foo.proto\" " 5107 "message_type {" 5108 " name: \"TestMessage\"" 5109 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }" 5110 "} " 5111 "enum_type {" 5112 " name: \"TestEnum\"" 5113 " value { name:\"BAR\" number:1 }" 5114 "} " 5115 "service {" 5116 " name: \"TestService\"" 5117 " method {" 5118 " name: \"Baz\"" 5119 " input_type: \"NoSuchType\"" // error 5120 " output_type: \"TestMessage\"" 5121 " }" 5122 "}", 5123 5124 "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n" 5125 ); 5126 5127 // Make sure that if we build the same file again with the error fixed, 5128 // it works. If the above rollback was incomplete, then some symbols will 5129 // be left defined, and this second attempt will fail since it tries to 5130 // re-define the same symbols. 5131 BuildFile( 5132 "name: \"foo.proto\" " 5133 "message_type {" 5134 " name: \"TestMessage\"" 5135 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }" 5136 "} " 5137 "enum_type {" 5138 " name: \"TestEnum\"" 5139 " value { name:\"BAR\" number:1 }" 5140 "} " 5141 "service {" 5142 " name: \"TestService\"" 5143 " method { name:\"Baz\"" 5144 " input_type:\"TestMessage\"" 5145 " output_type:\"TestMessage\" }" 5146 "}"); 5147 } 5148 5149 TEST_F(ValidationErrorTest, ErrorsReportedToLogError) { 5150 // Test that errors are reported to GOOGLE_LOG(ERROR) if no error collector is 5151 // provided. 5152 5153 FileDescriptorProto file_proto; 5154 ASSERT_TRUE(TextFormat::ParseFromString( 5155 "name: \"foo.proto\" " 5156 "message_type { name: \"Foo\" } " 5157 "message_type { name: \"Foo\" } ", 5158 &file_proto)); 5159 5160 vector<string> errors; 5161 5162 { 5163 ScopedMemoryLog log; 5164 EXPECT_TRUE(pool_.BuildFile(file_proto) == NULL); 5165 errors = log.GetMessages(ERROR); 5166 } 5167 5168 ASSERT_EQ(2, errors.size()); 5169 5170 EXPECT_EQ("Invalid proto descriptor for file \"foo.proto\":", errors[0]); 5171 EXPECT_EQ(" Foo: \"Foo\" is already defined.", errors[1]); 5172 } 5173 5174 TEST_F(ValidationErrorTest, DisallowEnumAlias) { 5175 BuildFileWithErrors( 5176 "name: \"foo.proto\" " 5177 "enum_type {" 5178 " name: \"Bar\"" 5179 " value { name:\"ENUM_A\" number:0 }" 5180 " value { name:\"ENUM_B\" number:0 }" 5181 "}", 5182 "foo.proto: Bar: NUMBER: " 5183 "\"ENUM_B\" uses the same enum value as \"ENUM_A\". " 5184 "If this is intended, set 'option allow_alias = true;' to the enum " 5185 "definition.\n"); 5186 } 5187 5188 TEST_F(ValidationErrorTest, AllowEnumAlias) { 5189 BuildFile( 5190 "name: \"foo.proto\" " 5191 "enum_type {" 5192 " name: \"Bar\"" 5193 " value { name:\"ENUM_A\" number:0 }" 5194 " value { name:\"ENUM_B\" number:0 }" 5195 " options { allow_alias: true }" 5196 "}"); 5197 } 5198 5199 TEST_F(ValidationErrorTest, UnusedImportWarning) { 5200 pool_.AddUnusedImportTrackFile("bar.proto"); 5201 BuildFile( 5202 "name: \"bar.proto\" " 5203 "message_type { name: \"Bar\" }"); 5204 5205 pool_.AddUnusedImportTrackFile("base.proto"); 5206 BuildFile( 5207 "name: \"base.proto\" " 5208 "message_type { name: \"Base\" }"); 5209 5210 pool_.AddUnusedImportTrackFile("baz.proto"); 5211 BuildFile( 5212 "name: \"baz.proto\" " 5213 "message_type { name: \"Baz\" }"); 5214 5215 pool_.AddUnusedImportTrackFile("public.proto"); 5216 BuildFile( 5217 "name: \"public.proto\" " 5218 "dependency: \"bar.proto\"" 5219 "public_dependency: 0"); 5220 5221 // // forward.proto 5222 // import "base.proto" // No warning: Base message is used. 5223 // import "bar.proto" // Will log a warning. 5224 // import public "baz.proto" // No warning: Do not track import public. 5225 // import "public.proto" // No warning: public.proto has import public. 5226 // message Forward { 5227 // optional Base base = 1; 5228 // } 5229 // 5230 pool_.AddUnusedImportTrackFile("forward.proto"); 5231 BuildFileWithWarnings( 5232 "name: \"forward.proto\"" 5233 "dependency: \"base.proto\"" 5234 "dependency: \"bar.proto\"" 5235 "dependency: \"baz.proto\"" 5236 "dependency: \"public.proto\"" 5237 "public_dependency: 2 " 5238 "message_type {" 5239 " name: \"Forward\"" 5240 " field { name:\"base\" number:1 label:LABEL_OPTIONAL type_name:\"Base\" }" 5241 "}", 5242 "forward.proto: bar.proto: OTHER: Import bar.proto but not used.\n"); 5243 } 5244 5245 namespace { 5246 void FillValidMapEntry(FileDescriptorProto* file_proto) { 5247 ASSERT_TRUE(TextFormat::ParseFromString( 5248 "name: 'foo.proto' " 5249 "message_type { " 5250 " name: 'Foo' " 5251 " field { " 5252 " name: 'foo_map' number: 1 label:LABEL_REPEATED " 5253 " type_name: 'FooMapEntry' " 5254 " } " 5255 " nested_type { " 5256 " name: 'FooMapEntry' " 5257 " options { map_entry: true } " 5258 " field { " 5259 " name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL " 5260 " } " 5261 " field { " 5262 " name: 'value' number: 2 type:TYPE_INT32 label:LABEL_OPTIONAL " 5263 " } " 5264 " } " 5265 "} " 5266 "message_type { " 5267 " name: 'Bar' " 5268 " extension_range { start: 1 end: 10 }" 5269 "} ", 5270 file_proto)); 5271 } 5272 static const char* kMapEntryErrorMessage = 5273 "foo.proto: Foo.foo_map: OTHER: map_entry should not be set explicitly. " 5274 "Use map<KeyType, ValueType> instead.\n"; 5275 static const char* kMapEntryKeyTypeErrorMessage = 5276 "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot be float/double, " 5277 "bytes or message types.\n"; 5278 5279 } // namespace 5280 5281 TEST_F(ValidationErrorTest, MapEntryBase) { 5282 FileDescriptorProto file_proto; 5283 FillValidMapEntry(&file_proto); 5284 BuildFile(file_proto.DebugString()); 5285 } 5286 5287 TEST_F(ValidationErrorTest, MapEntryExtensionRange) { 5288 FileDescriptorProto file_proto; 5289 FillValidMapEntry(&file_proto); 5290 TextFormat::MergeFromString( 5291 "extension_range { " 5292 " start: 10 end: 20 " 5293 "} ", 5294 file_proto.mutable_message_type(0)->mutable_nested_type(0)); 5295 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5296 } 5297 5298 TEST_F(ValidationErrorTest, MapEntryExtension) { 5299 FileDescriptorProto file_proto; 5300 FillValidMapEntry(&file_proto); 5301 TextFormat::MergeFromString( 5302 "extension { " 5303 " name: 'foo_ext' extendee: '.Bar' number: 5" 5304 "} ", 5305 file_proto.mutable_message_type(0)->mutable_nested_type(0)); 5306 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5307 } 5308 5309 TEST_F(ValidationErrorTest, MapEntryNestedType) { 5310 FileDescriptorProto file_proto; 5311 FillValidMapEntry(&file_proto); 5312 TextFormat::MergeFromString( 5313 "nested_type { " 5314 " name: 'Bar' " 5315 "} ", 5316 file_proto.mutable_message_type(0)->mutable_nested_type(0)); 5317 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5318 } 5319 5320 TEST_F(ValidationErrorTest, MapEntryEnumTypes) { 5321 FileDescriptorProto file_proto; 5322 FillValidMapEntry(&file_proto); 5323 TextFormat::MergeFromString( 5324 "enum_type { " 5325 " name: 'BarEnum' " 5326 " value { name: 'BAR_BAR' number:0 } " 5327 "} ", 5328 file_proto.mutable_message_type(0)->mutable_nested_type(0)); 5329 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5330 } 5331 5332 TEST_F(ValidationErrorTest, MapEntryExtraField) { 5333 FileDescriptorProto file_proto; 5334 FillValidMapEntry(&file_proto); 5335 TextFormat::MergeFromString( 5336 "field { " 5337 " name: 'other_field' " 5338 " label: LABEL_OPTIONAL " 5339 " type: TYPE_INT32 " 5340 " number: 3 " 5341 "} ", 5342 file_proto.mutable_message_type(0)->mutable_nested_type(0)); 5343 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5344 } 5345 5346 TEST_F(ValidationErrorTest, MapEntryMessageName) { 5347 FileDescriptorProto file_proto; 5348 FillValidMapEntry(&file_proto); 5349 file_proto.mutable_message_type(0)->mutable_nested_type(0)->set_name( 5350 "OtherMapEntry"); 5351 file_proto.mutable_message_type(0)->mutable_field(0)->set_type_name( 5352 "OtherMapEntry"); 5353 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5354 } 5355 5356 TEST_F(ValidationErrorTest, MapEntryNoneRepeatedMapEntry) { 5357 FileDescriptorProto file_proto; 5358 FillValidMapEntry(&file_proto); 5359 file_proto.mutable_message_type(0)->mutable_field(0)->set_label( 5360 FieldDescriptorProto::LABEL_OPTIONAL); 5361 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5362 } 5363 5364 TEST_F(ValidationErrorTest, MapEntryDifferentContainingType) { 5365 FileDescriptorProto file_proto; 5366 FillValidMapEntry(&file_proto); 5367 // Move the nested MapEntry message into the top level, which should not pass 5368 // the validation. 5369 file_proto.mutable_message_type()->AddAllocated( 5370 file_proto.mutable_message_type(0)->mutable_nested_type()->ReleaseLast()); 5371 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5372 } 5373 5374 TEST_F(ValidationErrorTest, MapEntryKeyName) { 5375 FileDescriptorProto file_proto; 5376 FillValidMapEntry(&file_proto); 5377 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5378 ->mutable_nested_type(0) 5379 ->mutable_field(0); 5380 key->set_name("Key"); 5381 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5382 } 5383 5384 TEST_F(ValidationErrorTest, MapEntryKeyLabel) { 5385 FileDescriptorProto file_proto; 5386 FillValidMapEntry(&file_proto); 5387 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5388 ->mutable_nested_type(0) 5389 ->mutable_field(0); 5390 key->set_label(FieldDescriptorProto::LABEL_REQUIRED); 5391 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5392 } 5393 5394 TEST_F(ValidationErrorTest, MapEntryKeyNumber) { 5395 FileDescriptorProto file_proto; 5396 FillValidMapEntry(&file_proto); 5397 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5398 ->mutable_nested_type(0) 5399 ->mutable_field(0); 5400 key->set_number(3); 5401 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5402 } 5403 5404 TEST_F(ValidationErrorTest, MapEntryValueName) { 5405 FileDescriptorProto file_proto; 5406 FillValidMapEntry(&file_proto); 5407 FieldDescriptorProto* value = file_proto.mutable_message_type(0) 5408 ->mutable_nested_type(0) 5409 ->mutable_field(1); 5410 value->set_name("Value"); 5411 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5412 } 5413 5414 TEST_F(ValidationErrorTest, MapEntryValueLabel) { 5415 FileDescriptorProto file_proto; 5416 FillValidMapEntry(&file_proto); 5417 FieldDescriptorProto* value = file_proto.mutable_message_type(0) 5418 ->mutable_nested_type(0) 5419 ->mutable_field(1); 5420 value->set_label(FieldDescriptorProto::LABEL_REQUIRED); 5421 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5422 } 5423 5424 TEST_F(ValidationErrorTest, MapEntryValueNumber) { 5425 FileDescriptorProto file_proto; 5426 FillValidMapEntry(&file_proto); 5427 FieldDescriptorProto* value = file_proto.mutable_message_type(0) 5428 ->mutable_nested_type(0) 5429 ->mutable_field(1); 5430 value->set_number(3); 5431 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); 5432 } 5433 5434 TEST_F(ValidationErrorTest, MapEntryKeyTypeFloat) { 5435 FileDescriptorProto file_proto; 5436 FillValidMapEntry(&file_proto); 5437 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5438 ->mutable_nested_type(0) 5439 ->mutable_field(0); 5440 key->set_type(FieldDescriptorProto::TYPE_FLOAT); 5441 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); 5442 } 5443 5444 TEST_F(ValidationErrorTest, MapEntryKeyTypeDouble) { 5445 FileDescriptorProto file_proto; 5446 FillValidMapEntry(&file_proto); 5447 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5448 ->mutable_nested_type(0) 5449 ->mutable_field(0); 5450 key->set_type(FieldDescriptorProto::TYPE_DOUBLE); 5451 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); 5452 } 5453 5454 TEST_F(ValidationErrorTest, MapEntryKeyTypeBytes) { 5455 FileDescriptorProto file_proto; 5456 FillValidMapEntry(&file_proto); 5457 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5458 ->mutable_nested_type(0) 5459 ->mutable_field(0); 5460 key->set_type(FieldDescriptorProto::TYPE_BYTES); 5461 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); 5462 } 5463 5464 TEST_F(ValidationErrorTest, MapEntryKeyTypeEnum) { 5465 FileDescriptorProto file_proto; 5466 FillValidMapEntry(&file_proto); 5467 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5468 ->mutable_nested_type(0) 5469 ->mutable_field(0); 5470 key->clear_type(); 5471 key->set_type_name("BarEnum"); 5472 EnumDescriptorProto* enum_proto = file_proto.add_enum_type(); 5473 enum_proto->set_name("BarEnum"); 5474 EnumValueDescriptorProto* enum_value_proto = enum_proto->add_value(); 5475 enum_value_proto->set_name("BAR_VALUE0"); 5476 enum_value_proto->set_number(0); 5477 BuildFileWithErrors(file_proto.DebugString(), 5478 "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot " 5479 "be enum types.\n"); 5480 // Enum keys are not allowed in proto3 as well. 5481 // Get rid of extensions for proto3 to make it proto3 compatible. 5482 file_proto.mutable_message_type()->RemoveLast(); 5483 file_proto.set_syntax("proto3"); 5484 BuildFileWithErrors(file_proto.DebugString(), 5485 "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot " 5486 "be enum types.\n"); 5487 } 5488 5489 5490 TEST_F(ValidationErrorTest, MapEntryKeyTypeMessage) { 5491 FileDescriptorProto file_proto; 5492 FillValidMapEntry(&file_proto); 5493 FieldDescriptorProto* key = file_proto.mutable_message_type(0) 5494 ->mutable_nested_type(0) 5495 ->mutable_field(0); 5496 key->clear_type(); 5497 key->set_type_name(".Bar"); 5498 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); 5499 } 5500 5501 TEST_F(ValidationErrorTest, MapEntryConflictsWithField) { 5502 FileDescriptorProto file_proto; 5503 FillValidMapEntry(&file_proto); 5504 TextFormat::MergeFromString( 5505 "field { " 5506 " name: 'FooMapEntry' " 5507 " type: TYPE_INT32 " 5508 " label: LABEL_OPTIONAL " 5509 " number: 100 " 5510 "}", 5511 file_proto.mutable_message_type(0)); 5512 BuildFileWithErrors( 5513 file_proto.DebugString(), 5514 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " 5515 "\"Foo\".\n" 5516 "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n" 5517 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " 5518 "with an existing field.\n"); 5519 } 5520 5521 TEST_F(ValidationErrorTest, MapEntryConflictsWithMessage) { 5522 FileDescriptorProto file_proto; 5523 FillValidMapEntry(&file_proto); 5524 TextFormat::MergeFromString( 5525 "nested_type { " 5526 " name: 'FooMapEntry' " 5527 "}", 5528 file_proto.mutable_message_type(0)); 5529 BuildFileWithErrors( 5530 file_proto.DebugString(), 5531 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " 5532 "\"Foo\".\n" 5533 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " 5534 "with an existing nested message type.\n"); 5535 } 5536 5537 TEST_F(ValidationErrorTest, MapEntryConflictsWithEnum) { 5538 FileDescriptorProto file_proto; 5539 FillValidMapEntry(&file_proto); 5540 TextFormat::MergeFromString( 5541 "enum_type { " 5542 " name: 'FooMapEntry' " 5543 " value { name: 'ENTRY_FOO' number: 0 }" 5544 "}", 5545 file_proto.mutable_message_type(0)); 5546 BuildFileWithErrors( 5547 file_proto.DebugString(), 5548 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " 5549 "\"Foo\".\n" 5550 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " 5551 "with an existing enum type.\n"); 5552 } 5553 5554 TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) { 5555 FileDescriptorProto file_proto; 5556 FillValidMapEntry(&file_proto); 5557 TextFormat::MergeFromString( 5558 "oneof_decl { " 5559 " name: 'FooMapEntry' " 5560 "}" 5561 "field { " 5562 " name: 'int_field' " 5563 " type: TYPE_INT32 " 5564 " label: LABEL_OPTIONAL " 5565 " oneof_index: 0 " 5566 " number: 100 " 5567 "} ", 5568 file_proto.mutable_message_type(0)); 5569 BuildFileWithErrors( 5570 file_proto.DebugString(), 5571 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " 5572 "\"Foo\".\n" 5573 "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n" 5574 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " 5575 "with an existing oneof type.\n"); 5576 } 5577 5578 TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) { 5579 BuildFileWithErrors( 5580 "name: \"foo.proto\" " 5581 "enum_type {" 5582 " name: \"Bar\"" 5583 " value { name:\"ENUM_A\" number:1 }" 5584 " value { name:\"ENUM_B\" number:2 }" 5585 "}" 5586 "message_type {" 5587 " name: 'Foo' " 5588 " field { " 5589 " name: 'foo_map' number: 1 label:LABEL_REPEATED " 5590 " type_name: 'FooMapEntry' " 5591 " } " 5592 " nested_type { " 5593 " name: 'FooMapEntry' " 5594 " options { map_entry: true } " 5595 " field { " 5596 " name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL " 5597 " } " 5598 " field { " 5599 " name: 'value' number: 2 type_name:\"Bar\" label:LABEL_OPTIONAL " 5600 " } " 5601 " } " 5602 "}", 5603 "foo.proto: Foo.foo_map: " 5604 "TYPE: Enum value in map must define 0 as the first value.\n"); 5605 } 5606 5607 TEST_F(ValidationErrorTest, Proto3RequiredFields) { 5608 BuildFileWithErrors( 5609 "name: 'foo.proto' " 5610 "syntax: 'proto3' " 5611 "message_type { " 5612 " name: 'Foo' " 5613 " field { name:'foo' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } " 5614 "}", 5615 "foo.proto: Foo.foo: OTHER: Required fields are not allowed in " 5616 "proto3.\n"); 5617 5618 // applied to nested types as well. 5619 BuildFileWithErrors( 5620 "name: 'foo.proto' " 5621 "syntax: 'proto3' " 5622 "message_type { " 5623 " name: 'Foo' " 5624 " nested_type { " 5625 " name : 'Bar' " 5626 " field { name:'bar' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } " 5627 " } " 5628 "}", 5629 "foo.proto: Foo.Bar.bar: OTHER: Required fields are not allowed in " 5630 "proto3.\n"); 5631 5632 // optional and repeated fields are OK. 5633 BuildFile( 5634 "name: 'foo.proto' " 5635 "syntax: 'proto3' " 5636 "message_type { " 5637 " name: 'Foo' " 5638 " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } " 5639 " field { name:'bar' number:2 label:LABEL_REPEATED type:TYPE_INT32 } " 5640 "}"); 5641 } 5642 5643 TEST_F(ValidationErrorTest, ValidateProto3DefaultValue) { 5644 BuildFileWithErrors( 5645 "name: 'foo.proto' " 5646 "syntax: 'proto3' " 5647 "message_type { " 5648 " name: 'Foo' " 5649 " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 " 5650 " default_value: '1' }" 5651 "}", 5652 "foo.proto: Foo.foo: OTHER: Explicit default values are not allowed in " 5653 "proto3.\n"); 5654 5655 BuildFileWithErrors( 5656 "name: 'foo.proto' " 5657 "syntax: 'proto3' " 5658 "message_type { " 5659 " name: 'Foo' " 5660 " nested_type { " 5661 " name : 'Bar' " 5662 " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 " 5663 " default_value: '1' }" 5664 " } " 5665 "}", 5666 "foo.proto: Foo.Bar.bar: OTHER: Explicit default values are not allowed " 5667 "in proto3.\n"); 5668 } 5669 5670 TEST_F(ValidationErrorTest, ValidateProto3ExtensionRange) { 5671 BuildFileWithErrors( 5672 "name: 'foo.proto' " 5673 "syntax: 'proto3' " 5674 "message_type { " 5675 " name: 'Foo' " 5676 " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } " 5677 " extension_range { start:10 end:100 } " 5678 "}", 5679 "foo.proto: Foo: OTHER: Extension ranges are not allowed in " 5680 "proto3.\n"); 5681 5682 BuildFileWithErrors( 5683 "name: 'foo.proto' " 5684 "syntax: 'proto3' " 5685 "message_type { " 5686 " name: 'Foo' " 5687 " nested_type { " 5688 " name : 'Bar' " 5689 " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } " 5690 " extension_range { start:10 end:100 } " 5691 " } " 5692 "}", 5693 "foo.proto: Foo.Bar: OTHER: Extension ranges are not allowed in " 5694 "proto3.\n"); 5695 } 5696 5697 TEST_F(ValidationErrorTest, ValidateProto3MessageSetWireFormat) { 5698 BuildFileWithErrors( 5699 "name: 'foo.proto' " 5700 "syntax: 'proto3' " 5701 "message_type { " 5702 " name: 'Foo' " 5703 " options { message_set_wire_format: true } " 5704 "}", 5705 "foo.proto: Foo: OTHER: MessageSet is not supported " 5706 "in proto3.\n"); 5707 } 5708 5709 TEST_F(ValidationErrorTest, ValidateProto3Enum) { 5710 BuildFileWithErrors( 5711 "name: 'foo.proto' " 5712 "syntax: 'proto3' " 5713 "enum_type { " 5714 " name: 'FooEnum' " 5715 " value { name: 'FOO_FOO' number:1 } " 5716 "}", 5717 "foo.proto: FooEnum: OTHER: The first enum value must be " 5718 "zero in proto3.\n"); 5719 5720 BuildFileWithErrors( 5721 "name: 'foo.proto' " 5722 "syntax: 'proto3' " 5723 "message_type { " 5724 " name: 'Foo' " 5725 " enum_type { " 5726 " name: 'FooEnum' " 5727 " value { name: 'FOO_FOO' number:1 } " 5728 " } " 5729 "}", 5730 "foo.proto: Foo.FooEnum: OTHER: The first enum value must be " 5731 "zero in proto3.\n"); 5732 5733 // valid case. 5734 BuildFile( 5735 "name: 'foo.proto' " 5736 "syntax: 'proto3' " 5737 "enum_type { " 5738 " name: 'FooEnum' " 5739 " value { name: 'FOO_FOO' number:0 } " 5740 "}"); 5741 } 5742 5743 TEST_F(ValidationErrorTest, ValidateProto3Group) { 5744 BuildFileWithErrors( 5745 "name: 'foo.proto' " 5746 "syntax: 'proto3' " 5747 "message_type { " 5748 " name: 'Foo' " 5749 " nested_type { " 5750 " name: 'FooGroup' " 5751 " } " 5752 " field { name:'foo_group' number: 1 label:LABEL_OPTIONAL " 5753 " type: TYPE_GROUP type_name:'FooGroup' } " 5754 "}", 5755 "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 " 5756 "syntax.\n"); 5757 } 5758 5759 5760 TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) { 5761 // Define an enum in a proto2 file. 5762 BuildFile( 5763 "name: 'foo.proto' " 5764 "package: 'foo' " 5765 "syntax: 'proto2' " 5766 "enum_type { " 5767 " name: 'FooEnum' " 5768 " value { name: 'DEFAULT_OPTION' number:0 } " 5769 "}"); 5770 5771 // Now try to refer to it. (All tests in the fixture use the same pool, so we 5772 // can refer to the enum above in this definition.) 5773 BuildFileWithErrors( 5774 "name: 'bar.proto' " 5775 "dependency: 'foo.proto' " 5776 "syntax: 'proto3' " 5777 "message_type { " 5778 " name: 'Foo' " 5779 " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_ENUM " 5780 " type_name: 'foo.FooEnum' }" 5781 "}", 5782 "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not a proto3 " 5783 "enum, but is used in \"Foo\" which is a proto3 message type.\n"); 5784 } 5785 5786 TEST_F(ValidationErrorTest, ValidateProto3Extension) { 5787 // Valid for options. 5788 DescriptorPool pool; 5789 FileDescriptorProto file_proto; 5790 // Add "google/protobuf/descriptor.proto". 5791 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); 5792 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 5793 // Add "foo.proto": 5794 // import "google/protobuf/descriptor.proto"; 5795 // extend google.protobuf.FieldOptions { 5796 // optional int32 option1 = 1000; 5797 // } 5798 file_proto.Clear(); 5799 file_proto.set_name("foo.proto"); 5800 file_proto.set_syntax("proto3"); 5801 file_proto.add_dependency("google/protobuf/descriptor.proto"); 5802 AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000, 5803 FieldDescriptorProto::LABEL_OPTIONAL, 5804 FieldDescriptorProto::TYPE_INT32); 5805 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); 5806 5807 // Copy and change the package of the descriptor.proto 5808 BuildFile( 5809 "name: 'google.protobuf.proto' " 5810 "syntax: 'proto2' " 5811 "message_type { " 5812 " name: 'Container' extension_range { start: 1 end: 1000 } " 5813 "}"); 5814 BuildFileWithErrors( 5815 "name: 'bar.proto' " 5816 "syntax: 'proto3' " 5817 "dependency: 'google.protobuf.proto' " 5818 "extension { " 5819 " name: 'bar' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 " 5820 " extendee: 'Container' " 5821 "}", 5822 "bar.proto: bar: OTHER: Extensions in proto3 are only allowed for " 5823 "defining options.\n"); 5824 } 5825 5826 // Test that field names that may conflict in JSON is not allowed by protoc. 5827 TEST_F(ValidationErrorTest, ValidateProto3JsonName) { 5828 // The comparison is case-insensitive. 5829 BuildFileWithErrors( 5830 "name: 'foo.proto' " 5831 "syntax: 'proto3' " 5832 "message_type {" 5833 " name: 'Foo'" 5834 " field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }" 5835 " field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" 5836 "}", 5837 "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" " 5838 "conflicts with field \"name\". This is not allowed in proto3.\n"); 5839 // Underscores are ignored. 5840 BuildFileWithErrors( 5841 "name: 'foo.proto' " 5842 "syntax: 'proto3' " 5843 "message_type {" 5844 " name: 'Foo'" 5845 " field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }" 5846 " field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" 5847 "}", 5848 "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" " 5849 "conflicts with field \"ab\". This is not allowed in proto3.\n"); 5850 } 5851 5852 // =================================================================== 5853 // DescriptorDatabase 5854 5855 static void AddToDatabase(SimpleDescriptorDatabase* database, 5856 const char* file_text) { 5857 FileDescriptorProto file_proto; 5858 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); 5859 database->Add(file_proto); 5860 } 5861 5862 class DatabaseBackedPoolTest : public testing::Test { 5863 protected: 5864 DatabaseBackedPoolTest() {} 5865 5866 SimpleDescriptorDatabase database_; 5867 5868 virtual void SetUp() { 5869 AddToDatabase(&database_, 5870 "name: 'foo.proto' " 5871 "message_type { name:'Foo' extension_range { start: 1 end: 100 } } " 5872 "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } " 5873 "service { name:'TestService' } "); 5874 AddToDatabase(&database_, 5875 "name: 'bar.proto' " 5876 "dependency: 'foo.proto' " 5877 "message_type { name:'Bar' } " 5878 "extension { name:'foo_ext' extendee: '.Foo' number:5 " 5879 " label:LABEL_OPTIONAL type:TYPE_INT32 } "); 5880 // Baz has an undeclared dependency on Foo. 5881 AddToDatabase(&database_, 5882 "name: 'baz.proto' " 5883 "message_type { " 5884 " name:'Baz' " 5885 " field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } " 5886 "}"); 5887 } 5888 5889 // We can't inject a file containing errors into a DescriptorPool, so we 5890 // need an actual mock DescriptorDatabase to test errors. 5891 class ErrorDescriptorDatabase : public DescriptorDatabase { 5892 public: 5893 ErrorDescriptorDatabase() {} 5894 ~ErrorDescriptorDatabase() {} 5895 5896 // implements DescriptorDatabase --------------------------------- 5897 bool FindFileByName(const string& filename, 5898 FileDescriptorProto* output) { 5899 // error.proto and error2.proto cyclically import each other. 5900 if (filename == "error.proto") { 5901 output->Clear(); 5902 output->set_name("error.proto"); 5903 output->add_dependency("error2.proto"); 5904 return true; 5905 } else if (filename == "error2.proto") { 5906 output->Clear(); 5907 output->set_name("error2.proto"); 5908 output->add_dependency("error.proto"); 5909 return true; 5910 } else { 5911 return false; 5912 } 5913 } 5914 bool FindFileContainingSymbol(const string& symbol_name, 5915 FileDescriptorProto* output) { 5916 return false; 5917 } 5918 bool FindFileContainingExtension(const string& containing_type, 5919 int field_number, 5920 FileDescriptorProto* output) { 5921 return false; 5922 } 5923 }; 5924 5925 // A DescriptorDatabase that counts how many times each method has been 5926 // called and forwards to some other DescriptorDatabase. 5927 class CallCountingDatabase : public DescriptorDatabase { 5928 public: 5929 CallCountingDatabase(DescriptorDatabase* wrapped_db) 5930 : wrapped_db_(wrapped_db) { 5931 Clear(); 5932 } 5933 ~CallCountingDatabase() {} 5934 5935 DescriptorDatabase* wrapped_db_; 5936 5937 int call_count_; 5938 5939 void Clear() { 5940 call_count_ = 0; 5941 } 5942 5943 // implements DescriptorDatabase --------------------------------- 5944 bool FindFileByName(const string& filename, 5945 FileDescriptorProto* output) { 5946 ++call_count_; 5947 return wrapped_db_->FindFileByName(filename, output); 5948 } 5949 bool FindFileContainingSymbol(const string& symbol_name, 5950 FileDescriptorProto* output) { 5951 ++call_count_; 5952 return wrapped_db_->FindFileContainingSymbol(symbol_name, output); 5953 } 5954 bool FindFileContainingExtension(const string& containing_type, 5955 int field_number, 5956 FileDescriptorProto* output) { 5957 ++call_count_; 5958 return wrapped_db_->FindFileContainingExtension( 5959 containing_type, field_number, output); 5960 } 5961 }; 5962 5963 // A DescriptorDatabase which falsely always returns foo.proto when searching 5964 // for any symbol or extension number. This shouldn't cause the 5965 // DescriptorPool to reload foo.proto if it is already loaded. 5966 class FalsePositiveDatabase : public DescriptorDatabase { 5967 public: 5968 FalsePositiveDatabase(DescriptorDatabase* wrapped_db) 5969 : wrapped_db_(wrapped_db) {} 5970 ~FalsePositiveDatabase() {} 5971 5972 DescriptorDatabase* wrapped_db_; 5973 5974 // implements DescriptorDatabase --------------------------------- 5975 bool FindFileByName(const string& filename, 5976 FileDescriptorProto* output) { 5977 return wrapped_db_->FindFileByName(filename, output); 5978 } 5979 bool FindFileContainingSymbol(const string& symbol_name, 5980 FileDescriptorProto* output) { 5981 return FindFileByName("foo.proto", output); 5982 } 5983 bool FindFileContainingExtension(const string& containing_type, 5984 int field_number, 5985 FileDescriptorProto* output) { 5986 return FindFileByName("foo.proto", output); 5987 } 5988 }; 5989 }; 5990 5991 TEST_F(DatabaseBackedPoolTest, FindFileByName) { 5992 DescriptorPool pool(&database_); 5993 5994 const FileDescriptor* foo = pool.FindFileByName("foo.proto"); 5995 ASSERT_TRUE(foo != NULL); 5996 EXPECT_EQ("foo.proto", foo->name()); 5997 ASSERT_EQ(1, foo->message_type_count()); 5998 EXPECT_EQ("Foo", foo->message_type(0)->name()); 5999 6000 EXPECT_EQ(foo, pool.FindFileByName("foo.proto")); 6001 6002 EXPECT_TRUE(pool.FindFileByName("no_such_file.proto") == NULL); 6003 } 6004 6005 TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) { 6006 DescriptorPool pool(&database_); 6007 6008 const FileDescriptor* foo = pool.FindFileByName("foo.proto"); 6009 ASSERT_TRUE(foo != NULL); 6010 EXPECT_EQ("foo.proto", foo->name()); 6011 ASSERT_EQ(1, foo->message_type_count()); 6012 EXPECT_EQ("Foo", foo->message_type(0)->name()); 6013 6014 const FileDescriptor* bar = pool.FindFileByName("bar.proto"); 6015 ASSERT_TRUE(bar != NULL); 6016 EXPECT_EQ("bar.proto", bar->name()); 6017 ASSERT_EQ(1, bar->message_type_count()); 6018 EXPECT_EQ("Bar", bar->message_type(0)->name()); 6019 6020 ASSERT_EQ(1, bar->dependency_count()); 6021 EXPECT_EQ(foo, bar->dependency(0)); 6022 } 6023 6024 TEST_F(DatabaseBackedPoolTest, FindDependentBeforeDependency) { 6025 DescriptorPool pool(&database_); 6026 6027 const FileDescriptor* bar = pool.FindFileByName("bar.proto"); 6028 ASSERT_TRUE(bar != NULL); 6029 EXPECT_EQ("bar.proto", bar->name()); 6030 ASSERT_EQ(1, bar->message_type_count()); 6031 ASSERT_EQ("Bar", bar->message_type(0)->name()); 6032 6033 const FileDescriptor* foo = pool.FindFileByName("foo.proto"); 6034 ASSERT_TRUE(foo != NULL); 6035 EXPECT_EQ("foo.proto", foo->name()); 6036 ASSERT_EQ(1, foo->message_type_count()); 6037 ASSERT_EQ("Foo", foo->message_type(0)->name()); 6038 6039 ASSERT_EQ(1, bar->dependency_count()); 6040 EXPECT_EQ(foo, bar->dependency(0)); 6041 } 6042 6043 TEST_F(DatabaseBackedPoolTest, FindFileContainingSymbol) { 6044 DescriptorPool pool(&database_); 6045 6046 const FileDescriptor* file = pool.FindFileContainingSymbol("Foo"); 6047 ASSERT_TRUE(file != NULL); 6048 EXPECT_EQ("foo.proto", file->name()); 6049 EXPECT_EQ(file, pool.FindFileByName("foo.proto")); 6050 6051 EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == NULL); 6052 } 6053 6054 TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) { 6055 DescriptorPool pool(&database_); 6056 6057 const Descriptor* type = pool.FindMessageTypeByName("Foo"); 6058 ASSERT_TRUE(type != NULL); 6059 EXPECT_EQ("Foo", type->name()); 6060 EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto")); 6061 6062 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == NULL); 6063 } 6064 6065 TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) { 6066 DescriptorPool pool(&database_); 6067 6068 const Descriptor* foo = pool.FindMessageTypeByName("Foo"); 6069 ASSERT_TRUE(foo != NULL); 6070 6071 const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5); 6072 ASSERT_TRUE(extension != NULL); 6073 EXPECT_EQ("foo_ext", extension->name()); 6074 EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto")); 6075 6076 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == NULL); 6077 } 6078 6079 TEST_F(DatabaseBackedPoolTest, FindAllExtensions) { 6080 DescriptorPool pool(&database_); 6081 6082 const Descriptor* foo = pool.FindMessageTypeByName("Foo"); 6083 6084 for (int i = 0; i < 2; ++i) { 6085 // Repeat the lookup twice, to check that we get consistent 6086 // results despite the fallback database lookup mutating the pool. 6087 vector<const FieldDescriptor*> extensions; 6088 pool.FindAllExtensions(foo, &extensions); 6089 ASSERT_EQ(1, extensions.size()); 6090 EXPECT_EQ(5, extensions[0]->number()); 6091 } 6092 } 6093 6094 TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) { 6095 ErrorDescriptorDatabase error_database; 6096 DescriptorPool pool(&error_database); 6097 6098 vector<string> errors; 6099 6100 { 6101 ScopedMemoryLog log; 6102 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL); 6103 errors = log.GetMessages(ERROR); 6104 } 6105 6106 EXPECT_FALSE(errors.empty()); 6107 } 6108 6109 TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) { 6110 ErrorDescriptorDatabase error_database; 6111 MockErrorCollector error_collector; 6112 DescriptorPool pool(&error_database, &error_collector); 6113 6114 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL); 6115 EXPECT_EQ( 6116 "error.proto: error.proto: OTHER: File recursively imports itself: " 6117 "error.proto -> error2.proto -> error.proto\n" 6118 "error2.proto: error2.proto: OTHER: Import \"error.proto\" was not " 6119 "found or had errors.\n" 6120 "error.proto: error.proto: OTHER: Import \"error2.proto\" was not " 6121 "found or had errors.\n", 6122 error_collector.text_); 6123 } 6124 6125 TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) { 6126 // Check that we find and report undeclared dependencies on types that exist 6127 // in the descriptor database but that have not not been built yet. 6128 MockErrorCollector error_collector; 6129 DescriptorPool pool(&database_, &error_collector); 6130 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL); 6131 EXPECT_EQ( 6132 "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", " 6133 "which is not imported by \"baz.proto\". To use it here, please add " 6134 "the necessary import.\n", 6135 error_collector.text_); 6136 } 6137 6138 TEST_F(DatabaseBackedPoolTest, RollbackAfterError) { 6139 // Make sure that all traces of bad types are removed from the pool. This used 6140 // to be b/4529436, due to the fact that a symbol resolution failure could 6141 // potentially cause another file to be recursively built, which would trigger 6142 // a checkpoint _past_ possibly invalid symbols. 6143 // Baz is defined in the database, but the file is invalid because it is 6144 // missing a necessary import. 6145 DescriptorPool pool(&database_); 6146 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL); 6147 // Make sure that searching again for the file or the type fails. 6148 EXPECT_TRUE(pool.FindFileByName("baz.proto") == NULL); 6149 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL); 6150 } 6151 6152 TEST_F(DatabaseBackedPoolTest, UnittestProto) { 6153 // Try to load all of unittest.proto from a DescriptorDatabase. This should 6154 // thoroughly test all paths through DescriptorBuilder to insure that there 6155 // are no deadlocking problems when pool_->mutex_ is non-NULL. 6156 const FileDescriptor* original_file = 6157 protobuf_unittest::TestAllTypes::descriptor()->file(); 6158 6159 DescriptorPoolDatabase database(*DescriptorPool::generated_pool()); 6160 DescriptorPool pool(&database); 6161 const FileDescriptor* file_from_database = 6162 pool.FindFileByName(original_file->name()); 6163 6164 ASSERT_TRUE(file_from_database != NULL); 6165 6166 FileDescriptorProto original_file_proto; 6167 original_file->CopyTo(&original_file_proto); 6168 6169 FileDescriptorProto file_from_database_proto; 6170 file_from_database->CopyTo(&file_from_database_proto); 6171 6172 EXPECT_EQ(original_file_proto.DebugString(), 6173 file_from_database_proto.DebugString()); 6174 6175 // Also verify that CopyTo() did not omit any information. 6176 EXPECT_EQ(original_file->DebugString(), 6177 file_from_database->DebugString()); 6178 } 6179 6180 TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) { 6181 // Searching for a child of an existing descriptor should never fall back 6182 // to the DescriptorDatabase even if it isn't found, because we know all 6183 // children are already loaded. 6184 CallCountingDatabase call_counter(&database_); 6185 DescriptorPool pool(&call_counter); 6186 6187 const FileDescriptor* file = pool.FindFileByName("foo.proto"); 6188 ASSERT_TRUE(file != NULL); 6189 const Descriptor* foo = pool.FindMessageTypeByName("Foo"); 6190 ASSERT_TRUE(foo != NULL); 6191 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum"); 6192 ASSERT_TRUE(test_enum != NULL); 6193 const ServiceDescriptor* test_service = pool.FindServiceByName("TestService"); 6194 ASSERT_TRUE(test_service != NULL); 6195 6196 EXPECT_NE(0, call_counter.call_count_); 6197 call_counter.Clear(); 6198 6199 EXPECT_TRUE(foo->FindFieldByName("no_such_field") == NULL); 6200 EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == NULL); 6201 EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == NULL); 6202 EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == NULL); 6203 EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == NULL); 6204 EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == NULL); 6205 EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == NULL); 6206 6207 EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == NULL); 6208 EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == NULL); 6209 EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == NULL); 6210 EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == NULL); 6211 EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == NULL); 6212 6213 EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == NULL); 6214 EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == NULL); 6215 EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == NULL); 6216 EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == NULL); 6217 EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == NULL); 6218 EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == NULL); 6219 EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == NULL); 6220 EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == NULL); 6221 6222 EXPECT_EQ(0, call_counter.call_count_); 6223 } 6224 6225 TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) { 6226 // If FindFileContainingSymbol() or FindFileContainingExtension() return a 6227 // file that is already in the DescriptorPool, it should not attempt to 6228 // reload the file. 6229 FalsePositiveDatabase false_positive_database(&database_); 6230 MockErrorCollector error_collector; 6231 DescriptorPool pool(&false_positive_database, &error_collector); 6232 6233 // First make sure foo.proto is loaded. 6234 const Descriptor* foo = pool.FindMessageTypeByName("Foo"); 6235 ASSERT_TRUE(foo != NULL); 6236 6237 // Try inducing false positives. 6238 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == NULL); 6239 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == NULL); 6240 6241 // No errors should have been reported. (If foo.proto was incorrectly 6242 // loaded multiple times, errors would have been reported.) 6243 EXPECT_EQ("", error_collector.text_); 6244 } 6245 6246 // DescriptorDatabase that attempts to induce exponentially-bad performance 6247 // in DescriptorPool. For every positive N, the database contains a file 6248 // fileN.proto, which defines a message MessageN, which contains fields of 6249 // type MessageK for all K in [0,N). Message0 is not defined anywhere 6250 // (file0.proto exists, but is empty), so every other file and message type 6251 // will fail to build. 6252 // 6253 // If the DescriptorPool is not careful to memoize errors, an attempt to 6254 // build a descriptor for MessageN can require O(2^N) time. 6255 class ExponentialErrorDatabase : public DescriptorDatabase { 6256 public: 6257 ExponentialErrorDatabase() {} 6258 ~ExponentialErrorDatabase() {} 6259 6260 // implements DescriptorDatabase --------------------------------- 6261 bool FindFileByName(const string& filename, 6262 FileDescriptorProto* output) { 6263 int file_num = -1; 6264 FullMatch(filename, "file", ".proto", &file_num); 6265 if (file_num > -1) { 6266 return PopulateFile(file_num, output); 6267 } else { 6268 return false; 6269 } 6270 } 6271 bool FindFileContainingSymbol(const string& symbol_name, 6272 FileDescriptorProto* output) { 6273 int file_num = -1; 6274 FullMatch(symbol_name, "Message", "", &file_num); 6275 if (file_num > 0) { 6276 return PopulateFile(file_num, output); 6277 } else { 6278 return false; 6279 } 6280 } 6281 bool FindFileContainingExtension(const string& containing_type, 6282 int field_number, 6283 FileDescriptorProto* output) { 6284 return false; 6285 } 6286 6287 private: 6288 void FullMatch(const string& name, 6289 const string& begin_with, 6290 const string& end_with, 6291 int* file_num) { 6292 int begin_size = begin_with.size(); 6293 int end_size = end_with.size(); 6294 if (name.substr(0, begin_size) != begin_with || 6295 name.substr(name.size()- end_size, end_size) != end_with) { 6296 return; 6297 } 6298 safe_strto32(name.substr(begin_size, name.size() - end_size - begin_size), 6299 file_num); 6300 } 6301 6302 bool PopulateFile(int file_num, FileDescriptorProto* output) { 6303 using strings::Substitute; 6304 GOOGLE_CHECK_GE(file_num, 0); 6305 output->Clear(); 6306 output->set_name(Substitute("file$0.proto", file_num)); 6307 // file0.proto doesn't define Message0 6308 if (file_num > 0) { 6309 DescriptorProto* message = output->add_message_type(); 6310 message->set_name(Substitute("Message$0", file_num)); 6311 for (int i = 0; i < file_num; ++i) { 6312 output->add_dependency(Substitute("file$0.proto", i)); 6313 FieldDescriptorProto* field = message->add_field(); 6314 field->set_name(Substitute("field$0", i)); 6315 field->set_number(i); 6316 field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); 6317 field->set_type(FieldDescriptorProto::TYPE_MESSAGE); 6318 field->set_type_name(Substitute("Message$0", i)); 6319 } 6320 } 6321 return true; 6322 } 6323 }; 6324 6325 TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) { 6326 ExponentialErrorDatabase error_database; 6327 DescriptorPool pool(&error_database); 6328 6329 GOOGLE_LOG(INFO) << "A timeout in this test probably indicates a real bug."; 6330 6331 EXPECT_TRUE(pool.FindFileByName("file40.proto") == NULL); 6332 EXPECT_TRUE(pool.FindMessageTypeByName("Message40") == NULL); 6333 } 6334 6335 TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) { 6336 // If a lookup finds a symbol of the wrong type (e.g. we pass a type name 6337 // to FindFieldByName()), we should fail fast, without checking the fallback 6338 // database. 6339 CallCountingDatabase call_counter(&database_); 6340 DescriptorPool pool(&call_counter); 6341 6342 const FileDescriptor* file = pool.FindFileByName("foo.proto"); 6343 ASSERT_TRUE(file != NULL); 6344 const Descriptor* foo = pool.FindMessageTypeByName("Foo"); 6345 ASSERT_TRUE(foo != NULL); 6346 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum"); 6347 ASSERT_TRUE(test_enum != NULL); 6348 6349 EXPECT_NE(0, call_counter.call_count_); 6350 call_counter.Clear(); 6351 6352 EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == NULL); 6353 EXPECT_TRUE(pool.FindFieldByName("Foo") == NULL); 6354 EXPECT_TRUE(pool.FindExtensionByName("Foo") == NULL); 6355 EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == NULL); 6356 EXPECT_TRUE(pool.FindEnumValueByName("Foo") == NULL); 6357 EXPECT_TRUE(pool.FindServiceByName("Foo") == NULL); 6358 EXPECT_TRUE(pool.FindMethodByName("Foo") == NULL); 6359 6360 EXPECT_EQ(0, call_counter.call_count_); 6361 } 6362 6363 // =================================================================== 6364 6365 class AbortingErrorCollector : public DescriptorPool::ErrorCollector { 6366 public: 6367 AbortingErrorCollector() {} 6368 6369 virtual void AddError( 6370 const string &filename, 6371 const string &element_name, 6372 const Message *message, 6373 ErrorLocation location, 6374 const string &error_message) { 6375 GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << " [" 6376 << element_name << "]: " << error_message; 6377 } 6378 private: 6379 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector); 6380 }; 6381 6382 // A source tree containing only one file. 6383 class SingletonSourceTree : public compiler::SourceTree { 6384 public: 6385 SingletonSourceTree(const string& filename, const string& contents) 6386 : filename_(filename), contents_(contents) {} 6387 6388 virtual io::ZeroCopyInputStream* Open(const string& filename) { 6389 return filename == filename_ ? 6390 new io::ArrayInputStream(contents_.data(), contents_.size()) : NULL; 6391 } 6392 6393 private: 6394 const string filename_; 6395 const string contents_; 6396 6397 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingletonSourceTree); 6398 }; 6399 6400 const char *const kSourceLocationTestInput = 6401 "syntax = \"proto2\";\n" 6402 "message A {\n" 6403 " optional int32 a = 1;\n" 6404 " message B {\n" 6405 " required double b = 1;\n" 6406 " }\n" 6407 "}\n" 6408 "enum Indecision {\n" 6409 " YES = 1;\n" 6410 " NO = 2;\n" 6411 " MAYBE = 3;\n" 6412 "}\n" 6413 "service S {\n" 6414 " rpc Method(A) returns (A.B);\n" 6415 // Put an empty line here to make the source location range match. 6416 "\n" 6417 "}\n" 6418 "message MessageWithExtensions {\n" 6419 " extensions 1000 to max;\n" 6420 "}\n" 6421 "extend MessageWithExtensions {\n" 6422 " optional int32 int32_extension = 1001;\n" 6423 "}\n" 6424 "message C {\n" 6425 " extend MessageWithExtensions {\n" 6426 " optional C message_extension = 1002;\n" 6427 " }\n" 6428 "}\n"; 6429 6430 class SourceLocationTest : public testing::Test { 6431 public: 6432 SourceLocationTest() 6433 : source_tree_("/test/test.proto", kSourceLocationTestInput), 6434 db_(&source_tree_), 6435 pool_(&db_, &collector_) {} 6436 6437 static string PrintSourceLocation(const SourceLocation &loc) { 6438 return strings::Substitute("$0:$1-$2:$3", 6439 1 + loc.start_line, 6440 1 + loc.start_column, 6441 1 + loc.end_line, 6442 1 + loc.end_column); 6443 } 6444 6445 private: 6446 AbortingErrorCollector collector_; 6447 SingletonSourceTree source_tree_; 6448 compiler::SourceTreeDescriptorDatabase db_; 6449 6450 protected: 6451 DescriptorPool pool_; 6452 }; 6453 6454 // TODO(adonovan): implement support for option fields and for 6455 // subparts of declarations. 6456 6457 TEST_F(SourceLocationTest, GetSourceLocation) { 6458 SourceLocation loc; 6459 6460 const FileDescriptor *file_desc = 6461 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto")); 6462 6463 const Descriptor *a_desc = file_desc->FindMessageTypeByName("A"); 6464 EXPECT_TRUE(a_desc->GetSourceLocation(&loc)); 6465 EXPECT_EQ("2:1-7:2", PrintSourceLocation(loc)); 6466 6467 const Descriptor *a_b_desc = a_desc->FindNestedTypeByName("B"); 6468 EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc)); 6469 EXPECT_EQ("4:3-6:4", PrintSourceLocation(loc)); 6470 6471 const EnumDescriptor *e_desc = file_desc->FindEnumTypeByName("Indecision"); 6472 EXPECT_TRUE(e_desc->GetSourceLocation(&loc)); 6473 EXPECT_EQ("8:1-12:2", PrintSourceLocation(loc)); 6474 6475 const EnumValueDescriptor *yes_desc = e_desc->FindValueByName("YES"); 6476 EXPECT_TRUE(yes_desc->GetSourceLocation(&loc)); 6477 EXPECT_EQ("9:3-9:13", PrintSourceLocation(loc)); 6478 6479 const ServiceDescriptor *s_desc = file_desc->FindServiceByName("S"); 6480 EXPECT_TRUE(s_desc->GetSourceLocation(&loc)); 6481 EXPECT_EQ("13:1-16:2", PrintSourceLocation(loc)); 6482 6483 const MethodDescriptor *m_desc = s_desc->FindMethodByName("Method"); 6484 EXPECT_TRUE(m_desc->GetSourceLocation(&loc)); 6485 EXPECT_EQ("14:3-14:31", PrintSourceLocation(loc)); 6486 6487 } 6488 6489 TEST_F(SourceLocationTest, ExtensionSourceLocation) { 6490 SourceLocation loc; 6491 6492 const FileDescriptor *file_desc = 6493 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto")); 6494 6495 const FieldDescriptor *int32_extension_desc = 6496 file_desc->FindExtensionByName("int32_extension"); 6497 EXPECT_TRUE(int32_extension_desc->GetSourceLocation(&loc)); 6498 EXPECT_EQ("21:3-21:41", PrintSourceLocation(loc)); 6499 6500 const Descriptor *c_desc = file_desc->FindMessageTypeByName("C"); 6501 EXPECT_TRUE(c_desc->GetSourceLocation(&loc)); 6502 EXPECT_EQ("23:1-27:2", PrintSourceLocation(loc)); 6503 6504 const FieldDescriptor *message_extension_desc = 6505 c_desc->FindExtensionByName("message_extension"); 6506 EXPECT_TRUE(message_extension_desc->GetSourceLocation(&loc)); 6507 EXPECT_EQ("25:5-25:41", PrintSourceLocation(loc)); 6508 } 6509 6510 // Missing SourceCodeInfo doesn't cause crash: 6511 TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) { 6512 SourceLocation loc; 6513 6514 const FileDescriptor *file_desc = 6515 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto")); 6516 6517 FileDescriptorProto proto; 6518 file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo. 6519 EXPECT_FALSE(proto.has_source_code_info()); 6520 6521 DescriptorPool bad1_pool(&pool_); 6522 const FileDescriptor* bad1_file_desc = 6523 GOOGLE_CHECK_NOTNULL(bad1_pool.BuildFile(proto)); 6524 const Descriptor *bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A"); 6525 EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc)); 6526 } 6527 6528 // Corrupt SourceCodeInfo doesn't cause crash: 6529 TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) { 6530 SourceLocation loc; 6531 6532 const FileDescriptor *file_desc = 6533 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto")); 6534 6535 FileDescriptorProto proto; 6536 file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo. 6537 EXPECT_FALSE(proto.has_source_code_info()); 6538 SourceCodeInfo_Location *loc_msg = 6539 proto.mutable_source_code_info()->add_location(); 6540 loc_msg->add_path(1); 6541 loc_msg->add_path(2); 6542 loc_msg->add_path(3); 6543 loc_msg->add_span(4); 6544 loc_msg->add_span(5); 6545 loc_msg->add_span(6); 6546 6547 DescriptorPool bad2_pool(&pool_); 6548 const FileDescriptor* bad2_file_desc = 6549 GOOGLE_CHECK_NOTNULL(bad2_pool.BuildFile(proto)); 6550 const Descriptor *bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A"); 6551 EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc)); 6552 } 6553 6554 // =================================================================== 6555 6556 const char* const kCopySourceCodeInfoToTestInput = 6557 "syntax = \"proto2\";\n" 6558 "message Foo {}\n"; 6559 6560 // Required since source code information is not preserved by 6561 // FileDescriptorTest. 6562 class CopySourceCodeInfoToTest : public testing::Test { 6563 public: 6564 CopySourceCodeInfoToTest() 6565 : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput), 6566 db_(&source_tree_), 6567 pool_(&db_, &collector_) {} 6568 6569 private: 6570 AbortingErrorCollector collector_; 6571 SingletonSourceTree source_tree_; 6572 compiler::SourceTreeDescriptorDatabase db_; 6573 6574 protected: 6575 DescriptorPool pool_; 6576 }; 6577 6578 TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) { 6579 const FileDescriptor* file_desc = 6580 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto")); 6581 FileDescriptorProto file_desc_proto; 6582 ASSERT_FALSE(file_desc_proto.has_source_code_info()); 6583 6584 file_desc->CopyTo(&file_desc_proto); 6585 EXPECT_FALSE(file_desc_proto.has_source_code_info()); 6586 } 6587 6588 TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) { 6589 const FileDescriptor* file_desc = 6590 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto")); 6591 FileDescriptorProto file_desc_proto; 6592 ASSERT_FALSE(file_desc_proto.has_source_code_info()); 6593 6594 file_desc->CopySourceCodeInfoTo(&file_desc_proto); 6595 const SourceCodeInfo& info = file_desc_proto.source_code_info(); 6596 ASSERT_EQ(4, info.location_size()); 6597 // Get the Foo message location 6598 const SourceCodeInfo_Location& foo_location = info.location(2); 6599 ASSERT_EQ(2, foo_location.path_size()); 6600 EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0)); 6601 EXPECT_EQ(0, foo_location.path(1)); // Foo is the first message defined 6602 ASSERT_EQ(3, foo_location.span_size()); // Foo spans one line 6603 EXPECT_EQ(1, foo_location.span(0)); // Foo is declared on line 1 6604 EXPECT_EQ(0, foo_location.span(1)); // Foo starts at column 0 6605 EXPECT_EQ(14, foo_location.span(2)); // Foo ends on column 14 6606 } 6607 6608 // =================================================================== 6609 6610 6611 } // namespace descriptor_unittest 6612 } // namespace protobuf 6613 } // namespace google 6614