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