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