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