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