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