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