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