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