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