• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
55 namespace google {
56 namespace protobuf {
57 namespace {
58 
AddToDatabase(SimpleDescriptorDatabase * database,const char * file_text)59 static 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 
ExpectContainsType(const FileDescriptorProto & proto,const string & type_name)66 static 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.
87 class DescriptorDatabaseTestCase {
88  public:
~DescriptorDatabaseTestCase()89   virtual ~DescriptorDatabaseTestCase() {}
90 
91   virtual DescriptorDatabase* GetDatabase() = 0;
92   virtual bool AddToDatabase(const FileDescriptorProto& file) = 0;
93 };
94 
95 // Factory function type.
96 typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory();
97 
98 // Specialization for SimpleDescriptorDatabase.
99 class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
100  public:
New()101   static DescriptorDatabaseTestCase* New() {
102     return new SimpleDescriptorDatabaseTestCase;
103   }
104 
~SimpleDescriptorDatabaseTestCase()105   virtual ~SimpleDescriptorDatabaseTestCase() {}
106 
GetDatabase()107   virtual DescriptorDatabase* GetDatabase() {
108     return &database_;
109   }
AddToDatabase(const FileDescriptorProto & file)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.
119 class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
120  public:
New()121   static DescriptorDatabaseTestCase* New() {
122     return new EncodedDescriptorDatabaseTestCase;
123   }
124 
~EncodedDescriptorDatabaseTestCase()125   virtual ~EncodedDescriptorDatabaseTestCase() {}
126 
GetDatabase()127   virtual DescriptorDatabase* GetDatabase() {
128     return &database_;
129   }
AddToDatabase(const FileDescriptorProto & file)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.
141 class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase {
142  public:
New()143   static DescriptorDatabaseTestCase* New() {
144     return new EncodedDescriptorDatabaseTestCase;
145   }
146 
DescriptorPoolDatabaseTestCase()147   DescriptorPoolDatabaseTestCase() : database_(pool_) {}
~DescriptorPoolDatabaseTestCase()148   virtual ~DescriptorPoolDatabaseTestCase() {}
149 
GetDatabase()150   virtual DescriptorDatabase* GetDatabase() {
151     return &database_;
152   }
AddToDatabase(const FileDescriptorProto & file)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 
164 class DescriptorDatabaseTest
165     : public testing::TestWithParam<DescriptorDatabaseTestCaseFactory*> {
166  protected:
SetUp()167   virtual void SetUp() {
168     test_case_.reset(GetParam()());
169     database_ = test_case_->GetDatabase();
170   }
171 
AddToDatabase(const char * file_descriptor_text)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 
AddToDatabaseWithError(const char * file_descriptor_text)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 
TEST_P(DescriptorDatabaseTest,FindFileByName)188 TEST_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 
TEST_P(DescriptorDatabaseTest,FindFileContainingSymbol)217 TEST_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 
TEST_P(DescriptorDatabaseTest,FindFileContainingExtension)323 TEST_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 
TEST_P(DescriptorDatabaseTest,FindAllExtensionNumbers)392 TEST_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 
TEST_P(DescriptorDatabaseTest,ConflictingFileError)443 TEST_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 
TEST_P(DescriptorDatabaseTest,ConflictingTypeError)456 TEST_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 
TEST_P(DescriptorDatabaseTest,ConflictingExtensionError)469 TEST_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 
480 INSTANTIATE_TEST_CASE_P(Simple, DescriptorDatabaseTest,
481     testing::Values(&SimpleDescriptorDatabaseTestCase::New));
482 INSTANTIATE_TEST_CASE_P(MemoryConserving, DescriptorDatabaseTest,
483     testing::Values(&EncodedDescriptorDatabaseTestCase::New));
484 INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest,
485     testing::Values(&DescriptorPoolDatabaseTestCase::New));
486 
487 #endif  // GTEST_HAS_PARAM_TEST
488 
TEST(EncodedDescriptorDatabaseExtraTest,FindNameOfFileContainingSymbol)489 TEST(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 
525 class MergedDescriptorDatabaseTest : public testing::Test {
526  protected:
MergedDescriptorDatabaseTest()527   MergedDescriptorDatabaseTest()
528     : forward_merged_(&database1_, &database2_),
529       reverse_merged_(&database2_, &database1_) {}
530 
SetUp()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 
TEST_F(MergedDescriptorDatabaseTest,FindFileByName)567 TEST_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 
TEST_F(MergedDescriptorDatabaseTest,FindFileContainingSymbol)607 TEST_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 
TEST_F(MergedDescriptorDatabaseTest,FindFileContainingExtension)656 TEST_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 
TEST_F(MergedDescriptorDatabaseTest,FindAllExtensionNumbers)709 TEST_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