1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// Author: kenton@google.com (Kenton Varda) 32// Based on original Protocol Buffers design by 33// Sanjay Ghemawat, Jeff Dean, and others. 34// 35// This file makes extensive use of RFC 3092. :) 36 37#include <algorithm> 38 39#include <google/protobuf/descriptor_database.h> 40#include <google/protobuf/descriptor.h> 41#include <google/protobuf/descriptor.pb.h> 42#include <google/protobuf/text_format.h> 43#include <google/protobuf/stubs/strutil.h> 44 45#include <google/protobuf/stubs/common.h> 46#include <google/protobuf/testing/googletest.h> 47#include <gtest/gtest.h> 48 49namespace google { 50namespace protobuf { 51namespace { 52 53static void AddToDatabase(SimpleDescriptorDatabase* database, 54 const char* file_text) { 55 FileDescriptorProto file_proto; 56 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); 57 database->Add(file_proto); 58} 59 60static void ExpectContainsType(const FileDescriptorProto& proto, 61 const string& type_name) { 62 for (int i = 0; i < proto.message_type_size(); i++) { 63 if (proto.message_type(i).name() == type_name) return; 64 } 65 ADD_FAILURE() << "\"" << proto.name() 66 << "\" did not contain expected type \"" 67 << type_name << "\"."; 68} 69 70// =================================================================== 71 72#if GTEST_HAS_PARAM_TEST 73 74// SimpleDescriptorDatabase, EncodedDescriptorDatabase, and 75// DescriptorPoolDatabase call for very similar tests. Instead of writing 76// three nearly-identical sets of tests, we use parameterized tests to apply 77// the same code to all three. 78 79// The parameterized test runs against a DescriptarDatabaseTestCase. We have 80// implementations for each of the three classes we want to test. 81class DescriptorDatabaseTestCase { 82 public: 83 virtual ~DescriptorDatabaseTestCase() {} 84 85 virtual DescriptorDatabase* GetDatabase() = 0; 86 virtual bool AddToDatabase(const FileDescriptorProto& file) = 0; 87}; 88 89// Factory function type. 90typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory(); 91 92// Specialization for SimpleDescriptorDatabase. 93class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase { 94 public: 95 static DescriptorDatabaseTestCase* New() { 96 return new SimpleDescriptorDatabaseTestCase; 97 } 98 99 virtual ~SimpleDescriptorDatabaseTestCase() {} 100 101 virtual DescriptorDatabase* GetDatabase() { 102 return &database_; 103 } 104 virtual bool AddToDatabase(const FileDescriptorProto& file) { 105 return database_.Add(file); 106 } 107 108 private: 109 SimpleDescriptorDatabase database_; 110}; 111 112// Specialization for EncodedDescriptorDatabase. 113class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase { 114 public: 115 static DescriptorDatabaseTestCase* New() { 116 return new EncodedDescriptorDatabaseTestCase; 117 } 118 119 virtual ~EncodedDescriptorDatabaseTestCase() {} 120 121 virtual DescriptorDatabase* GetDatabase() { 122 return &database_; 123 } 124 virtual bool AddToDatabase(const FileDescriptorProto& file) { 125 string data; 126 file.SerializeToString(&data); 127 return database_.AddCopy(data.data(), data.size()); 128 } 129 130 private: 131 EncodedDescriptorDatabase database_; 132}; 133 134// Specialization for DescriptorPoolDatabase. 135class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase { 136 public: 137 static DescriptorDatabaseTestCase* New() { 138 return new EncodedDescriptorDatabaseTestCase; 139 } 140 141 DescriptorPoolDatabaseTestCase() : database_(pool_) {} 142 virtual ~DescriptorPoolDatabaseTestCase() {} 143 144 virtual DescriptorDatabase* GetDatabase() { 145 return &database_; 146 } 147 virtual bool AddToDatabase(const FileDescriptorProto& file) { 148 return pool_.BuildFile(file); 149 } 150 151 private: 152 DescriptorPool pool_; 153 DescriptorPoolDatabase database_; 154}; 155 156// ------------------------------------------------------------------- 157 158class DescriptorDatabaseTest 159 : public testing::TestWithParam<DescriptorDatabaseTestCaseFactory*> { 160 protected: 161 virtual void SetUp() { 162 test_case_.reset(GetParam()()); 163 database_ = test_case_->GetDatabase(); 164 } 165 166 void AddToDatabase(const char* file_descriptor_text) { 167 FileDescriptorProto file_proto; 168 EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto)); 169 EXPECT_TRUE(test_case_->AddToDatabase(file_proto)); 170 } 171 172 void AddToDatabaseWithError(const char* file_descriptor_text) { 173 FileDescriptorProto file_proto; 174 EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto)); 175 EXPECT_FALSE(test_case_->AddToDatabase(file_proto)); 176 } 177 178 scoped_ptr<DescriptorDatabaseTestCase> test_case_; 179 DescriptorDatabase* database_; 180}; 181 182TEST_P(DescriptorDatabaseTest, FindFileByName) { 183 AddToDatabase( 184 "name: \"foo.proto\" " 185 "message_type { name:\"Foo\" }"); 186 AddToDatabase( 187 "name: \"bar.proto\" " 188 "message_type { name:\"Bar\" }"); 189 190 { 191 FileDescriptorProto file; 192 EXPECT_TRUE(database_->FindFileByName("foo.proto", &file)); 193 EXPECT_EQ("foo.proto", file.name()); 194 ExpectContainsType(file, "Foo"); 195 } 196 197 { 198 FileDescriptorProto file; 199 EXPECT_TRUE(database_->FindFileByName("bar.proto", &file)); 200 EXPECT_EQ("bar.proto", file.name()); 201 ExpectContainsType(file, "Bar"); 202 } 203 204 { 205 // Fails to find undefined files. 206 FileDescriptorProto file; 207 EXPECT_FALSE(database_->FindFileByName("baz.proto", &file)); 208 } 209} 210 211TEST_P(DescriptorDatabaseTest, FindFileContainingSymbol) { 212 AddToDatabase( 213 "name: \"foo.proto\" " 214 "message_type { " 215 " name: \"Foo\" " 216 " field { name:\"qux\" }" 217 " nested_type { name: \"Grault\" } " 218 " enum_type { name: \"Garply\" } " 219 "} " 220 "enum_type { " 221 " name: \"Waldo\" " 222 " value { name:\"FRED\" } " 223 "} " 224 "extension { name: \"plugh\" } " 225 "service { " 226 " name: \"Xyzzy\" " 227 " method { name: \"Thud\" } " 228 "}" 229 ); 230 AddToDatabase( 231 "name: \"bar.proto\" " 232 "package: \"corge\" " 233 "message_type { name: \"Bar\" }"); 234 235 { 236 FileDescriptorProto file; 237 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo", &file)); 238 EXPECT_EQ("foo.proto", file.name()); 239 } 240 241 { 242 // Can find fields. 243 FileDescriptorProto file; 244 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.qux", &file)); 245 EXPECT_EQ("foo.proto", file.name()); 246 } 247 248 { 249 // Can find nested types. 250 FileDescriptorProto file; 251 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Grault", &file)); 252 EXPECT_EQ("foo.proto", file.name()); 253 } 254 255 { 256 // Can find nested enums. 257 FileDescriptorProto file; 258 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Garply", &file)); 259 EXPECT_EQ("foo.proto", file.name()); 260 } 261 262 { 263 // Can find enum types. 264 FileDescriptorProto file; 265 EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo", &file)); 266 EXPECT_EQ("foo.proto", file.name()); 267 } 268 269 { 270 // Can find enum values. 271 FileDescriptorProto file; 272 EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo.FRED", &file)); 273 EXPECT_EQ("foo.proto", file.name()); 274 } 275 276 { 277 // Can find extensions. 278 FileDescriptorProto file; 279 EXPECT_TRUE(database_->FindFileContainingSymbol("plugh", &file)); 280 EXPECT_EQ("foo.proto", file.name()); 281 } 282 283 { 284 // Can find services. 285 FileDescriptorProto file; 286 EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy", &file)); 287 EXPECT_EQ("foo.proto", file.name()); 288 } 289 290 { 291 // Can find methods. 292 FileDescriptorProto file; 293 EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy.Thud", &file)); 294 EXPECT_EQ("foo.proto", file.name()); 295 } 296 297 { 298 // Can find things in packages. 299 FileDescriptorProto file; 300 EXPECT_TRUE(database_->FindFileContainingSymbol("corge.Bar", &file)); 301 EXPECT_EQ("bar.proto", file.name()); 302 } 303 304 { 305 // Fails to find undefined symbols. 306 FileDescriptorProto file; 307 EXPECT_FALSE(database_->FindFileContainingSymbol("Baz", &file)); 308 } 309 310 { 311 // Names must be fully-qualified. 312 FileDescriptorProto file; 313 EXPECT_FALSE(database_->FindFileContainingSymbol("Bar", &file)); 314 } 315} 316 317TEST_P(DescriptorDatabaseTest, FindFileContainingExtension) { 318 AddToDatabase( 319 "name: \"foo.proto\" " 320 "message_type { " 321 " name: \"Foo\" " 322 " extension_range { start: 1 end: 1000 } " 323 " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " 324 " extendee: \".Foo\" }" 325 "}"); 326 AddToDatabase( 327 "name: \"bar.proto\" " 328 "package: \"corge\" " 329 "dependency: \"foo.proto\" " 330 "message_type { " 331 " name: \"Bar\" " 332 " extension_range { start: 1 end: 1000 } " 333 "} " 334 "extension { name:\"grault\" extendee: \".Foo\" number:32 } " 335 "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } " 336 "extension { name:\"waldo\" extendee: \"Bar\" number:56 } "); 337 338 { 339 FileDescriptorProto file; 340 EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 5, &file)); 341 EXPECT_EQ("foo.proto", file.name()); 342 } 343 344 { 345 FileDescriptorProto file; 346 EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 32, &file)); 347 EXPECT_EQ("bar.proto", file.name()); 348 } 349 350 { 351 // Can find extensions for qualified type names. 352 FileDescriptorProto file; 353 EXPECT_TRUE(database_->FindFileContainingExtension("corge.Bar", 70, &file)); 354 EXPECT_EQ("bar.proto", file.name()); 355 } 356 357 { 358 // Can't find extensions whose extendee was not fully-qualified in the 359 // FileDescriptorProto. 360 FileDescriptorProto file; 361 EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 56, &file)); 362 EXPECT_FALSE( 363 database_->FindFileContainingExtension("corge.Bar", 56, &file)); 364 } 365 366 { 367 // Can't find non-existent extension numbers. 368 FileDescriptorProto file; 369 EXPECT_FALSE(database_->FindFileContainingExtension("Foo", 12, &file)); 370 } 371 372 { 373 // Can't find extensions for non-existent types. 374 FileDescriptorProto file; 375 EXPECT_FALSE( 376 database_->FindFileContainingExtension("NoSuchType", 5, &file)); 377 } 378 379 { 380 // Can't find extensions for unqualified type names. 381 FileDescriptorProto file; 382 EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 70, &file)); 383 } 384} 385 386TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) { 387 AddToDatabase( 388 "name: \"foo.proto\" " 389 "message_type { " 390 " name: \"Foo\" " 391 " extension_range { start: 1 end: 1000 } " 392 " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " 393 " extendee: \".Foo\" }" 394 "}"); 395 AddToDatabase( 396 "name: \"bar.proto\" " 397 "package: \"corge\" " 398 "dependency: \"foo.proto\" " 399 "message_type { " 400 " name: \"Bar\" " 401 " extension_range { start: 1 end: 1000 } " 402 "} " 403 "extension { name:\"grault\" extendee: \".Foo\" number:32 } " 404 "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } " 405 "extension { name:\"waldo\" extendee: \"Bar\" number:56 } "); 406 407 { 408 vector<int> numbers; 409 EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers)); 410 ASSERT_EQ(2, numbers.size()); 411 sort(numbers.begin(), numbers.end()); 412 EXPECT_EQ(5, numbers[0]); 413 EXPECT_EQ(32, numbers[1]); 414 } 415 416 { 417 vector<int> numbers; 418 EXPECT_TRUE(database_->FindAllExtensionNumbers("corge.Bar", &numbers)); 419 // Note: won't find extension 56 due to the name not being fully qualified. 420 ASSERT_EQ(1, numbers.size()); 421 EXPECT_EQ(70, numbers[0]); 422 } 423 424 { 425 // Can't find extensions for non-existent types. 426 vector<int> numbers; 427 EXPECT_FALSE(database_->FindAllExtensionNumbers("NoSuchType", &numbers)); 428 } 429 430 { 431 // Can't find extensions for unqualified types. 432 vector<int> numbers; 433 EXPECT_FALSE(database_->FindAllExtensionNumbers("Bar", &numbers)); 434 } 435} 436 437TEST_P(DescriptorDatabaseTest, ConflictingFileError) { 438 AddToDatabase( 439 "name: \"foo.proto\" " 440 "message_type { " 441 " name: \"Foo\" " 442 "}"); 443 AddToDatabaseWithError( 444 "name: \"foo.proto\" " 445 "message_type { " 446 " name: \"Bar\" " 447 "}"); 448} 449 450TEST_P(DescriptorDatabaseTest, ConflictingTypeError) { 451 AddToDatabase( 452 "name: \"foo.proto\" " 453 "message_type { " 454 " name: \"Foo\" " 455 "}"); 456 AddToDatabaseWithError( 457 "name: \"bar.proto\" " 458 "message_type { " 459 " name: \"Foo\" " 460 "}"); 461} 462 463TEST_P(DescriptorDatabaseTest, ConflictingExtensionError) { 464 AddToDatabase( 465 "name: \"foo.proto\" " 466 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " 467 " extendee: \".Foo\" }"); 468 AddToDatabaseWithError( 469 "name: \"bar.proto\" " 470 "extension { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " 471 " extendee: \".Foo\" }"); 472} 473 474INSTANTIATE_TEST_CASE_P(Simple, DescriptorDatabaseTest, 475 testing::Values(&SimpleDescriptorDatabaseTestCase::New)); 476INSTANTIATE_TEST_CASE_P(MemoryConserving, DescriptorDatabaseTest, 477 testing::Values(&EncodedDescriptorDatabaseTestCase::New)); 478INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest, 479 testing::Values(&DescriptorPoolDatabaseTestCase::New)); 480 481#endif // GTEST_HAS_PARAM_TEST 482 483TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) { 484 // Create two files, one of which is in two parts. 485 FileDescriptorProto file1, file2a, file2b; 486 file1.set_name("foo.proto"); 487 file1.set_package("foo"); 488 file1.add_message_type()->set_name("Foo"); 489 file2a.set_name("bar.proto"); 490 file2b.set_package("bar"); 491 file2b.add_message_type()->set_name("Bar"); 492 493 // Normal serialization allows our optimization to kick in. 494 string data1 = file1.SerializeAsString(); 495 496 // Force out-of-order serialization to test slow path. 497 string data2 = file2b.SerializeAsString() + file2a.SerializeAsString(); 498 499 // Create EncodedDescriptorDatabase containing both files. 500 EncodedDescriptorDatabase db; 501 db.Add(data1.data(), data1.size()); 502 db.Add(data2.data(), data2.size()); 503 504 // Test! 505 string filename; 506 EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename)); 507 EXPECT_EQ("foo.proto", filename); 508 EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename)); 509 EXPECT_EQ("foo.proto", filename); 510 EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename)); 511 EXPECT_EQ("bar.proto", filename); 512 EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename)); 513 EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename)); 514 EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename)); 515} 516 517// =================================================================== 518 519class MergedDescriptorDatabaseTest : public testing::Test { 520 protected: 521 MergedDescriptorDatabaseTest() 522 : forward_merged_(&database1_, &database2_), 523 reverse_merged_(&database2_, &database1_) {} 524 525 virtual void SetUp() { 526 AddToDatabase(&database1_, 527 "name: \"foo.proto\" " 528 "message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } " 529 "extension { name:\"foo_ext\" extendee: \".Foo\" number:3 " 530 " label:LABEL_OPTIONAL type:TYPE_INT32 } "); 531 AddToDatabase(&database2_, 532 "name: \"bar.proto\" " 533 "message_type { name:\"Bar\" extension_range { start: 1 end: 100 } } " 534 "extension { name:\"bar_ext\" extendee: \".Bar\" number:5 " 535 " label:LABEL_OPTIONAL type:TYPE_INT32 } "); 536 537 // baz.proto exists in both pools, with different definitions. 538 AddToDatabase(&database1_, 539 "name: \"baz.proto\" " 540 "message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } " 541 "message_type { name:\"FromPool1\" } " 542 "extension { name:\"baz_ext\" extendee: \".Baz\" number:12 " 543 " label:LABEL_OPTIONAL type:TYPE_INT32 } " 544 "extension { name:\"database1_only_ext\" extendee: \".Baz\" number:13 " 545 " label:LABEL_OPTIONAL type:TYPE_INT32 } "); 546 AddToDatabase(&database2_, 547 "name: \"baz.proto\" " 548 "message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } " 549 "message_type { name:\"FromPool2\" } " 550 "extension { name:\"baz_ext\" extendee: \".Baz\" number:12 " 551 " label:LABEL_OPTIONAL type:TYPE_INT32 } "); 552 } 553 554 SimpleDescriptorDatabase database1_; 555 SimpleDescriptorDatabase database2_; 556 557 MergedDescriptorDatabase forward_merged_; 558 MergedDescriptorDatabase reverse_merged_; 559}; 560 561TEST_F(MergedDescriptorDatabaseTest, FindFileByName) { 562 { 563 // Can find file that is only in database1_. 564 FileDescriptorProto file; 565 EXPECT_TRUE(forward_merged_.FindFileByName("foo.proto", &file)); 566 EXPECT_EQ("foo.proto", file.name()); 567 ExpectContainsType(file, "Foo"); 568 } 569 570 { 571 // Can find file that is only in database2_. 572 FileDescriptorProto file; 573 EXPECT_TRUE(forward_merged_.FindFileByName("bar.proto", &file)); 574 EXPECT_EQ("bar.proto", file.name()); 575 ExpectContainsType(file, "Bar"); 576 } 577 578 { 579 // In forward_merged_, database1_'s baz.proto takes precedence. 580 FileDescriptorProto file; 581 EXPECT_TRUE(forward_merged_.FindFileByName("baz.proto", &file)); 582 EXPECT_EQ("baz.proto", file.name()); 583 ExpectContainsType(file, "FromPool1"); 584 } 585 586 { 587 // In reverse_merged_, database2_'s baz.proto takes precedence. 588 FileDescriptorProto file; 589 EXPECT_TRUE(reverse_merged_.FindFileByName("baz.proto", &file)); 590 EXPECT_EQ("baz.proto", file.name()); 591 ExpectContainsType(file, "FromPool2"); 592 } 593 594 { 595 // Can't find non-existent file. 596 FileDescriptorProto file; 597 EXPECT_FALSE(forward_merged_.FindFileByName("no_such.proto", &file)); 598 } 599} 600 601TEST_F(MergedDescriptorDatabaseTest, FindFileContainingSymbol) { 602 { 603 // Can find file that is only in database1_. 604 FileDescriptorProto file; 605 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Foo", &file)); 606 EXPECT_EQ("foo.proto", file.name()); 607 ExpectContainsType(file, "Foo"); 608 } 609 610 { 611 // Can find file that is only in database2_. 612 FileDescriptorProto file; 613 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Bar", &file)); 614 EXPECT_EQ("bar.proto", file.name()); 615 ExpectContainsType(file, "Bar"); 616 } 617 618 { 619 // In forward_merged_, database1_'s baz.proto takes precedence. 620 FileDescriptorProto file; 621 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Baz", &file)); 622 EXPECT_EQ("baz.proto", file.name()); 623 ExpectContainsType(file, "FromPool1"); 624 } 625 626 { 627 // In reverse_merged_, database2_'s baz.proto takes precedence. 628 FileDescriptorProto file; 629 EXPECT_TRUE(reverse_merged_.FindFileContainingSymbol("Baz", &file)); 630 EXPECT_EQ("baz.proto", file.name()); 631 ExpectContainsType(file, "FromPool2"); 632 } 633 634 { 635 // FromPool1 only shows up in forward_merged_ because it is masked by 636 // database2_'s baz.proto in reverse_merged_. 637 FileDescriptorProto file; 638 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("FromPool1", &file)); 639 EXPECT_FALSE(reverse_merged_.FindFileContainingSymbol("FromPool1", &file)); 640 } 641 642 { 643 // Can't find non-existent symbol. 644 FileDescriptorProto file; 645 EXPECT_FALSE( 646 forward_merged_.FindFileContainingSymbol("NoSuchType", &file)); 647 } 648} 649 650TEST_F(MergedDescriptorDatabaseTest, FindFileContainingExtension) { 651 { 652 // Can find file that is only in database1_. 653 FileDescriptorProto file; 654 EXPECT_TRUE( 655 forward_merged_.FindFileContainingExtension("Foo", 3, &file)); 656 EXPECT_EQ("foo.proto", file.name()); 657 ExpectContainsType(file, "Foo"); 658 } 659 660 { 661 // Can find file that is only in database2_. 662 FileDescriptorProto file; 663 EXPECT_TRUE( 664 forward_merged_.FindFileContainingExtension("Bar", 5, &file)); 665 EXPECT_EQ("bar.proto", file.name()); 666 ExpectContainsType(file, "Bar"); 667 } 668 669 { 670 // In forward_merged_, database1_'s baz.proto takes precedence. 671 FileDescriptorProto file; 672 EXPECT_TRUE( 673 forward_merged_.FindFileContainingExtension("Baz", 12, &file)); 674 EXPECT_EQ("baz.proto", file.name()); 675 ExpectContainsType(file, "FromPool1"); 676 } 677 678 { 679 // In reverse_merged_, database2_'s baz.proto takes precedence. 680 FileDescriptorProto file; 681 EXPECT_TRUE( 682 reverse_merged_.FindFileContainingExtension("Baz", 12, &file)); 683 EXPECT_EQ("baz.proto", file.name()); 684 ExpectContainsType(file, "FromPool2"); 685 } 686 687 { 688 // Baz's extension 13 only shows up in forward_merged_ because it is 689 // masked by database2_'s baz.proto in reverse_merged_. 690 FileDescriptorProto file; 691 EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Baz", 13, &file)); 692 EXPECT_FALSE(reverse_merged_.FindFileContainingExtension("Baz", 13, &file)); 693 } 694 695 { 696 // Can't find non-existent extension. 697 FileDescriptorProto file; 698 EXPECT_FALSE( 699 forward_merged_.FindFileContainingExtension("Foo", 6, &file)); 700 } 701} 702 703TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) { 704 { 705 // Message only has extension in database1_ 706 vector<int> numbers; 707 EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Foo", &numbers)); 708 ASSERT_EQ(1, numbers.size()); 709 EXPECT_EQ(3, numbers[0]); 710 } 711 712 { 713 // Message only has extension in database2_ 714 vector<int> numbers; 715 EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Bar", &numbers)); 716 ASSERT_EQ(1, numbers.size()); 717 EXPECT_EQ(5, numbers[0]); 718 } 719 720 { 721 // Merge results from the two databases. 722 vector<int> numbers; 723 EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers)); 724 ASSERT_EQ(2, numbers.size()); 725 sort(numbers.begin(), numbers.end()); 726 EXPECT_EQ(12, numbers[0]); 727 EXPECT_EQ(13, numbers[1]); 728 } 729 730 { 731 vector<int> numbers; 732 EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers)); 733 ASSERT_EQ(2, numbers.size()); 734 sort(numbers.begin(), numbers.end()); 735 EXPECT_EQ(12, numbers[0]); 736 EXPECT_EQ(13, numbers[1]); 737 } 738 739 { 740 // Can't find extensions for a non-existent message. 741 vector<int> numbers; 742 EXPECT_FALSE(reverse_merged_.FindAllExtensionNumbers("Blah", &numbers)); 743 } 744} 745 746} // anonymous namespace 747} // namespace protobuf 748} // namespace google 749