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