1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34 //
35 // This file makes extensive use of RFC 3092. :)
36
37 #include <algorithm>
38 #include <memory>
39 #ifndef _SHARED_PTR_H
40 #include <google/protobuf/stubs/shared_ptr.h>
41 #endif
42
43 #include <google/protobuf/descriptor_database.h>
44 #include <google/protobuf/descriptor.h>
45 #include <google/protobuf/descriptor.pb.h>
46 #include <google/protobuf/text_format.h>
47 #include <google/protobuf/stubs/strutil.h>
48
49 #include <google/protobuf/stubs/logging.h>
50 #include <google/protobuf/stubs/common.h>
51 #include <google/protobuf/testing/googletest.h>
52 #include <gtest/gtest.h>
53
54 namespace google {
55 namespace protobuf {
56 namespace {
57
AddToDatabase(SimpleDescriptorDatabase * database,const char * file_text)58 static void AddToDatabase(SimpleDescriptorDatabase* database,
59 const char* file_text) {
60 FileDescriptorProto file_proto;
61 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
62 database->Add(file_proto);
63 }
64
ExpectContainsType(const FileDescriptorProto & proto,const string & type_name)65 static void ExpectContainsType(const FileDescriptorProto& proto,
66 const string& type_name) {
67 for (int i = 0; i < proto.message_type_size(); i++) {
68 if (proto.message_type(i).name() == type_name) return;
69 }
70 ADD_FAILURE() << "\"" << proto.name()
71 << "\" did not contain expected type \""
72 << type_name << "\".";
73 }
74
75 // ===================================================================
76
77 #if GTEST_HAS_PARAM_TEST
78
79 // SimpleDescriptorDatabase, EncodedDescriptorDatabase, and
80 // DescriptorPoolDatabase call for very similar tests. Instead of writing
81 // three nearly-identical sets of tests, we use parameterized tests to apply
82 // the same code to all three.
83
84 // The parameterized test runs against a DescriptarDatabaseTestCase. We have
85 // implementations for each of the three classes we want to test.
86 class DescriptorDatabaseTestCase {
87 public:
~DescriptorDatabaseTestCase()88 virtual ~DescriptorDatabaseTestCase() {}
89
90 virtual DescriptorDatabase* GetDatabase() = 0;
91 virtual bool AddToDatabase(const FileDescriptorProto& file) = 0;
92 };
93
94 // Factory function type.
95 typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory();
96
97 // Specialization for SimpleDescriptorDatabase.
98 class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
99 public:
New()100 static DescriptorDatabaseTestCase* New() {
101 return new SimpleDescriptorDatabaseTestCase;
102 }
103
~SimpleDescriptorDatabaseTestCase()104 virtual ~SimpleDescriptorDatabaseTestCase() {}
105
GetDatabase()106 virtual DescriptorDatabase* GetDatabase() {
107 return &database_;
108 }
AddToDatabase(const FileDescriptorProto & file)109 virtual bool AddToDatabase(const FileDescriptorProto& file) {
110 return database_.Add(file);
111 }
112
113 private:
114 SimpleDescriptorDatabase database_;
115 };
116
117 // Specialization for EncodedDescriptorDatabase.
118 class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
119 public:
New()120 static DescriptorDatabaseTestCase* New() {
121 return new EncodedDescriptorDatabaseTestCase;
122 }
123
~EncodedDescriptorDatabaseTestCase()124 virtual ~EncodedDescriptorDatabaseTestCase() {}
125
GetDatabase()126 virtual DescriptorDatabase* GetDatabase() {
127 return &database_;
128 }
AddToDatabase(const FileDescriptorProto & file)129 virtual bool AddToDatabase(const FileDescriptorProto& file) {
130 string data;
131 file.SerializeToString(&data);
132 return database_.AddCopy(data.data(), data.size());
133 }
134
135 private:
136 EncodedDescriptorDatabase database_;
137 };
138
139 // Specialization for DescriptorPoolDatabase.
140 class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase {
141 public:
New()142 static DescriptorDatabaseTestCase* New() {
143 return new EncodedDescriptorDatabaseTestCase;
144 }
145
DescriptorPoolDatabaseTestCase()146 DescriptorPoolDatabaseTestCase() : database_(pool_) {}
~DescriptorPoolDatabaseTestCase()147 virtual ~DescriptorPoolDatabaseTestCase() {}
148
GetDatabase()149 virtual DescriptorDatabase* GetDatabase() {
150 return &database_;
151 }
AddToDatabase(const FileDescriptorProto & file)152 virtual bool AddToDatabase(const FileDescriptorProto& file) {
153 return pool_.BuildFile(file);
154 }
155
156 private:
157 DescriptorPool pool_;
158 DescriptorPoolDatabase database_;
159 };
160
161 // -------------------------------------------------------------------
162
163 class DescriptorDatabaseTest
164 : public testing::TestWithParam<DescriptorDatabaseTestCaseFactory*> {
165 protected:
SetUp()166 virtual void SetUp() {
167 test_case_.reset(GetParam()());
168 database_ = test_case_->GetDatabase();
169 }
170
AddToDatabase(const char * file_descriptor_text)171 void AddToDatabase(const char* file_descriptor_text) {
172 FileDescriptorProto file_proto;
173 EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
174 EXPECT_TRUE(test_case_->AddToDatabase(file_proto));
175 }
176
AddToDatabaseWithError(const char * file_descriptor_text)177 void AddToDatabaseWithError(const char* file_descriptor_text) {
178 FileDescriptorProto file_proto;
179 EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
180 EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
181 }
182
183 google::protobuf::scoped_ptr<DescriptorDatabaseTestCase> test_case_;
184 DescriptorDatabase* database_;
185 };
186
TEST_P(DescriptorDatabaseTest,FindFileByName)187 TEST_P(DescriptorDatabaseTest, FindFileByName) {
188 AddToDatabase(
189 "name: \"foo.proto\" "
190 "message_type { name:\"Foo\" }");
191 AddToDatabase(
192 "name: \"bar.proto\" "
193 "message_type { name:\"Bar\" }");
194
195 {
196 FileDescriptorProto file;
197 EXPECT_TRUE(database_->FindFileByName("foo.proto", &file));
198 EXPECT_EQ("foo.proto", file.name());
199 ExpectContainsType(file, "Foo");
200 }
201
202 {
203 FileDescriptorProto file;
204 EXPECT_TRUE(database_->FindFileByName("bar.proto", &file));
205 EXPECT_EQ("bar.proto", file.name());
206 ExpectContainsType(file, "Bar");
207 }
208
209 {
210 // Fails to find undefined files.
211 FileDescriptorProto file;
212 EXPECT_FALSE(database_->FindFileByName("baz.proto", &file));
213 }
214 }
215
TEST_P(DescriptorDatabaseTest,FindFileContainingSymbol)216 TEST_P(DescriptorDatabaseTest, FindFileContainingSymbol) {
217 AddToDatabase(
218 "name: \"foo.proto\" "
219 "message_type { "
220 " name: \"Foo\" "
221 " field { name:\"qux\" }"
222 " nested_type { name: \"Grault\" } "
223 " enum_type { name: \"Garply\" } "
224 "} "
225 "enum_type { "
226 " name: \"Waldo\" "
227 " value { name:\"FRED\" } "
228 "} "
229 "extension { name: \"plugh\" } "
230 "service { "
231 " name: \"Xyzzy\" "
232 " method { name: \"Thud\" } "
233 "}"
234 );
235 AddToDatabase(
236 "name: \"bar.proto\" "
237 "package: \"corge\" "
238 "message_type { name: \"Bar\" }");
239
240 {
241 FileDescriptorProto file;
242 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo", &file));
243 EXPECT_EQ("foo.proto", file.name());
244 }
245
246 {
247 // Can find fields.
248 FileDescriptorProto file;
249 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.qux", &file));
250 EXPECT_EQ("foo.proto", file.name());
251 }
252
253 {
254 // Can find nested types.
255 FileDescriptorProto file;
256 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Grault", &file));
257 EXPECT_EQ("foo.proto", file.name());
258 }
259
260 {
261 // Can find nested enums.
262 FileDescriptorProto file;
263 EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Garply", &file));
264 EXPECT_EQ("foo.proto", file.name());
265 }
266
267 {
268 // Can find enum types.
269 FileDescriptorProto file;
270 EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo", &file));
271 EXPECT_EQ("foo.proto", file.name());
272 }
273
274 {
275 // Can find enum values.
276 FileDescriptorProto file;
277 EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo.FRED", &file));
278 EXPECT_EQ("foo.proto", file.name());
279 }
280
281 {
282 // Can find extensions.
283 FileDescriptorProto file;
284 EXPECT_TRUE(database_->FindFileContainingSymbol("plugh", &file));
285 EXPECT_EQ("foo.proto", file.name());
286 }
287
288 {
289 // Can find services.
290 FileDescriptorProto file;
291 EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy", &file));
292 EXPECT_EQ("foo.proto", file.name());
293 }
294
295 {
296 // Can find methods.
297 FileDescriptorProto file;
298 EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy.Thud", &file));
299 EXPECT_EQ("foo.proto", file.name());
300 }
301
302 {
303 // Can find things in packages.
304 FileDescriptorProto file;
305 EXPECT_TRUE(database_->FindFileContainingSymbol("corge.Bar", &file));
306 EXPECT_EQ("bar.proto", file.name());
307 }
308
309 {
310 // Fails to find undefined symbols.
311 FileDescriptorProto file;
312 EXPECT_FALSE(database_->FindFileContainingSymbol("Baz", &file));
313 }
314
315 {
316 // Names must be fully-qualified.
317 FileDescriptorProto file;
318 EXPECT_FALSE(database_->FindFileContainingSymbol("Bar", &file));
319 }
320 }
321
TEST_P(DescriptorDatabaseTest,FindFileContainingExtension)322 TEST_P(DescriptorDatabaseTest, FindFileContainingExtension) {
323 AddToDatabase(
324 "name: \"foo.proto\" "
325 "message_type { "
326 " name: \"Foo\" "
327 " extension_range { start: 1 end: 1000 } "
328 " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
329 " extendee: \".Foo\" }"
330 "}");
331 AddToDatabase(
332 "name: \"bar.proto\" "
333 "package: \"corge\" "
334 "dependency: \"foo.proto\" "
335 "message_type { "
336 " name: \"Bar\" "
337 " extension_range { start: 1 end: 1000 } "
338 "} "
339 "extension { name:\"grault\" extendee: \".Foo\" number:32 } "
340 "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
341 "extension { name:\"waldo\" extendee: \"Bar\" number:56 } ");
342
343 {
344 FileDescriptorProto file;
345 EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 5, &file));
346 EXPECT_EQ("foo.proto", file.name());
347 }
348
349 {
350 FileDescriptorProto file;
351 EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 32, &file));
352 EXPECT_EQ("bar.proto", file.name());
353 }
354
355 {
356 // Can find extensions for qualified type names.
357 FileDescriptorProto file;
358 EXPECT_TRUE(database_->FindFileContainingExtension("corge.Bar", 70, &file));
359 EXPECT_EQ("bar.proto", file.name());
360 }
361
362 {
363 // Can't find extensions whose extendee was not fully-qualified in the
364 // FileDescriptorProto.
365 FileDescriptorProto file;
366 EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 56, &file));
367 EXPECT_FALSE(
368 database_->FindFileContainingExtension("corge.Bar", 56, &file));
369 }
370
371 {
372 // Can't find non-existent extension numbers.
373 FileDescriptorProto file;
374 EXPECT_FALSE(database_->FindFileContainingExtension("Foo", 12, &file));
375 }
376
377 {
378 // Can't find extensions for non-existent types.
379 FileDescriptorProto file;
380 EXPECT_FALSE(
381 database_->FindFileContainingExtension("NoSuchType", 5, &file));
382 }
383
384 {
385 // Can't find extensions for unqualified type names.
386 FileDescriptorProto file;
387 EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 70, &file));
388 }
389 }
390
TEST_P(DescriptorDatabaseTest,FindAllExtensionNumbers)391 TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) {
392 AddToDatabase(
393 "name: \"foo.proto\" "
394 "message_type { "
395 " name: \"Foo\" "
396 " extension_range { start: 1 end: 1000 } "
397 " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
398 " extendee: \".Foo\" }"
399 "}");
400 AddToDatabase(
401 "name: \"bar.proto\" "
402 "package: \"corge\" "
403 "dependency: \"foo.proto\" "
404 "message_type { "
405 " name: \"Bar\" "
406 " extension_range { start: 1 end: 1000 } "
407 "} "
408 "extension { name:\"grault\" extendee: \".Foo\" number:32 } "
409 "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
410 "extension { name:\"waldo\" extendee: \"Bar\" number:56 } ");
411
412 {
413 vector<int> numbers;
414 EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
415 ASSERT_EQ(2, numbers.size());
416 std::sort(numbers.begin(), numbers.end());
417 EXPECT_EQ(5, numbers[0]);
418 EXPECT_EQ(32, numbers[1]);
419 }
420
421 {
422 vector<int> numbers;
423 EXPECT_TRUE(database_->FindAllExtensionNumbers("corge.Bar", &numbers));
424 // Note: won't find extension 56 due to the name not being fully qualified.
425 ASSERT_EQ(1, numbers.size());
426 EXPECT_EQ(70, numbers[0]);
427 }
428
429 {
430 // Can't find extensions for non-existent types.
431 vector<int> numbers;
432 EXPECT_FALSE(database_->FindAllExtensionNumbers("NoSuchType", &numbers));
433 }
434
435 {
436 // Can't find extensions for unqualified types.
437 vector<int> numbers;
438 EXPECT_FALSE(database_->FindAllExtensionNumbers("Bar", &numbers));
439 }
440 }
441
TEST_P(DescriptorDatabaseTest,ConflictingFileError)442 TEST_P(DescriptorDatabaseTest, ConflictingFileError) {
443 AddToDatabase(
444 "name: \"foo.proto\" "
445 "message_type { "
446 " name: \"Foo\" "
447 "}");
448 AddToDatabaseWithError(
449 "name: \"foo.proto\" "
450 "message_type { "
451 " name: \"Bar\" "
452 "}");
453 }
454
TEST_P(DescriptorDatabaseTest,ConflictingTypeError)455 TEST_P(DescriptorDatabaseTest, ConflictingTypeError) {
456 AddToDatabase(
457 "name: \"foo.proto\" "
458 "message_type { "
459 " name: \"Foo\" "
460 "}");
461 AddToDatabaseWithError(
462 "name: \"bar.proto\" "
463 "message_type { "
464 " name: \"Foo\" "
465 "}");
466 }
467
TEST_P(DescriptorDatabaseTest,ConflictingExtensionError)468 TEST_P(DescriptorDatabaseTest, ConflictingExtensionError) {
469 AddToDatabase(
470 "name: \"foo.proto\" "
471 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
472 " extendee: \".Foo\" }");
473 AddToDatabaseWithError(
474 "name: \"bar.proto\" "
475 "extension { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
476 " extendee: \".Foo\" }");
477 }
478
479 INSTANTIATE_TEST_CASE_P(Simple, DescriptorDatabaseTest,
480 testing::Values(&SimpleDescriptorDatabaseTestCase::New));
481 INSTANTIATE_TEST_CASE_P(MemoryConserving, DescriptorDatabaseTest,
482 testing::Values(&EncodedDescriptorDatabaseTestCase::New));
483 INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest,
484 testing::Values(&DescriptorPoolDatabaseTestCase::New));
485
486 #endif // GTEST_HAS_PARAM_TEST
487
TEST(EncodedDescriptorDatabaseExtraTest,FindNameOfFileContainingSymbol)488 TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) {
489 // Create two files, one of which is in two parts.
490 FileDescriptorProto file1, file2a, file2b;
491 file1.set_name("foo.proto");
492 file1.set_package("foo");
493 file1.add_message_type()->set_name("Foo");
494 file2a.set_name("bar.proto");
495 file2b.set_package("bar");
496 file2b.add_message_type()->set_name("Bar");
497
498 // Normal serialization allows our optimization to kick in.
499 string data1 = file1.SerializeAsString();
500
501 // Force out-of-order serialization to test slow path.
502 string data2 = file2b.SerializeAsString() + file2a.SerializeAsString();
503
504 // Create EncodedDescriptorDatabase containing both files.
505 EncodedDescriptorDatabase db;
506 db.Add(data1.data(), data1.size());
507 db.Add(data2.data(), data2.size());
508
509 // Test!
510 string filename;
511 EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename));
512 EXPECT_EQ("foo.proto", filename);
513 EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename));
514 EXPECT_EQ("foo.proto", filename);
515 EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename));
516 EXPECT_EQ("bar.proto", filename);
517 EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename));
518 EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename));
519 EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename));
520 }
521
522 // ===================================================================
523
524 class MergedDescriptorDatabaseTest : public testing::Test {
525 protected:
MergedDescriptorDatabaseTest()526 MergedDescriptorDatabaseTest()
527 : forward_merged_(&database1_, &database2_),
528 reverse_merged_(&database2_, &database1_) {}
529
SetUp()530 virtual void SetUp() {
531 AddToDatabase(&database1_,
532 "name: \"foo.proto\" "
533 "message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
534 "extension { name:\"foo_ext\" extendee: \".Foo\" number:3 "
535 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
536 AddToDatabase(&database2_,
537 "name: \"bar.proto\" "
538 "message_type { name:\"Bar\" extension_range { start: 1 end: 100 } } "
539 "extension { name:\"bar_ext\" extendee: \".Bar\" number:5 "
540 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
541
542 // baz.proto exists in both pools, with different definitions.
543 AddToDatabase(&database1_,
544 "name: \"baz.proto\" "
545 "message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
546 "message_type { name:\"FromPool1\" } "
547 "extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
548 " label:LABEL_OPTIONAL type:TYPE_INT32 } "
549 "extension { name:\"database1_only_ext\" extendee: \".Baz\" number:13 "
550 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
551 AddToDatabase(&database2_,
552 "name: \"baz.proto\" "
553 "message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
554 "message_type { name:\"FromPool2\" } "
555 "extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
556 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
557 }
558
559 SimpleDescriptorDatabase database1_;
560 SimpleDescriptorDatabase database2_;
561
562 MergedDescriptorDatabase forward_merged_;
563 MergedDescriptorDatabase reverse_merged_;
564 };
565
TEST_F(MergedDescriptorDatabaseTest,FindFileByName)566 TEST_F(MergedDescriptorDatabaseTest, FindFileByName) {
567 {
568 // Can find file that is only in database1_.
569 FileDescriptorProto file;
570 EXPECT_TRUE(forward_merged_.FindFileByName("foo.proto", &file));
571 EXPECT_EQ("foo.proto", file.name());
572 ExpectContainsType(file, "Foo");
573 }
574
575 {
576 // Can find file that is only in database2_.
577 FileDescriptorProto file;
578 EXPECT_TRUE(forward_merged_.FindFileByName("bar.proto", &file));
579 EXPECT_EQ("bar.proto", file.name());
580 ExpectContainsType(file, "Bar");
581 }
582
583 {
584 // In forward_merged_, database1_'s baz.proto takes precedence.
585 FileDescriptorProto file;
586 EXPECT_TRUE(forward_merged_.FindFileByName("baz.proto", &file));
587 EXPECT_EQ("baz.proto", file.name());
588 ExpectContainsType(file, "FromPool1");
589 }
590
591 {
592 // In reverse_merged_, database2_'s baz.proto takes precedence.
593 FileDescriptorProto file;
594 EXPECT_TRUE(reverse_merged_.FindFileByName("baz.proto", &file));
595 EXPECT_EQ("baz.proto", file.name());
596 ExpectContainsType(file, "FromPool2");
597 }
598
599 {
600 // Can't find non-existent file.
601 FileDescriptorProto file;
602 EXPECT_FALSE(forward_merged_.FindFileByName("no_such.proto", &file));
603 }
604 }
605
TEST_F(MergedDescriptorDatabaseTest,FindFileContainingSymbol)606 TEST_F(MergedDescriptorDatabaseTest, FindFileContainingSymbol) {
607 {
608 // Can find file that is only in database1_.
609 FileDescriptorProto file;
610 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Foo", &file));
611 EXPECT_EQ("foo.proto", file.name());
612 ExpectContainsType(file, "Foo");
613 }
614
615 {
616 // Can find file that is only in database2_.
617 FileDescriptorProto file;
618 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Bar", &file));
619 EXPECT_EQ("bar.proto", file.name());
620 ExpectContainsType(file, "Bar");
621 }
622
623 {
624 // In forward_merged_, database1_'s baz.proto takes precedence.
625 FileDescriptorProto file;
626 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Baz", &file));
627 EXPECT_EQ("baz.proto", file.name());
628 ExpectContainsType(file, "FromPool1");
629 }
630
631 {
632 // In reverse_merged_, database2_'s baz.proto takes precedence.
633 FileDescriptorProto file;
634 EXPECT_TRUE(reverse_merged_.FindFileContainingSymbol("Baz", &file));
635 EXPECT_EQ("baz.proto", file.name());
636 ExpectContainsType(file, "FromPool2");
637 }
638
639 {
640 // FromPool1 only shows up in forward_merged_ because it is masked by
641 // database2_'s baz.proto in reverse_merged_.
642 FileDescriptorProto file;
643 EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("FromPool1", &file));
644 EXPECT_FALSE(reverse_merged_.FindFileContainingSymbol("FromPool1", &file));
645 }
646
647 {
648 // Can't find non-existent symbol.
649 FileDescriptorProto file;
650 EXPECT_FALSE(
651 forward_merged_.FindFileContainingSymbol("NoSuchType", &file));
652 }
653 }
654
TEST_F(MergedDescriptorDatabaseTest,FindFileContainingExtension)655 TEST_F(MergedDescriptorDatabaseTest, FindFileContainingExtension) {
656 {
657 // Can find file that is only in database1_.
658 FileDescriptorProto file;
659 EXPECT_TRUE(
660 forward_merged_.FindFileContainingExtension("Foo", 3, &file));
661 EXPECT_EQ("foo.proto", file.name());
662 ExpectContainsType(file, "Foo");
663 }
664
665 {
666 // Can find file that is only in database2_.
667 FileDescriptorProto file;
668 EXPECT_TRUE(
669 forward_merged_.FindFileContainingExtension("Bar", 5, &file));
670 EXPECT_EQ("bar.proto", file.name());
671 ExpectContainsType(file, "Bar");
672 }
673
674 {
675 // In forward_merged_, database1_'s baz.proto takes precedence.
676 FileDescriptorProto file;
677 EXPECT_TRUE(
678 forward_merged_.FindFileContainingExtension("Baz", 12, &file));
679 EXPECT_EQ("baz.proto", file.name());
680 ExpectContainsType(file, "FromPool1");
681 }
682
683 {
684 // In reverse_merged_, database2_'s baz.proto takes precedence.
685 FileDescriptorProto file;
686 EXPECT_TRUE(
687 reverse_merged_.FindFileContainingExtension("Baz", 12, &file));
688 EXPECT_EQ("baz.proto", file.name());
689 ExpectContainsType(file, "FromPool2");
690 }
691
692 {
693 // Baz's extension 13 only shows up in forward_merged_ because it is
694 // masked by database2_'s baz.proto in reverse_merged_.
695 FileDescriptorProto file;
696 EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Baz", 13, &file));
697 EXPECT_FALSE(reverse_merged_.FindFileContainingExtension("Baz", 13, &file));
698 }
699
700 {
701 // Can't find non-existent extension.
702 FileDescriptorProto file;
703 EXPECT_FALSE(
704 forward_merged_.FindFileContainingExtension("Foo", 6, &file));
705 }
706 }
707
TEST_F(MergedDescriptorDatabaseTest,FindAllExtensionNumbers)708 TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
709 {
710 // Message only has extension in database1_
711 vector<int> numbers;
712 EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Foo", &numbers));
713 ASSERT_EQ(1, numbers.size());
714 EXPECT_EQ(3, numbers[0]);
715 }
716
717 {
718 // Message only has extension in database2_
719 vector<int> numbers;
720 EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Bar", &numbers));
721 ASSERT_EQ(1, numbers.size());
722 EXPECT_EQ(5, numbers[0]);
723 }
724
725 {
726 // Merge results from the two databases.
727 vector<int> numbers;
728 EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
729 ASSERT_EQ(2, numbers.size());
730 std::sort(numbers.begin(), numbers.end());
731 EXPECT_EQ(12, numbers[0]);
732 EXPECT_EQ(13, numbers[1]);
733 }
734
735 {
736 vector<int> numbers;
737 EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
738 ASSERT_EQ(2, numbers.size());
739 std::sort(numbers.begin(), numbers.end());
740 EXPECT_EQ(12, numbers[0]);
741 EXPECT_EQ(13, numbers[1]);
742 }
743
744 {
745 // Can't find extensions for a non-existent message.
746 vector<int> numbers;
747 EXPECT_FALSE(reverse_merged_.FindAllExtensionNumbers("Blah", &numbers));
748 }
749 }
750
751 } // anonymous namespace
752 } // namespace protobuf
753 } // namespace google
754