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